Rewrite tests with a hyper server instead of raw TCP
This makes the tests much less brittle, by not depending on the exact order of the HTTP headers, nor always requiring to check for every single header.
This commit is contained in:
362
tests/client.rs
362
tests/client.rs
@@ -1,44 +1,35 @@
|
||||
#[macro_use]
|
||||
mod support;
|
||||
use support::*;
|
||||
|
||||
use std::io::Write;
|
||||
use std::time::Duration;
|
||||
|
||||
use reqwest::multipart::{Form, Part};
|
||||
use reqwest::{Body, Client};
|
||||
|
||||
use bytes::Bytes;
|
||||
use reqwest::Client;
|
||||
|
||||
#[tokio::test]
|
||||
async fn gzip_response() {
|
||||
gzip_case(10_000, 4096).await;
|
||||
}
|
||||
async fn auto_headers() {
|
||||
let server = server::http(move |req| {
|
||||
async move {
|
||||
assert_eq!(req.method(), "GET");
|
||||
|
||||
#[tokio::test]
|
||||
async fn gzip_single_byte_chunks() {
|
||||
gzip_case(10, 1).await;
|
||||
assert_eq!(req.headers()["accept"], "*/*");
|
||||
assert_eq!(req.headers()["user-agent"], DEFAULT_USER_AGENT);
|
||||
assert_eq!(req.headers()["accept-encoding"], "gzip");
|
||||
|
||||
http::Response::default()
|
||||
}
|
||||
});
|
||||
|
||||
let url = format!("http://{}/1", server.addr());
|
||||
let res = reqwest::get(&url).await.unwrap();
|
||||
|
||||
assert_eq!(res.url().as_str(), &url);
|
||||
assert_eq!(res.status(), reqwest::StatusCode::OK);
|
||||
assert_eq!(res.remote_addr(), Some(server.addr()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn response_text() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /text HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Content-Length: 5\r\n\
|
||||
\r\n\
|
||||
Hello\
|
||||
"
|
||||
};
|
||||
let server = server::http(move |_req| async { http::Response::new("Hello".into()) });
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
@@ -55,22 +46,7 @@ async fn response_text() {
|
||||
async fn response_json() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /json HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Content-Length: 7\r\n\
|
||||
\r\n\
|
||||
\"Hello\"\
|
||||
"
|
||||
};
|
||||
let server = server::http(move |_req| async { http::Response::new("\"Hello\"".into()) });
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
@@ -83,287 +59,29 @@ async fn response_json() {
|
||||
assert_eq!("Hello", text);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn multipart() {
|
||||
use futures_util::{future, stream};
|
||||
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let stream = reqwest::Body::wrap_stream(stream::once(future::ready(Ok::<_, reqwest::Error>(
|
||||
"part1 part2".to_owned(),
|
||||
))));
|
||||
let part = Part::stream(stream);
|
||||
|
||||
let form = Form::new().text("foo", "bar").part("part_stream", part);
|
||||
|
||||
let expected_body = format!(
|
||||
"\
|
||||
24\r\n\
|
||||
--{0}\r\n\r\n\
|
||||
2E\r\n\
|
||||
Content-Disposition: form-data; name=\"foo\"\r\n\r\n\r\n\
|
||||
3\r\n\
|
||||
bar\r\n\
|
||||
2\r\n\
|
||||
\r\n\r\n\
|
||||
24\r\n\
|
||||
--{0}\r\n\r\n\
|
||||
36\r\n\
|
||||
Content-Disposition: form-data; name=\"part_stream\"\r\n\r\n\r\n\
|
||||
B\r\n\
|
||||
part1 part2\r\n\
|
||||
2\r\n\
|
||||
\r\n\r\n\
|
||||
26\r\n\
|
||||
--{0}--\r\n\r\n\
|
||||
0\r\n\r\n\
|
||||
",
|
||||
form.boundary()
|
||||
);
|
||||
|
||||
let server = server! {
|
||||
request: format!("\
|
||||
POST /multipart/1 HTTP/1.1\r\n\
|
||||
content-type: multipart/form-data; boundary={}\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
transfer-encoding: chunked\r\n\
|
||||
\r\n\
|
||||
{}\
|
||||
", form.boundary(), expected_body),
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: multipart\r\n\
|
||||
Content-Length: 0\r\n\
|
||||
\r\n\
|
||||
"
|
||||
};
|
||||
|
||||
let url = format!("http://{}/multipart/1", server.addr());
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
let res = client
|
||||
.post(&url)
|
||||
.multipart(form)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to post multipart");
|
||||
assert_eq!(res.url().as_str(), &url);
|
||||
assert_eq!(res.status(), reqwest::StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn request_timeout() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /slow HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Content-Length: 5\r\n\
|
||||
\r\n\
|
||||
Hello\
|
||||
",
|
||||
read_timeout: Duration::from_secs(2)
|
||||
};
|
||||
|
||||
let client = Client::builder()
|
||||
.timeout(Duration::from_millis(500))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let url = format!("http://{}/slow", server.addr());
|
||||
|
||||
let res = client.get(&url).send().await;
|
||||
|
||||
let err = res.unwrap_err();
|
||||
|
||||
assert!(err.is_timeout());
|
||||
assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn response_timeout() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /slow HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Content-Length: 5\r\n\
|
||||
\r\n\
|
||||
Hello\
|
||||
",
|
||||
write_timeout: Duration::from_secs(2)
|
||||
};
|
||||
|
||||
let client = Client::builder()
|
||||
.timeout(Duration::from_millis(500))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let url = format!("http://{}/slow", server.addr());
|
||||
let res = client.get(&url).send().await.expect("Failed to get");
|
||||
let body = res.text().await;
|
||||
|
||||
let err = body.unwrap_err();
|
||||
|
||||
assert!(err.is_timeout());
|
||||
}
|
||||
|
||||
async fn gzip_case(response_size: usize, chunk_size: usize) {
|
||||
let content: String = (0..response_size)
|
||||
.into_iter()
|
||||
.map(|i| format!("test {}", i))
|
||||
.collect();
|
||||
let mut encoder = libflate::gzip::Encoder::new(Vec::new()).unwrap();
|
||||
match encoder.write(content.as_bytes()) {
|
||||
Ok(n) => assert!(n > 0, "Failed to write to encoder."),
|
||||
_ => panic!("Failed to gzip encode string."),
|
||||
};
|
||||
|
||||
let gzipped_content = encoder.finish().into_result().unwrap();
|
||||
|
||||
let mut response = format!(
|
||||
"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: test-accept\r\n\
|
||||
Content-Encoding: gzip\r\n\
|
||||
Content-Length: {}\r\n\
|
||||
\r\n",
|
||||
&gzipped_content.len()
|
||||
)
|
||||
.into_bytes();
|
||||
response.extend(&gzipped_content);
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /gzip HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
chunk_size: chunk_size,
|
||||
write_timeout: Duration::from_millis(10),
|
||||
response: response
|
||||
};
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
let res = client
|
||||
.get(&format!("http://{}/gzip", server.addr()))
|
||||
.send()
|
||||
.await
|
||||
.expect("response");
|
||||
|
||||
let body = res.text().await.expect("text");
|
||||
assert_eq!(body, content);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn body_stream() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let source = futures_util::stream::iter::<Vec<Result<Bytes, std::io::Error>>>(vec![
|
||||
Ok(Bytes::from_static(b"123")),
|
||||
Ok(Bytes::from_static(b"4567")),
|
||||
]);
|
||||
|
||||
let expected_body = "3\r\n123\r\n4\r\n4567\r\n0\r\n\r\n";
|
||||
|
||||
let server = server! {
|
||||
request: format!("\
|
||||
POST /post HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
transfer-encoding: chunked\r\n\
|
||||
\r\n\
|
||||
{}\
|
||||
", expected_body),
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: post\r\n\
|
||||
Content-Length: 7\r\n\
|
||||
\r\n\
|
||||
"
|
||||
};
|
||||
|
||||
let url = format!("http://{}/post", server.addr());
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
let res = client
|
||||
.post(&url)
|
||||
.body(Body::wrap_stream(source))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to post");
|
||||
|
||||
assert_eq!(res.url().as_str(), &url);
|
||||
assert_eq!(res.status(), reqwest::StatusCode::OK);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn body_pipe_response() {
|
||||
let _ = env_logger::try_init();
|
||||
|
||||
let server = server! {
|
||||
request: b"\
|
||||
GET /get HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: pipe\r\n\
|
||||
Content-Length: 7\r\n\
|
||||
\r\n\
|
||||
pipe me\
|
||||
";
|
||||
let server = server::http(move |mut req| {
|
||||
async move {
|
||||
if req.uri() == "/get" {
|
||||
http::Response::new("pipe me".into())
|
||||
} else {
|
||||
assert_eq!(req.uri(), "/pipe");
|
||||
assert_eq!(req.headers()["transfer-encoding"], "chunked");
|
||||
|
||||
request: b"\
|
||||
POST /pipe HTTP/1.1\r\n\
|
||||
user-agent: $USERAGENT\r\n\
|
||||
accept: */*\r\n\
|
||||
accept-encoding: gzip\r\n\
|
||||
host: $HOST\r\n\
|
||||
transfer-encoding: chunked\r\n\
|
||||
\r\n\
|
||||
7\r\n\
|
||||
pipe me\r\n\
|
||||
0\r\n\r\n\
|
||||
",
|
||||
response: b"\
|
||||
HTTP/1.1 200 OK\r\n\
|
||||
Server: pipe\r\n\
|
||||
Content-Length: 0\r\n\
|
||||
\r\n\
|
||||
"
|
||||
};
|
||||
let mut full: Vec<u8> = Vec::new();
|
||||
while let Some(item) = req.body_mut().next().await {
|
||||
full.extend(&*item.unwrap());
|
||||
}
|
||||
|
||||
assert_eq!(full, b"pipe me");
|
||||
|
||||
http::Response::default()
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user