use super::*; use futures_util::future::{pending, ready}; use tower::{timeout::TimeoutLayer, MakeService}; async fn unit() {} async fn forever() { pending().await } fn timeout() -> TimeoutLayer { TimeoutLayer::new(Duration::from_millis(10)) } #[derive(Clone)] struct Svc; impl Service for Svc { type Response = Response; type Error = hyper::Error; type Future = Ready>; fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, _req: R) -> Self::Future { ready(Ok(Response::new(Body::empty()))) } } fn check_make_svc(_make_svc: M) where M: MakeService<(), R, Response = T, Error = E>, { } fn handle_error(_: E) -> Result { Ok(StatusCode::INTERNAL_SERVER_ERROR) } #[tokio::test] async fn handler() { let app = Router::new().route( "/", get(forever .layer(timeout()) .handle_error(|_: BoxError| Ok::<_, Infallible>(StatusCode::REQUEST_TIMEOUT))), ); let addr = run_in_background(app).await; let client = reqwest::Client::new(); let res = client .get(format!("http://{}/", addr)) .send() .await .unwrap(); assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT); } #[tokio::test] async fn handler_multiple_methods_first() { let app = Router::new().route( "/", get(forever .layer(timeout()) .handle_error(|_: BoxError| Ok::<_, Infallible>(StatusCode::REQUEST_TIMEOUT))) .post(unit), ); let addr = run_in_background(app).await; let client = reqwest::Client::new(); let res = client .get(format!("http://{}/", addr)) .send() .await .unwrap(); assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT); } #[tokio::test] async fn handler_multiple_methods_middle() { let app = Router::new().route( "/", delete(unit) .get( forever .layer(timeout()) .handle_error(|_: BoxError| Ok::<_, Infallible>(StatusCode::REQUEST_TIMEOUT)), ) .post(unit), ); let addr = run_in_background(app).await; let client = reqwest::Client::new(); let res = client .get(format!("http://{}/", addr)) .send() .await .unwrap(); assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT); } #[tokio::test] async fn handler_multiple_methods_last() { let app = Router::new().route( "/", delete(unit).get( forever .layer(timeout()) .handle_error(|_: BoxError| Ok::<_, Infallible>(StatusCode::REQUEST_TIMEOUT)), ), ); let addr = run_in_background(app).await; let client = reqwest::Client::new(); let res = client .get(format!("http://{}/", addr)) .send() .await .unwrap(); assert_eq!(res.status(), StatusCode::REQUEST_TIMEOUT); } #[test] fn service_propagates_errors() { let app = Router::new().route::<_, Body>("/echo", service::post(Svc)); check_make_svc::<_, _, _, hyper::Error>(app.into_make_service()); } #[test] fn service_nested_propagates_errors() { let app = Router::new().route::<_, Body>("/echo", Router::new().nest("/foo", service::post(Svc))); check_make_svc::<_, _, _, hyper::Error>(app.into_make_service()); } #[test] fn service_handle_on_method() { let app = Router::new().route::<_, Body>( "/echo", service::get(Svc).handle_error(handle_error::), ); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[test] fn service_handle_on_method_multiple() { let app = Router::new().route::<_, Body>( "/echo", service::get(Svc) .post(Svc) .handle_error(handle_error::), ); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[test] fn service_handle_on_router() { let app = Router::new() .route::<_, Body>("/echo", service::get(Svc)) .handle_error(handle_error::); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[test] fn service_handle_on_router_still_impls_routing_dsl() { let app = Router::new() .route::<_, Body>("/echo", service::get(Svc)) .handle_error(handle_error::) .route("/", get(unit)); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[test] fn layered() { let app = Router::new() .route::<_, Body>("/echo", get(unit)) .layer(timeout()) .handle_error(handle_error::); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); } #[tokio::test] // async because of `.boxed()` async fn layered_boxed() { let app = Router::new() .route::<_, Body>("/echo", get(unit)) .layer(timeout()) .boxed() .handle_error(handle_error::); check_make_svc::<_, _, _, Infallible>(app.into_make_service()); }