use super::*;
use crate::extract::OriginalUri;
use serde_json::{json, Value};
use tower::limit::ConcurrencyLimitLayer;
#[crate::test]
async fn basic() {
let one = Router::new()
.route("/foo", get(|| async {}))
.route("/bar", get(|| async {}));
let two = Router::new().route("/baz", get(|| async {}));
let app = one.merge(two);
let client = TestClient::new(app);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/bar").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/baz").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/qux").await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
#[crate::test]
async fn multiple_ors_balanced_differently() {
let one = Router::new().route("/one", get(|| async { "one" }));
let two = Router::new().route("/two", get(|| async { "two" }));
let three = Router::new().route("/three", get(|| async { "three" }));
let four = Router::new().route("/four", get(|| async { "four" }));
test(
"one",
one.clone()
.merge(two.clone())
.merge(three.clone())
.merge(four.clone()),
)
.await;
test(
"two",
one.clone()
.merge(two.clone())
.merge(three.clone().merge(four.clone())),
)
.await;
test(
"three",
one.clone()
.merge(two.clone().merge(three.clone()).merge(four.clone())),
)
.await;
test("four", one.merge(two.merge(three.merge(four)))).await;
async fn test(name: &str, app: Router) {
let client = TestClient::new(app);
for n in ["one", "two", "three", "four"].iter() {
println!("running: {name} / {n}");
let res = client.get(&format!("/{n}")).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(res.text().await, *n);
}
}
}
#[crate::test]
async fn nested_or() {
let bar = Router::new().route("/bar", get(|| async { "bar" }));
let baz = Router::new().route("/baz", get(|| async { "baz" }));
let bar_or_baz = bar.merge(baz);
let client = TestClient::new(bar_or_baz.clone());
assert_eq!(client.get("/bar").await.text().await, "bar");
assert_eq!(client.get("/baz").await.text().await, "baz");
let client = TestClient::new(Router::new().nest("/foo", bar_or_baz));
assert_eq!(client.get("/foo/bar").await.text().await, "bar");
assert_eq!(client.get("/foo/baz").await.text().await, "baz");
}
#[crate::test]
async fn or_with_route_following() {
let one = Router::new().route("/one", get(|| async { "one" }));
let two = Router::new().route("/two", get(|| async { "two" }));
let app = one.merge(two).route("/three", get(|| async { "three" }));
let client = TestClient::new(app);
let res = client.get("/one").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/two").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/three").await;
assert_eq!(res.status(), StatusCode::OK);
}
#[crate::test]
async fn layer() {
let one = Router::new().route("/foo", get(|| async {}));
let two = Router::new()
.route("/bar", get(|| async {}))
.layer(ConcurrencyLimitLayer::new(10));
let app = one.merge(two);
let client = TestClient::new(app);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/bar").await;
assert_eq!(res.status(), StatusCode::OK);
}
#[crate::test]
async fn layer_and_handle_error() {
let one = Router::new().route("/foo", get(|| async {}));
let two = Router::new()
.route("/timeout", get(std::future::pending::<()>))
.layer(TimeoutLayer::with_status_code(
StatusCode::REQUEST_TIMEOUT,
Duration::from_millis(10),
));
let app = one.merge(two);
let client = TestClient::new(app);
let res = client.get("/timeout").await;
assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
}
#[crate::test]
async fn nesting() {
let one = Router::new().route("/foo", get(|| async {}));
let two = Router::new().nest("/bar", Router::new().route("/baz", get(|| async {})));
let app = one.merge(two);
let client = TestClient::new(app);
let res = client.get("/bar/baz").await;
assert_eq!(res.status(), StatusCode::OK);
}
#[crate::test]
async fn boxed() {
let one = Router::new().route("/foo", get(|| async {}));
let two = Router::new().route("/bar", get(|| async {}));
let app = one.merge(two);
let client = TestClient::new(app);
let res = client.get("/bar").await;
assert_eq!(res.status(), StatusCode::OK);
}
#[crate::test]
async fn many_ors() {
let app = Router::new()
.route("/r1", get(|| async {}))
.merge(Router::new().route("/r2", get(|| async {})))
.merge(Router::new().route("/r3", get(|| async {})))
.merge(Router::new().route("/r4", get(|| async {})))
.merge(Router::new().route("/r5", get(|| async {})))
.merge(Router::new().route("/r6", get(|| async {})))
.merge(Router::new().route("/r7", get(|| async {})));
let client = TestClient::new(app);
for n in 1..=7 {
let res = client.get(&format!("/r{n}")).await;
assert_eq!(res.status(), StatusCode::OK);
}
let res = client.get("/r8").await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
}
#[crate::test]
async fn services() {
use crate::routing::get_service;
let app = Router::new()
.route(
"/foo",
get_service(service_fn(|_: Request| async {
Ok::<_, Infallible>(Response::new(Body::empty()))
})),
)
.merge(Router::new().route(
"/bar",
get_service(service_fn(|_: Request| async {
Ok::<_, Infallible>(Response::new(Body::empty()))
})),
));
let client = TestClient::new(app);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
let res = client.get("/bar").await;
assert_eq!(res.status(), StatusCode::OK);
}
async fn all_the_uris(
uri: Uri,
OriginalUri(original_uri): OriginalUri,
req: Request,
) -> impl IntoResponse {
Json(json!({
"uri": uri.to_string(),
"request_uri": req.uri().to_string(),
"original_uri": original_uri.to_string(),
}))
}
#[crate::test]
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 client = TestClient::new(one.merge(two));
let res = client.get("/foo/bar").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/bar",
"request_uri": "/bar",
"original_uri": "/foo/bar",
})
);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/foo",
"request_uri": "/foo",
"original_uri": "/foo",
})
);
}
#[crate::test]
async fn nesting_and_seeing_the_right_uri_at_more_levels_of_nesting() {
let one = Router::new().nest(
"/foo/",
Router::new().nest("/bar", Router::new().route("/baz", get(all_the_uris))),
);
let two = Router::new().route("/foo", get(all_the_uris));
let client = TestClient::new(one.merge(two));
let res = client.get("/foo/bar/baz").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/baz",
"request_uri": "/baz",
"original_uri": "/foo/bar/baz",
})
);
let res = client.get("/foo").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/foo",
"request_uri": "/foo",
"original_uri": "/foo",
})
);
}
#[crate::test]
async fn nesting_and_seeing_the_right_uri_ors_with_nesting() {
let one = Router::new().nest(
"/one",
Router::new().nest("/bar", Router::new().route("/baz", get(all_the_uris))),
);
let two = Router::new().nest("/two", Router::new().route("/qux", get(all_the_uris)));
let three = Router::new().route("/three", get(all_the_uris));
let client = TestClient::new(one.merge(two).merge(three));
let res = client.get("/one/bar/baz").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/baz",
"request_uri": "/baz",
"original_uri": "/one/bar/baz",
})
);
let res = client.get("/two/qux").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/qux",
"request_uri": "/qux",
"original_uri": "/two/qux",
})
);
let res = client.get("/three").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/three",
"request_uri": "/three",
"original_uri": "/three",
})
);
}
#[crate::test]
async fn nesting_and_seeing_the_right_uri_ors_with_multi_segment_uris() {
let one = Router::new().nest(
"/one",
Router::new().nest("/foo", Router::new().route("/bar", get(all_the_uris))),
);
let two = Router::new().route("/two/foo", get(all_the_uris));
let client = TestClient::new(one.merge(two));
let res = client.get("/one/foo/bar").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/bar",
"request_uri": "/bar",
"original_uri": "/one/foo/bar",
})
);
let res = client.get("/two/foo").await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.json::<Value>().await,
json!({
"uri": "/two/foo",
"request_uri": "/two/foo",
"original_uri": "/two/foo",
})
);
}
#[allow(deprecated)]
#[crate::test]
async fn middleware_that_return_early() {
let private = Router::new()
.route("/", get(|| async {}))
.layer(ValidateRequestHeaderLayer::bearer("password"));
let public = Router::new().route("/public", get(|| async {}));
let client = TestClient::new(private.merge(public));
assert_eq!(client.get("/").await.status(), StatusCode::UNAUTHORIZED);
assert_eq!(
client
.get("/")
.header("authorization", "Bearer password")
.await
.status(),
StatusCode::OK
);
assert_eq!(
client.get("/doesnt-exist").await.status(),
StatusCode::NOT_FOUND
);
assert_eq!(client.get("/public").await.status(), StatusCode::OK);
}