| use super::*; |
| use crate::{error_handling::HandleErrorLayer, extract::OriginalUri, response::IntoResponse, Json}; |
| use serde_json::{json, Value}; |
| use tower::{limit::ConcurrencyLimitLayer, timeout::TimeoutLayer}; |
| |
| #[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").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/bar").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/baz").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/qux").send().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}")).send().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").send().await.text().await, "bar"); |
| assert_eq!(client.get("/baz").send().await.text().await, "baz"); |
| |
| let client = TestClient::new(Router::new().nest("/foo", bar_or_baz)); |
| assert_eq!(client.get("/foo/bar").send().await.text().await, "bar"); |
| assert_eq!(client.get("/foo/baz").send().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").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/two").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/three").send().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").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/bar").send().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( |
| ServiceBuilder::new() |
| .layer(HandleErrorLayer::new(|_| async { |
| StatusCode::REQUEST_TIMEOUT |
| })) |
| .layer(TimeoutLayer::new(Duration::from_millis(10))), |
| ); |
| let app = one.merge(two); |
| |
| let client = TestClient::new(app); |
| |
| let res = client.get("/timeout").send().await; |
| assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT); |
| } |
| |
| #[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").send().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").send().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}")).send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| } |
| |
| let res = client.get("/r8").send().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<Body>| async { |
| Ok::<_, Infallible>(Response::new(Body::empty())) |
| })), |
| ) |
| .merge(Router::new().route( |
| "/bar", |
| get_service(service_fn(|_: Request<Body>| async { |
| Ok::<_, Infallible>(Response::new(Body::empty())) |
| })), |
| )); |
| |
| let client = TestClient::new(app); |
| |
| let res = client.get("/foo").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| |
| let res = client.get("/bar").send().await; |
| assert_eq!(res.status(), StatusCode::OK); |
| } |
| |
| async fn all_the_uris( |
| uri: Uri, |
| OriginalUri(original_uri): OriginalUri, |
| req: Request<Body>, |
| ) -> 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").send().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").send().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").send().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").send().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").send().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").send().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").send().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").send().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").send().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", |
| }) |
| ); |
| } |
| |
| #[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("/").send().await.status(), |
| StatusCode::UNAUTHORIZED |
| ); |
| assert_eq!( |
| client |
| .get("/") |
| .header("authorization", "Bearer password") |
| .send() |
| .await |
| .status(), |
| StatusCode::OK |
| ); |
| assert_eq!( |
| client.get("/doesnt-exist").send().await.status(), |
| StatusCode::NOT_FOUND |
| ); |
| assert_eq!(client.get("/public").send().await.status(), StatusCode::OK); |
| } |