120 lines
3.8 KiB
Rust
120 lines
3.8 KiB
Rust
#![cfg(feature = "runtime")]
|
|
extern crate pretty_env_logger;
|
|
|
|
use std::thread;
|
|
use std::time::Duration;
|
|
|
|
use futures::Async;
|
|
use futures::future::poll_fn;
|
|
use tokio::executor::thread_pool::{Builder as ThreadPoolBuilder};
|
|
|
|
use mock::MockConnector;
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn retryable_request() {
|
|
let _ = pretty_env_logger::try_init();
|
|
|
|
let executor = ThreadPoolBuilder::new().pool_size(1).build();
|
|
let mut connector = MockConnector::new();
|
|
|
|
let sock1 = connector.mock("http://mock.local");
|
|
let sock2 = connector.mock("http://mock.local");
|
|
|
|
let client = Client::builder()
|
|
.executor(executor.sender().clone())
|
|
.build::<_, ::Body>(connector);
|
|
|
|
client.pool.no_timer();
|
|
|
|
{
|
|
|
|
let req = Request::builder()
|
|
.uri("http://mock.local/a")
|
|
.body(Default::default())
|
|
.unwrap();
|
|
let res1 = client.request(req);
|
|
let srv1 = poll_fn(|| {
|
|
try_ready!(sock1.read(&mut [0u8; 512]));
|
|
try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
|
|
Ok(Async::Ready(()))
|
|
}).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e));
|
|
res1.join(srv1).wait().expect("res1");
|
|
}
|
|
drop(sock1);
|
|
|
|
let req = Request::builder()
|
|
.uri("http://mock.local/b")
|
|
.body(Default::default())
|
|
.unwrap();
|
|
let res2 = client.request(req)
|
|
.map(|res| {
|
|
assert_eq!(res.status().as_u16(), 222);
|
|
});
|
|
let srv2 = poll_fn(|| {
|
|
try_ready!(sock2.read(&mut [0u8; 512]));
|
|
try_ready!(sock2.write(b"HTTP/1.1 222 OK\r\nContent-Length: 0\r\n\r\n"));
|
|
Ok(Async::Ready(()))
|
|
}).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e));
|
|
|
|
res2.join(srv2).wait().expect("res2");
|
|
}
|
|
|
|
#[test]
|
|
fn conn_reset_after_write() {
|
|
let _ = pretty_env_logger::try_init();
|
|
|
|
let executor = ThreadPoolBuilder::new().pool_size(1).build();
|
|
let mut connector = MockConnector::new();
|
|
|
|
let sock1 = connector.mock("http://mock.local");
|
|
|
|
let client = Client::builder()
|
|
.executor(executor.sender().clone())
|
|
.build::<_, ::Body>(connector);
|
|
|
|
client.pool.no_timer();
|
|
|
|
{
|
|
let req = Request::builder()
|
|
.uri("http://mock.local/a")
|
|
//TODO: remove this header when auto lengths are fixed
|
|
.header("content-length", "0")
|
|
.body(Default::default())
|
|
.unwrap();
|
|
let res1 = client.request(req);
|
|
let srv1 = poll_fn(|| {
|
|
try_ready!(sock1.read(&mut [0u8; 512]));
|
|
try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"));
|
|
Ok(Async::Ready(()))
|
|
}).map_err(|e: ::std::io::Error| panic!("srv1 poll_fn error: {}", e));
|
|
res1.join(srv1).wait().expect("res1");
|
|
}
|
|
|
|
// sleep to allow some time for the connection to return to the pool
|
|
thread::sleep(Duration::from_millis(10));
|
|
|
|
let req = Request::builder()
|
|
.uri("http://mock.local/a")
|
|
.body(Default::default())
|
|
.unwrap();
|
|
let res2 = client.request(req);
|
|
let mut sock1 = Some(sock1);
|
|
let srv2 = poll_fn(|| {
|
|
// We purposefully keep the socket open until the client
|
|
// has written the second request, and THEN disconnect.
|
|
//
|
|
// Not because we expect servers to be jerks, but to trigger
|
|
// state where we write on an assumedly good connetion, and
|
|
// only reset the close AFTER we wrote bytes.
|
|
try_ready!(sock1.as_mut().unwrap().read(&mut [0u8; 512]));
|
|
sock1.take();
|
|
Ok(Async::Ready(()))
|
|
}).map_err(|e: ::std::io::Error| panic!("srv2 poll_fn error: {}", e));
|
|
let err = res2.join(srv2).wait().expect_err("res2");
|
|
match err.kind() {
|
|
&::error::Kind::Incomplete => (),
|
|
other => panic!("expected Incomplete, found {:?}", other)
|
|
}
|
|
}
|