1 use tower::ServiceExt;
2 
3 use super::*;
4 use crate::middleware::{map_request, map_response};
5 
6 #[crate::test]
basic()7 async fn basic() {
8     let app = Router::new()
9         .route("/foo", get(|| async {}))
10         .fallback(|| async { "fallback" });
11 
12     let client = TestClient::new(app);
13 
14     assert_eq!(client.get("/foo").send().await.status(), StatusCode::OK);
15 
16     let res = client.get("/does-not-exist").send().await;
17     assert_eq!(res.status(), StatusCode::OK);
18     assert_eq!(res.text().await, "fallback");
19 }
20 
21 #[crate::test]
nest()22 async fn nest() {
23     let app = Router::new()
24         .nest("/foo", Router::new().route("/bar", get(|| async {})))
25         .fallback(|| async { "fallback" });
26 
27     let client = TestClient::new(app);
28 
29     assert_eq!(client.get("/foo/bar").send().await.status(), StatusCode::OK);
30 
31     let res = client.get("/does-not-exist").send().await;
32     assert_eq!(res.status(), StatusCode::OK);
33     assert_eq!(res.text().await, "fallback");
34 }
35 
36 #[crate::test]
or()37 async fn or() {
38     let one = Router::new().route("/one", get(|| async {}));
39     let two = Router::new().route("/two", get(|| async {}));
40 
41     let app = one.merge(two).fallback(|| async { "fallback" });
42 
43     let client = TestClient::new(app);
44 
45     assert_eq!(client.get("/one").send().await.status(), StatusCode::OK);
46     assert_eq!(client.get("/two").send().await.status(), StatusCode::OK);
47 
48     let res = client.get("/does-not-exist").send().await;
49     assert_eq!(res.status(), StatusCode::OK);
50     assert_eq!(res.text().await, "fallback");
51 }
52 
53 #[crate::test]
fallback_accessing_state()54 async fn fallback_accessing_state() {
55     let app = Router::new()
56         .fallback(|State(state): State<&'static str>| async move { state })
57         .with_state("state");
58 
59     let client = TestClient::new(app);
60 
61     let res = client.get("/does-not-exist").send().await;
62     assert_eq!(res.status(), StatusCode::OK);
63     assert_eq!(res.text().await, "state");
64 }
65 
inner_fallback() -> impl IntoResponse66 async fn inner_fallback() -> impl IntoResponse {
67     (StatusCode::NOT_FOUND, "inner")
68 }
69 
outer_fallback() -> impl IntoResponse70 async fn outer_fallback() -> impl IntoResponse {
71     (StatusCode::NOT_FOUND, "outer")
72 }
73 
74 #[crate::test]
nested_router_inherits_fallback()75 async fn nested_router_inherits_fallback() {
76     let inner = Router::new();
77     let app = Router::new().nest("/foo", inner).fallback(outer_fallback);
78 
79     let client = TestClient::new(app);
80 
81     let res = client.get("/foo/bar").send().await;
82     assert_eq!(res.status(), StatusCode::NOT_FOUND);
83     assert_eq!(res.text().await, "outer");
84 }
85 
86 #[crate::test]
doesnt_inherit_fallback_if_overriden()87 async fn doesnt_inherit_fallback_if_overriden() {
88     let inner = Router::new().fallback(inner_fallback);
89     let app = Router::new().nest("/foo", inner).fallback(outer_fallback);
90 
91     let client = TestClient::new(app);
92 
93     let res = client.get("/foo/bar").send().await;
94     assert_eq!(res.status(), StatusCode::NOT_FOUND);
95     assert_eq!(res.text().await, "inner");
96 
97     let res = client.get("/").send().await;
98     assert_eq!(res.status(), StatusCode::NOT_FOUND);
99     assert_eq!(res.text().await, "outer");
100 }
101 
102 #[crate::test]
deeply_nested_inherit_from_top()103 async fn deeply_nested_inherit_from_top() {
104     let app = Router::new()
105         .nest("/foo", Router::new().nest("/bar", Router::new()))
106         .fallback(outer_fallback);
107 
108     let client = TestClient::new(app);
109 
110     let res = client.get("/foo/bar/baz").send().await;
111     assert_eq!(res.status(), StatusCode::NOT_FOUND);
112     assert_eq!(res.text().await, "outer");
113 }
114 
115 #[crate::test]
deeply_nested_inherit_from_middle()116 async fn deeply_nested_inherit_from_middle() {
117     let app = Router::new().nest(
118         "/foo",
119         Router::new()
120             .nest("/bar", Router::new())
121             .fallback(outer_fallback),
122     );
123 
124     let client = TestClient::new(app);
125 
126     let res = client.get("/foo/bar/baz").send().await;
127     assert_eq!(res.status(), StatusCode::NOT_FOUND);
128     assert_eq!(res.text().await, "outer");
129 }
130 
131 #[crate::test]
with_middleware_on_inner_fallback()132 async fn with_middleware_on_inner_fallback() {
133     async fn never_called<B>(_: Request<B>) -> Request<B> {
134         panic!("should never be called")
135     }
136 
137     let inner = Router::new().layer(map_request(never_called));
138     let app = Router::new().nest("/foo", inner).fallback(outer_fallback);
139 
140     let client = TestClient::new(app);
141 
142     let res = client.get("/foo/bar").send().await;
143     assert_eq!(res.status(), StatusCode::NOT_FOUND);
144     assert_eq!(res.text().await, "outer");
145 }
146 
147 #[crate::test]
also_inherits_default_layered_fallback()148 async fn also_inherits_default_layered_fallback() {
149     async fn set_header<B>(mut res: Response<B>) -> Response<B> {
150         res.headers_mut()
151             .insert("x-from-fallback", "1".parse().unwrap());
152         res
153     }
154 
155     let inner = Router::new();
156     let app = Router::new()
157         .nest("/foo", inner)
158         .fallback(outer_fallback)
159         .layer(map_response(set_header));
160 
161     let client = TestClient::new(app);
162 
163     let res = client.get("/foo/bar").send().await;
164     assert_eq!(res.status(), StatusCode::NOT_FOUND);
165     assert_eq!(res.headers()["x-from-fallback"], "1");
166     assert_eq!(res.text().await, "outer");
167 }
168 
169 #[crate::test]
fallback_inherited_into_nested_router_service()170 async fn fallback_inherited_into_nested_router_service() {
171     let inner = Router::new()
172         .route(
173             "/bar",
174             get(|State(state): State<&'static str>| async move { state }),
175         )
176         .with_state("inner");
177 
178     // with a different state
179     let app = Router::<()>::new()
180         .nest_service("/foo", inner)
181         .fallback(outer_fallback);
182 
183     let client = TestClient::new(app);
184     let res = client.get("/foo/not-found").send().await;
185     assert_eq!(res.status(), StatusCode::NOT_FOUND);
186     assert_eq!(res.text().await, "outer");
187 }
188 
189 #[crate::test]
fallback_inherited_into_nested_opaque_service()190 async fn fallback_inherited_into_nested_opaque_service() {
191     let inner = Router::new()
192         .route(
193             "/bar",
194             get(|State(state): State<&'static str>| async move { state }),
195         )
196         .with_state("inner")
197         // even if the service is made more opaque it should still inherit the fallback
198         .boxed_clone();
199 
200     // with a different state
201     let app = Router::<()>::new()
202         .nest_service("/foo", inner)
203         .fallback(outer_fallback);
204 
205     let client = TestClient::new(app);
206     let res = client.get("/foo/not-found").send().await;
207     assert_eq!(res.status(), StatusCode::NOT_FOUND);
208     assert_eq!(res.text().await, "outer");
209 }
210 
211 #[crate::test]
nest_fallback_on_inner()212 async fn nest_fallback_on_inner() {
213     let app = Router::new()
214         .nest(
215             "/foo",
216             Router::new()
217                 .route("/", get(|| async {}))
218                 .fallback(|| async { (StatusCode::NOT_FOUND, "inner fallback") }),
219         )
220         .fallback(|| async { (StatusCode::NOT_FOUND, "outer fallback") });
221 
222     let client = TestClient::new(app);
223 
224     let res = client.get("/foo/not-found").send().await;
225     assert_eq!(res.status(), StatusCode::NOT_FOUND);
226     assert_eq!(res.text().await, "inner fallback");
227 }
228 
229 // https://github.com/tokio-rs/axum/issues/1931
230 #[crate::test]
doesnt_panic_if_used_with_nested_router()231 async fn doesnt_panic_if_used_with_nested_router() {
232     async fn handler() {}
233 
234     let routes_static =
235         Router::new().nest_service("/", crate::routing::get_service(handler.into_service()));
236 
237     let routes_all = Router::new().fallback_service(routes_static);
238 
239     let client = TestClient::new(routes_all);
240 
241     let res = client.get("/foobar").send().await;
242     assert_eq!(res.status(), StatusCode::OK);
243 }
244 
245 #[crate::test]
issue_2072()246 async fn issue_2072() {
247     let nested_routes = Router::new().fallback(inner_fallback);
248 
249     let app = Router::new()
250         .nest("/nested", nested_routes)
251         .merge(Router::new());
252 
253     let client = TestClient::new(app);
254 
255     let res = client.get("/nested/does-not-exist").send().await;
256     assert_eq!(res.status(), StatusCode::NOT_FOUND);
257     assert_eq!(res.text().await, "inner");
258 
259     let res = client.get("/does-not-exist").send().await;
260     assert_eq!(res.status(), StatusCode::NOT_FOUND);
261     assert_eq!(res.text().await, "");
262 }
263 
264 #[crate::test]
issue_2072_outer_fallback_before_merge()265 async fn issue_2072_outer_fallback_before_merge() {
266     let nested_routes = Router::new().fallback(inner_fallback);
267 
268     let app = Router::new()
269         .nest("/nested", nested_routes)
270         .fallback(outer_fallback)
271         .merge(Router::new());
272 
273     let client = TestClient::new(app);
274 
275     let res = client.get("/nested/does-not-exist").send().await;
276     assert_eq!(res.status(), StatusCode::NOT_FOUND);
277     assert_eq!(res.text().await, "inner");
278 
279     let res = client.get("/does-not-exist").send().await;
280     assert_eq!(res.status(), StatusCode::NOT_FOUND);
281     assert_eq!(res.text().await, "outer");
282 }
283 
284 #[crate::test]
issue_2072_outer_fallback_after_merge()285 async fn issue_2072_outer_fallback_after_merge() {
286     let nested_routes = Router::new().fallback(inner_fallback);
287 
288     let app = Router::new()
289         .nest("/nested", nested_routes)
290         .merge(Router::new())
291         .fallback(outer_fallback);
292 
293     let client = TestClient::new(app);
294 
295     let res = client.get("/nested/does-not-exist").send().await;
296     assert_eq!(res.status(), StatusCode::NOT_FOUND);
297     assert_eq!(res.text().await, "inner");
298 
299     let res = client.get("/does-not-exist").send().await;
300     assert_eq!(res.status(), StatusCode::NOT_FOUND);
301     assert_eq!(res.text().await, "outer");
302 }
303 
304 #[crate::test]
merge_router_with_fallback_into_nested_router_with_fallback()305 async fn merge_router_with_fallback_into_nested_router_with_fallback() {
306     let nested_routes = Router::new().fallback(inner_fallback);
307 
308     let app = Router::new()
309         .nest("/nested", nested_routes)
310         .merge(Router::new().fallback(outer_fallback));
311 
312     let client = TestClient::new(app);
313 
314     let res = client.get("/nested/does-not-exist").send().await;
315     assert_eq!(res.status(), StatusCode::NOT_FOUND);
316     assert_eq!(res.text().await, "inner");
317 
318     let res = client.get("/does-not-exist").send().await;
319     assert_eq!(res.status(), StatusCode::NOT_FOUND);
320     assert_eq!(res.text().await, "outer");
321 }
322 
323 #[crate::test]
merging_nested_router_with_fallback_into_router_with_fallback()324 async fn merging_nested_router_with_fallback_into_router_with_fallback() {
325     let nested_routes = Router::new().fallback(inner_fallback);
326 
327     let app = Router::new()
328         .fallback(outer_fallback)
329         .merge(Router::new().nest("/nested", nested_routes));
330 
331     let client = TestClient::new(app);
332 
333     let res = client.get("/nested/does-not-exist").send().await;
334     assert_eq!(res.status(), StatusCode::NOT_FOUND);
335     assert_eq!(res.text().await, "inner");
336 
337     let res = client.get("/does-not-exist").send().await;
338     assert_eq!(res.status(), StatusCode::NOT_FOUND);
339     assert_eq!(res.text().await, "outer");
340 }
341 
342 #[crate::test]
merge_empty_into_router_with_fallback()343 async fn merge_empty_into_router_with_fallback() {
344     let app = Router::new().fallback(outer_fallback).merge(Router::new());
345 
346     let client = TestClient::new(app);
347 
348     let res = client.get("/does-not-exist").send().await;
349     assert_eq!(res.status(), StatusCode::NOT_FOUND);
350     assert_eq!(res.text().await, "outer");
351 }
352 
353 #[crate::test]
merge_router_with_fallback_into_empty()354 async fn merge_router_with_fallback_into_empty() {
355     let app = Router::new().merge(Router::new().fallback(outer_fallback));
356 
357     let client = TestClient::new(app);
358 
359     let res = client.get("/does-not-exist").send().await;
360     assert_eq!(res.status(), StatusCode::NOT_FOUND);
361     assert_eq!(res.text().await, "outer");
362 }
363