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