summaryrefslogtreecommitdiffstats
path: root/third_party/rust/hyper/src/client/tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/hyper/src/client/tests.rs')
-rw-r--r--third_party/rust/hyper/src/client/tests.rs286
1 files changed, 286 insertions, 0 deletions
diff --git a/third_party/rust/hyper/src/client/tests.rs b/third_party/rust/hyper/src/client/tests.rs
new file mode 100644
index 0000000000..0a281a637d
--- /dev/null
+++ b/third_party/rust/hyper/src/client/tests.rs
@@ -0,0 +1,286 @@
+use std::io;
+
+use futures_util::future;
+use tokio::net::TcpStream;
+
+use super::Client;
+
+#[tokio::test]
+async fn client_connect_uri_argument() {
+ let connector = tower::service_fn(|dst: http::Uri| {
+ assert_eq!(dst.scheme(), Some(&http::uri::Scheme::HTTP));
+ assert_eq!(dst.host(), Some("example.local"));
+ assert_eq!(dst.port(), None);
+ assert_eq!(dst.path(), "/", "path should be removed");
+
+ future::err::<TcpStream, _>(io::Error::new(io::ErrorKind::Other, "expect me"))
+ });
+
+ let client = Client::builder().build::<_, crate::Body>(connector);
+ let _ = client
+ .get("http://example.local/and/a/path".parse().unwrap())
+ .await
+ .expect_err("response should fail");
+}
+
+/*
+// FIXME: re-implement tests with `async/await`
+#[test]
+fn retryable_request() {
+ let _ = pretty_env_logger::try_init();
+
+ let mut rt = Runtime::new().expect("new rt");
+ let mut connector = MockConnector::new();
+
+ let sock1 = connector.mock("http://mock.local");
+ let sock2 = connector.mock("http://mock.local");
+
+ let client = Client::builder()
+ .build::<_, crate::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));
+ rt.block_on(res1.join(srv1)).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));
+
+ rt.block_on(res2.join(srv2)).expect("res2");
+}
+
+#[test]
+fn conn_reset_after_write() {
+ let _ = pretty_env_logger::try_init();
+
+ let mut rt = Runtime::new().expect("new rt");
+ let mut connector = MockConnector::new();
+
+ let sock1 = connector.mock("http://mock.local");
+
+ let client = Client::builder()
+ .build::<_, crate::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));
+ rt.block_on(res1.join(srv1)).expect("res1");
+ }
+
+ 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 connection, 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 = rt.block_on(res2.join(srv2)).expect_err("res2");
+ assert!(err.is_incomplete_message(), "{:?}", err);
+}
+
+#[test]
+fn checkout_win_allows_connect_future_to_be_pooled() {
+ let _ = pretty_env_logger::try_init();
+
+ let mut rt = Runtime::new().expect("new rt");
+ let mut connector = MockConnector::new();
+
+
+ let (tx, rx) = oneshot::channel::<()>();
+ let sock1 = connector.mock("http://mock.local");
+ let sock2 = connector.mock_fut("http://mock.local", rx);
+
+ let client = Client::builder()
+ .build::<_, crate::Body>(connector);
+
+ client.pool.no_timer();
+
+ let uri = "http://mock.local/a".parse::<crate::Uri>().expect("uri parse");
+
+ // First request just sets us up to have a connection able to be put
+ // back in the pool. *However*, it doesn't insert immediately. The
+ // body has 1 pending byte, and we will only drain in request 2, once
+ // the connect future has been started.
+ let mut body = {
+ let res1 = client.get(uri.clone())
+ .map(|res| res.into_body().concat2());
+ let srv1 = poll_fn(|| {
+ try_ready!(sock1.read(&mut [0u8; 512]));
+ // Chunked is used so as to force 2 body reads.
+ try_ready!(sock1.write(b"\
+ HTTP/1.1 200 OK\r\n\
+ transfer-encoding: chunked\r\n\
+ \r\n\
+ 1\r\nx\r\n\
+ 0\r\n\r\n\
+ "));
+ Ok(Async::Ready(()))
+ }).map_err(|e: std::io::Error| panic!("srv1 poll_fn error: {}", e));
+
+ rt.block_on(res1.join(srv1)).expect("res1").0
+ };
+
+
+ // The second request triggers the only mocked connect future, but then
+ // the drained body allows the first socket to go back to the pool,
+ // "winning" the checkout race.
+ {
+ let res2 = client.get(uri.clone());
+ let drain = poll_fn(move || {
+ body.poll()
+ });
+ let srv2 = poll_fn(|| {
+ try_ready!(sock1.read(&mut [0u8; 512]));
+ try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nx"));
+ Ok(Async::Ready(()))
+ }).map_err(|e: std::io::Error| panic!("srv2 poll_fn error: {}", e));
+
+ rt.block_on(res2.join(drain).join(srv2)).expect("res2");
+ }
+
+ // "Release" the mocked connect future, and let the runtime spin once so
+ // it's all setup...
+ {
+ let mut tx = Some(tx);
+ let client = &client;
+ let key = client.pool.h1_key("http://mock.local");
+ let mut tick_cnt = 0;
+ let fut = poll_fn(move || {
+ tx.take();
+
+ if client.pool.idle_count(&key) == 0 {
+ tick_cnt += 1;
+ assert!(tick_cnt < 10, "ticked too many times waiting for idle");
+ trace!("no idle yet; tick count: {}", tick_cnt);
+ ::futures::task::current().notify();
+ Ok(Async::NotReady)
+ } else {
+ Ok::<_, ()>(Async::Ready(()))
+ }
+ });
+ rt.block_on(fut).unwrap();
+ }
+
+ // Third request just tests out that the "loser" connection was pooled. If
+ // it isn't, this will panic since the MockConnector doesn't have any more
+ // mocks to give out.
+ {
+ let res3 = client.get(uri);
+ let srv3 = poll_fn(|| {
+ try_ready!(sock2.read(&mut [0u8; 512]));
+ try_ready!(sock2.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!("srv3 poll_fn error: {}", e));
+
+ rt.block_on(res3.join(srv3)).expect("res3");
+ }
+}
+
+#[cfg(feature = "nightly")]
+#[bench]
+fn bench_http1_get_0b(b: &mut test::Bencher) {
+ let _ = pretty_env_logger::try_init();
+
+ let mut rt = Runtime::new().expect("new rt");
+ let mut connector = MockConnector::new();
+
+
+ let client = Client::builder()
+ .build::<_, crate::Body>(connector.clone());
+
+ client.pool.no_timer();
+
+ let uri = Uri::from_static("http://mock.local/a");
+
+ b.iter(move || {
+ let sock1 = connector.mock("http://mock.local");
+ let res1 = client
+ .get(uri.clone())
+ .and_then(|res| {
+ res.into_body().for_each(|_| Ok(()))
+ });
+ 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));
+ rt.block_on(res1.join(srv1)).expect("res1");
+ });
+}
+
+#[cfg(feature = "nightly")]
+#[bench]
+fn bench_http1_get_10b(b: &mut test::Bencher) {
+ let _ = pretty_env_logger::try_init();
+
+ let mut rt = Runtime::new().expect("new rt");
+ let mut connector = MockConnector::new();
+
+
+ let client = Client::builder()
+ .build::<_, crate::Body>(connector.clone());
+
+ client.pool.no_timer();
+
+ let uri = Uri::from_static("http://mock.local/a");
+
+ b.iter(move || {
+ let sock1 = connector.mock("http://mock.local");
+ let res1 = client
+ .get(uri.clone())
+ .and_then(|res| {
+ res.into_body().for_each(|_| Ok(()))
+ });
+ let srv1 = poll_fn(|| {
+ try_ready!(sock1.read(&mut [0u8; 512]));
+ try_ready!(sock1.write(b"HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\n0123456789"));
+ Ok(Async::Ready(()))
+ }).map_err(|e: std::io::Error| panic!("srv1 poll_fn error: {}", e));
+ rt.block_on(res1.join(srv1)).expect("res1");
+ });
+}
+*/