Refactor internal testing setup (#338)

This changes the test setup to use our own client rather than using
reqwest directly. Allows us to add several quality of life features like
always unwrapping results.
This commit is contained in:
David Pedersen 2021-09-19 11:38:34 +02:00 committed by GitHub
parent 2a683417d1
commit 0b9e0c7508
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 338 additions and 645 deletions

View file

@ -335,19 +335,12 @@ mod tests {
let app = Router::new().route("/", post(handler));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.post(format!("http://{}", addr))
.body("hi there")
.send()
.await
.unwrap();
let res = client.post("/").body("hi there").send().await;
assert_eq!(res.status(), StatusCode::INTERNAL_SERVER_ERROR);
assert_eq!(
res.text().await.unwrap(),
res.text().await,
"Cannot have two request body extractors for a single handler"
);
}

View file

@ -152,21 +152,14 @@ mod tests {
let app = Router::new().route("/", get(handle));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}", addr))
.header("user-agent", "foobar")
.send()
.await
.unwrap();
let body = res.text().await.unwrap();
let res = client.get("/").header("user-agent", "foobar").send().await;
let body = res.text().await;
assert_eq!(body, "foobar");
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let body = res.text().await.unwrap();
let res = client.get("/").send().await;
let body = res.text().await;
assert_eq!(body, "Header of type `user-agent` was missing");
}
}

View file

@ -48,15 +48,9 @@ async fn handler() {
.handle_error(|_: BoxError| Ok::<_, Infallible>(StatusCode::REQUEST_TIMEOUT))),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
}
@ -70,15 +64,9 @@ async fn handler_multiple_methods_first() {
.post(unit),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
}
@ -95,15 +83,9 @@ async fn handler_multiple_methods_middle() {
.post(unit),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
}
@ -118,15 +100,9 @@ async fn handler_multiple_methods_last() {
),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
}

140
src/tests/helpers.rs Normal file
View file

@ -0,0 +1,140 @@
#![allow(unused_imports, dead_code)]
use crate::BoxError;
use crate::{
extract,
handler::{any, delete, get, on, patch, post, Handler},
response::IntoResponse,
routing::MethodFilter,
service, Router,
};
use bytes::Bytes;
use http::{
header::{HeaderMap, HeaderName, HeaderValue, AUTHORIZATION},
Method, Request, StatusCode, Uri,
};
use hyper::{Body, Server};
use serde::Deserialize;
use serde_json::json;
use std::future::Ready;
use std::{
collections::HashMap,
convert::{Infallible, TryFrom},
future::ready,
net::{SocketAddr, TcpListener},
task::{Context, Poll},
time::Duration,
};
use tower::{make::Shared, service_fn};
use tower_service::Service;
pub(crate) struct TestClient {
client: reqwest::Client,
addr: SocketAddr,
}
impl TestClient {
pub(crate) fn new<S, ResBody>(svc: S) -> Self
where
S: Service<Request<Body>, Response = http::Response<ResBody>> + Clone + Send + 'static,
ResBody: http_body::Body + Send + 'static,
ResBody::Data: Send,
ResBody::Error: Into<BoxError>,
S::Future: Send,
S::Error: Into<BoxError>,
{
let listener = TcpListener::bind("127.0.0.1:0").expect("Could not bind ephemeral socket");
let addr = listener.local_addr().unwrap();
println!("Listening on {}", addr);
tokio::spawn(async move {
let server = Server::from_tcp(listener).unwrap().serve(Shared::new(svc));
server.await.expect("server error");
});
TestClient {
client: reqwest::Client::new(),
addr,
}
}
pub(crate) fn get(&self, url: &str) -> RequestBuilder {
RequestBuilder {
builder: self.client.get(format!("http://{}{}", self.addr, url)),
}
}
pub(crate) fn post(&self, url: &str) -> RequestBuilder {
RequestBuilder {
builder: self.client.post(format!("http://{}{}", self.addr, url)),
}
}
pub(crate) fn put(&self, url: &str) -> RequestBuilder {
RequestBuilder {
builder: self.client.put(format!("http://{}{}", self.addr, url)),
}
}
pub(crate) fn patch(&self, url: &str) -> RequestBuilder {
RequestBuilder {
builder: self.client.patch(format!("http://{}{}", self.addr, url)),
}
}
}
pub(crate) struct RequestBuilder {
builder: reqwest::RequestBuilder,
}
impl RequestBuilder {
pub(crate) async fn send(self) -> Response {
Response {
response: self.builder.send().await.unwrap(),
}
}
pub(crate) fn body(mut self, body: impl Into<reqwest::Body>) -> Self {
self.builder = self.builder.body(body);
self
}
pub(crate) fn json<T>(mut self, json: &T) -> Self
where
T: serde::Serialize,
{
self.builder = self.builder.json(json);
self
}
pub(crate) fn header<K, V>(mut self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<http::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
{
self.builder = self.builder.header(key, value);
self
}
}
pub(crate) struct Response {
response: reqwest::Response,
}
impl Response {
pub(crate) async fn text(self) -> String {
self.response.text().await.unwrap()
}
pub(crate) async fn json<T>(self) -> T
where
T: serde::de::DeserializeOwned,
{
self.response.json().await.unwrap()
}
pub(crate) fn status(&self) -> StatusCode {
self.response.status()
}
}

View file

@ -2,7 +2,7 @@
use crate::BoxError;
use crate::{
extract,
extract::{self, Path},
handler::{any, delete, get, on, patch, post, Handler},
response::IntoResponse,
routing::MethodFilter,
@ -13,7 +13,7 @@ use http::{
header::{HeaderMap, AUTHORIZATION},
Request, Response, StatusCode, Uri,
};
use hyper::{Body, Server};
use hyper::Body;
use serde::Deserialize;
use serde_json::json;
use std::future::Ready;
@ -21,15 +21,17 @@ use std::{
collections::HashMap,
convert::Infallible,
future::ready,
net::{SocketAddr, TcpListener},
task::{Context, Poll},
time::Duration,
};
use tower::{make::Shared, service_fn};
use tower::service_fn;
use tower_service::Service;
pub(crate) use helpers::*;
mod get_to_head;
mod handle_error;
mod helpers;
mod nest;
mod or;
@ -51,28 +53,18 @@ async fn hello_world() {
.route("/", get(root).post(foo))
.route("/users", post(users_create));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let body = res.text().await.unwrap();
let res = client.get("/").send().await;
let body = res.text().await;
assert_eq!(body, "Hello, World!");
let res = client
.post(format!("http://{}", addr))
.send()
.await
.unwrap();
let body = res.text().await.unwrap();
let res = client.post("/").send().await;
let body = res.text().await;
assert_eq!(body, "foo");
let res = client
.post(format!("http://{}/users", addr))
.send()
.await
.unwrap();
let body = res.text().await.unwrap();
let res = client.post("/users").send().await;
let body = res.text().await;
assert_eq!(body, "users#create");
}
@ -80,16 +72,9 @@ async fn hello_world() {
async fn consume_body() {
let app = Router::new().route("/", get(|body: String| async { body }));
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}", addr))
.body("foo")
.send()
.await
.unwrap();
let body = res.text().await.unwrap();
let client = TestClient::new(app);
let res = client.get("/").body("foo").send().await;
let body = res.text().await;
assert_eq!(body, "foo");
}
@ -106,16 +91,9 @@ async fn deserialize_body() {
post(|input: extract::Json<Input>| async { input.0.foo }),
);
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let res = client
.post(format!("http://{}", addr))
.json(&json!({ "foo": "bar" }))
.send()
.await
.unwrap();
let body = res.text().await.unwrap();
let client = TestClient::new(app);
let res = client.post("/").json(&json!({ "foo": "bar" })).send().await;
let body = res.text().await;
assert_eq!(body, "bar");
}
@ -132,18 +110,11 @@ async fn consume_body_to_json_requires_json_content_type() {
post(|input: extract::Json<Input>| async { input.0.foo }),
);
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let res = client
.post(format!("http://{}", addr))
.body(r#"{ "foo": "bar" }"#)
.send()
.await
.unwrap();
let client = TestClient::new(app);
let res = client.post("/").body(r#"{ "foo": "bar" }"#).send().await;
let status = res.status();
dbg!(res.text().await.unwrap());
dbg!(res.text().await);
assert_eq!(status, StatusCode::BAD_REQUEST);
}
@ -164,42 +135,35 @@ async fn body_with_length_limit() {
post(|_body: extract::ContentLengthLimit<Bytes, LIMIT>| async {}),
);
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let client = TestClient::new(app);
let res = client
.post(format!("http://{}", addr))
.post("/")
.body(repeat(0_u8).take((LIMIT - 1) as usize).collect::<Vec<_>>())
.send()
.await
.unwrap();
.await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}", addr))
.post("/")
.body(repeat(0_u8).take(LIMIT as usize).collect::<Vec<_>>())
.send()
.await
.unwrap();
.await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}", addr))
.post("/")
.body(repeat(0_u8).take((LIMIT + 1) as usize).collect::<Vec<_>>())
.send()
.await
.unwrap();
.await;
assert_eq!(res.status(), StatusCode::PAYLOAD_TOO_LARGE);
let res = client
.post(format!("http://{}", addr))
.post("/")
.body(reqwest::Body::wrap_stream(futures_util::stream::iter(
vec![Ok::<_, std::io::Error>(bytes::Bytes::new())],
)))
.send()
.await
.unwrap();
.await;
assert_eq!(res.status(), StatusCode::LENGTH_REQUIRED);
}
@ -217,76 +181,46 @@ async fn routing() {
get(|_: Request<Body>| async { "users#action" }),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
let res = client
.get(format!("http://{}/users", addr))
.send()
.await
.unwrap();
let res = client.get("/users").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "users#index");
assert_eq!(res.text().await, "users#index");
let res = client
.post(format!("http://{}/users", addr))
.send()
.await
.unwrap();
let res = client.post("/users").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "users#create");
assert_eq!(res.text().await, "users#create");
let res = client
.get(format!("http://{}/users/1", addr))
.send()
.await
.unwrap();
let res = client.get("/users/1").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "users#show");
assert_eq!(res.text().await, "users#show");
let res = client
.get(format!("http://{}/users/1/action", addr))
.send()
.await
.unwrap();
let res = client.get("/users/1/action").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "users#action");
assert_eq!(res.text().await, "users#action");
}
#[tokio::test]
async fn extracting_url_params() {
let app = Router::new().route(
"/users/:id",
get(|extract::Path(id): extract::Path<i32>| async move {
get(|Path(id): Path<i32>| async move {
assert_eq!(id, 42);
})
.post(
|extract::Path(params_map): extract::Path<HashMap<String, i32>>| async move {
assert_eq!(params_map.get("id").unwrap(), &1337);
},
),
.post(|Path(params_map): Path<HashMap<String, i32>>| async move {
assert_eq!(params_map.get("id").unwrap(), &1337);
}),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/users/42", addr))
.send()
.await
.unwrap();
let res = client.get("/users/42").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}/users/1337", addr))
.send()
.await
.unwrap();
let res = client.post("/users/1337").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -297,15 +231,9 @@ async fn extracting_url_params_multiple_times() {
get(|_: extract::Path<i32>, _: extract::Path<String>| async {}),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/users/42", addr))
.send()
.await
.unwrap();
let res = client.get("/users/42").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -324,21 +252,15 @@ async fn boxing() {
.layer(tower_http::compression::CompressionLayer::new())
.boxed();
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "hi from GET");
assert_eq!(res.text().await, "hi from GET");
let res = client
.post(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.post("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "hi from POST");
assert_eq!(res.text().await, "hi from POST");
}
#[tokio::test]
@ -368,41 +290,23 @@ async fn routing_between_services() {
)
.route("/two", service::on(MethodFilter::GET, any(handle)));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/one", addr))
.send()
.await
.unwrap();
let res = client.get("/one").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "one get");
assert_eq!(res.text().await, "one get");
let res = client
.post(format!("http://{}/one", addr))
.send()
.await
.unwrap();
let res = client.post("/one").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "one post");
assert_eq!(res.text().await, "one post");
let res = client
.put(format!("http://{}/one", addr))
.send()
.await
.unwrap();
let res = client.put("/one").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "one put");
assert_eq!(res.text().await, "one put");
let res = client
.get(format!("http://{}/two", addr))
.send()
.await
.unwrap();
let res = client.get("/two").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "handler");
assert_eq!(res.text().await, "handler");
}
#[tokio::test]
@ -424,23 +328,23 @@ async fn middleware_on_single_route() {
)),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let res = reqwest::get(format!("http://{}", addr)).await.unwrap();
let body = res.text().await.unwrap();
let res = client.get("/").send().await;
let body = res.text().await;
assert_eq!(body, "Hello, World!");
}
#[tokio::test]
async fn service_in_bottom() {
async fn handler(_req: Request<hyper::Body>) -> Result<Response<hyper::Body>, hyper::Error> {
async fn handler(_req: Request<Body>) -> Result<Response<Body>, hyper::Error> {
Ok(Response::new(hyper::Body::empty()))
}
let app = Router::new().route("/", service::get(service_fn(handler)));
run_in_background(app).await;
TestClient::new(app);
}
#[tokio::test]
@ -477,23 +381,12 @@ async fn test_extractor_middleware() {
get(handler.layer(extract::extractor_middleware::<RequireAuth>())),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
let res = client
.get(format!("http://{}/", addr))
.header(AUTHORIZATION, "secret")
.send()
.await
.unwrap();
let res = client.get("/").header(AUTHORIZATION, "secret").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -503,36 +396,18 @@ async fn wrong_method_handler() {
.route("/", get(|| async {}).post(|| async {}))
.route("/foo", patch(|| async {}));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.patch(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.patch("/").send().await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let res = client
.patch(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.patch("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.post("/foo").send().await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
@ -559,36 +434,18 @@ async fn wrong_method_service() {
.route("/", service::get(Svc).post(Svc))
.route("/foo", service::patch(Svc));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.patch(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.patch("/").send().await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let res = client
.patch(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.patch("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.post("/foo").send().await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
@ -600,18 +457,12 @@ async fn multiple_methods_for_one_handler() {
let app = Router::new().route("/", on(MethodFilter::GET | MethodFilter::POST, root));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.post("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -621,18 +472,11 @@ async fn handler_into_service() {
format!("you said: {}", body)
}
let addr = run_in_background(handle.into_service()).await;
let client = TestClient::new(handle.into_service());
let client = reqwest::Client::new();
let res = client
.post(format!("http://{}", addr))
.body("hi there!")
.send()
.await
.unwrap();
let res = client.post("/").body("hi there!").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "you said: hi there!");
assert_eq!(res.text().await, "you said: hi there!");
}
#[tokio::test]
@ -643,32 +487,18 @@ async fn when_multiple_routes_match() {
.route("/foo", get(|| async {}))
.nest("/foo", Router::new().route("/bar", get(|| async {})));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.post("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/foo/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -676,48 +506,15 @@ async fn when_multiple_routes_match() {
async fn captures_dont_match_empty_segments() {
let app = Router::new().route("/:key", get(|| async {}));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
/// Run a `tower::Service` in the background and get a URI for it.
pub(crate) async fn run_in_background<S, ResBody>(svc: S) -> SocketAddr
where
S: Service<Request<Body>, Response = Response<ResBody>> + Clone + Send + 'static,
ResBody: http_body::Body + Send + 'static,
ResBody::Data: Send,
ResBody::Error: Into<BoxError>,
S::Future: Send,
S::Error: Into<BoxError>,
{
let listener = TcpListener::bind("127.0.0.1:0").expect("Could not bind ephemeral socket");
let addr = listener.local_addr().unwrap();
println!("Listening on {}", addr);
let (tx, rx) = tokio::sync::oneshot::channel();
tokio::spawn(async move {
let server = Server::from_tcp(listener).unwrap().serve(Shared::new(svc));
tx.send(()).unwrap();
server.await.expect("server error");
});
rx.await.unwrap();
addr
}
pub(crate) fn assert_send<T: Send>() {}
pub(crate) fn assert_sync<T: Sync>() {}
pub(crate) fn assert_unpin<T: Unpin>() {}

View file

@ -38,41 +38,23 @@ async fn nesting_apps() {
.route("/", get(|| async { "hi" }))
.nest("/:version/api", api_routes);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/", addr))
.send()
.await
.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "hi");
assert_eq!(res.text().await, "hi");
let res = client
.get(format!("http://{}/v0/api/users", addr))
.send()
.await
.unwrap();
let res = client.get("/v0/api/users").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "users#index");
assert_eq!(res.text().await, "users#index");
let res = client
.get(format!("http://{}/v0/api/users/123", addr))
.send()
.await
.unwrap();
let res = client.get("/v0/api/users/123").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "v0: users#show (123)");
assert_eq!(res.text().await, "v0: users#show (123)");
let res = client
.get(format!("http://{}/v0/api/games/123", addr))
.send()
.await
.unwrap();
let res = client.get("/v0/api/games/123").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "v0: games#show (123)");
assert_eq!(res.text().await, "v0: games#show (123)");
}
#[tokio::test]
@ -80,25 +62,15 @@ async fn wrong_method_nest() {
let nested_app = Router::new().route("/", get(|| async {}));
let app = Router::new().nest("/", nested_app);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.post(format!("http://{}", addr))
.send()
.await
.unwrap();
let res = client.post("/").send().await;
assert_eq!(res.status(), StatusCode::METHOD_NOT_ALLOWED);
let res = client
.patch(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.patch("/foo").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
@ -106,29 +78,19 @@ async fn wrong_method_nest() {
async fn nesting_at_root() {
let app = Router::new().nest("/", get(|uri: Uri| async move { uri.to_string() }));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client.get(format!("http://{}", addr)).send().await.unwrap();
let res = client.get("/").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/");
assert_eq!(res.text().await, "/");
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/foo");
assert_eq!(res.text().await, "/foo");
let res = client
.get(format!("http://{}/foo/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/foo/bar");
assert_eq!(res.text().await, "/foo/bar");
}
#[tokio::test]
@ -146,25 +108,15 @@ async fn nested_url_extractor() {
),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/baz");
assert_eq!(res.text().await, "/baz");
let res = client
.get(format!("http://{}/foo/bar/qux", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/qux").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/qux");
assert_eq!(res.text().await, "/qux");
}
#[tokio::test]
@ -180,17 +132,11 @@ async fn nested_url_original_extractor() {
),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/foo/bar/baz");
assert_eq!(res.text().await, "/foo/bar/baz");
}
#[tokio::test]
@ -209,17 +155,11 @@ async fn nested_service_sees_stripped_uri() {
),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), "/baz");
assert_eq!(res.text().await, "/baz");
}
#[tokio::test]
@ -234,14 +174,8 @@ async fn nest_static_file_server() {
}),
);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/static/README.md", addr))
.send()
.await
.unwrap();
let res = client.get("/static/README.md").send().await;
assert_eq!(res.status(), StatusCode::OK);
}

View file

@ -11,36 +11,18 @@ async fn basic() {
let two = Router::new().route("/baz", get(|| async {}));
let app = one.or(two);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/qux", addr))
.send()
.await
.unwrap();
let res = client.get("/qux").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
@ -86,19 +68,13 @@ async fn multiple_ors_balanced_differently() {
S::Future: Send,
S::Error: Into<BoxError>,
{
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let client = TestClient::new(app);
for n in ["one", "two", "three", "four"].iter() {
println!("running: {} / {}", name, n);
let res = client
.get(format!("http://{}/{}", addr, n))
.send()
.await
.unwrap();
let res = client.get(&format!("/{}", n)).send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await.unwrap(), *n);
assert_eq!(res.text().await, *n);
}
}
}
@ -110,22 +86,12 @@ async fn or_nested_inside_other_thing() {
.or(Router::new().route("/baz", get(|| async {})));
let app = Router::new().nest("/foo", inner);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/foo/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -135,29 +101,15 @@ async fn or_with_route_following() {
let two = Router::new().route("/two", get(|| async { "two" }));
let app = one.or(two).route("/three", get(|| async { "three" }));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/one", addr))
.send()
.await
.unwrap();
let res = client.get("/one").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/two", addr))
.send()
.await
.unwrap();
let res = client.get("/two").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/three", addr))
.send()
.await
.unwrap();
let res = client.get("/three").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -169,22 +121,12 @@ async fn layer() {
.layer(ConcurrencyLimitLayer::new(10));
let app = one.or(two);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -192,20 +134,14 @@ async fn layer() {
async fn layer_and_handle_error() {
let one = Router::new().route("/foo", get(|| async {}));
let two = Router::new()
.route("/time-out", get(futures::future::pending::<()>))
.route("/timeout", get(futures::future::pending::<()>))
.layer(TimeoutLayer::new(Duration::from_millis(10)))
.handle_error(|_| Ok(StatusCode::REQUEST_TIMEOUT));
let app = one.or(two);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/time-out", addr))
.send()
.await
.unwrap();
let res = client.get("/timeout").send().await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
}
@ -215,15 +151,9 @@ async fn nesting() {
let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {})));
let app = one.or(two);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -233,15 +163,9 @@ async fn boxed() {
let two = Router::new().route("/bar", get(|| async {})).boxed();
let app = one.or(two);
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -256,24 +180,14 @@ async fn many_ors() {
.or(Router::new().route("/r6", get(|| async {})))
.or(Router::new().route("/r7", get(|| async {})));
let addr = run_in_background(app).await;
let client = reqwest::Client::new();
let client = TestClient::new(app);
for n in 1..=7 {
let res = client
.get(format!("http://{}/r{}", addr, n))
.send()
.await
.unwrap();
let res = client.get(&format!("/r{}", n)).send().await;
assert_eq!(res.status(), StatusCode::OK);
}
let res = client
.get(format!("http://{}/r8", addr))
.send()
.await
.unwrap();
let res = client.get("/r8").send().await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
@ -293,22 +207,12 @@ async fn services() {
})),
));
let addr = run_in_background(app).await;
let client = TestClient::new(app);
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
let res = client
.get(format!("http://{}/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
}
@ -329,18 +233,12 @@ async fn nesting_and_seeing_the_right_uri() {
let one = Router::new().nest("/foo", Router::new().route("/bar", get(all_the_uris)));
let two = Router::new().route("/foo", get(all_the_uris));
let addr = run_in_background(one.or(two)).await;
let client = TestClient::new(one.or(two));
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/bar",
"request_uri": "/bar",
@ -348,14 +246,10 @@ async fn nesting_and_seeing_the_right_uri() {
})
);
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/foo",
"request_uri": "/foo",
@ -372,18 +266,12 @@ async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
);
let two = Router::new().route("/foo", get(all_the_uris));
let addr = run_in_background(one.or(two)).await;
let client = TestClient::new(one.or(two));
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/baz",
"request_uri": "/baz",
@ -391,14 +279,10 @@ async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
})
);
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/foo",
"request_uri": "/foo",
@ -416,18 +300,12 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
let two = Router::new().nest("/foo", Router::new().route("/qux", get(all_the_uris)));
let three = Router::new().route("/foo", get(all_the_uris));
let addr = run_in_background(one.or(two).or(three)).await;
let client = TestClient::new(one.or(two).or(three));
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/baz",
"request_uri": "/baz",
@ -435,14 +313,10 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
})
);
let res = client
.get(format!("http://{}/foo/qux", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/qux").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/qux",
"request_uri": "/qux",
@ -450,14 +324,10 @@ async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
})
);
let res = client
.get(format!("http://{}/foo", addr))
.send()
.await
.unwrap();
let res = client.get("/foo").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/foo",
"request_uri": "/foo",
@ -474,18 +344,12 @@ async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
);
let two = Router::new().route("/foo/bar", get(all_the_uris));
let addr = run_in_background(one.or(two)).await;
let client = TestClient::new(one.or(two));
let client = reqwest::Client::new();
let res = client
.get(format!("http://{}/foo/bar/baz", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar/baz").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/baz",
"request_uri": "/baz",
@ -493,14 +357,10 @@ async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
})
);
let res = client
.get(format!("http://{}/foo/bar", addr))
.send()
.await
.unwrap();
let res = client.get("/foo/bar").send().await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await.unwrap(),
res.json::<Value>().await,
json!({
"uri": "/foo/bar",
"request_uri": "/foo/bar",