@@ -1225,30 +1225,49 @@ def direct_endpoint(self):
12251225
12261226
12271227@pytest .mark .parametrize (
1228- "app_root_path,serve_root_path" ,
1228+ "app_root_path,serve_root_path,expected_params_1,expected_params_2 " ,
12291229 [
1230- ("" , "" ), # http://127.0.0.1:8000/ hello, request.scope["root_path"] == ""
1230+ ("" , "" , [ "/ hello" , "" , "/hello" ], []),
12311231 (
12321232 "/app_root_path" ,
12331233 "" ,
1234- ), # http://127.0.0.1:8000/hello, request.scope["root_path"] == "/app_root_path"
1234+ ["/hello" , "/app_root_path" , "/hello" ],
1235+ ["/app_root_path/hello" , "/app_root_path" , "/app_root_path/hello" ],
1236+ ),
12351237 (
12361238 "" ,
12371239 "/serve_root_path" ,
1238- ), # http://127.0.0.1:8000/serve_root_path/hello, request.scope["root_path"] == "/serve_root_path"
1239- # ("/app_root_path", "/serve_root_path"), # doesn't work for uvicorn versions before and after `0.26.0`
1240- (
1241- "/root_path" ,
1242- "/root_path" ,
1243- ), # http://127.0.0.1:8000/root_path/hello, request.scope["root_path"] == "/root_path"
1240+ ["/hello" , "/serve_root_path" , "/serve_root_path/hello" ],
1241+ [],
1242+ ),
1243+ ("/app_root_path" , "/serve_root_path" , [], []),
1244+ ("/root_path" , "/root_path" , ["/hello" , "/root_path" , "/root_path/hello" ], []),
12441245 ],
12451246)
1246- def test_root_path (ray_shutdown , app_root_path , serve_root_path ):
1247+ def test_root_path (
1248+ ray_shutdown , app_root_path , serve_root_path , expected_params_1 , expected_params_2
1249+ ):
1250+ """
1251+ The test works across uvicorn versions (before and after uvicorn 0.26.0 version which introduces breaking changes for the scope root_path).
1252+
1253+ Reference: https://github.com/Kludex/uvicorn/pull/2213
1254+
1255+ | Case | `app_root_path` | `serve_root_path` | Expected Working URL #1 (suffix) | `root_path` (req.scope) | `path` (req.scope) | Expected Working URL #2 (suffix) | `root_path` #2 | `path` #2 |
1256+ | ---: | ---------------- | ------------------ | -------------------------------- | ----------------------- | ------------------------ | -------------------------------- | ---------------- | ---------------------- |
1257+ | 1 | `""` | `""` | `/hello` | `""` | `/hello` | — | — | — |
1258+ | 2 | `/app_root_path` | `""` | `/hello` | `/app_root_path` | `/hello` | `/app_root_path/hello` | `/app_root_path` | `/app_root_path/hello` |
1259+ | 3 | `""` | `/serve_root_path` | `/hello` | `/serve_root_path` | `/serve_root_path/hello` | — | — | — |
1260+ | 4 | `/app_root_path` | `/serve_root_path` | *(none)* | — | — | — | — | — |
1261+ | 5 | `/root_path` | `/root_path` | `/hello` | `/root_path` | `/root_path/hello` | — | — | — |
1262+ """
12471263 app = FastAPI (root_path = app_root_path )
12481264
12491265 @app .get ("/hello" )
12501266 def func (request : Request ):
1251- return {"hello" : request .scope .get ("root_path" )}
1267+ return {
1268+ "root_path" : request .scope .get ("root_path" ),
1269+ "path" : request .scope .get ("path" ),
1270+ }
12521271
12531272 @serve .deployment
12541273 @serve .ingress (app )
@@ -1258,13 +1277,46 @@ class App:
12581277 serve .start (http_options = {"root_path" : serve_root_path })
12591278 serve .run (App .bind ())
12601279
1261- url = get_application_url ("HTTP" )
1262- if serve_root_path != "" :
1263- url += serve_root_path
1264- url += "/hello"
1265- resp = httpx .get (url )
1266- scope_root_path = app_root_path or serve_root_path
1267- assert resp .json () == {"hello" : scope_root_path }
1280+ base = get_application_url ("HTTP" )
1281+ test_urls = [
1282+ f"{ base } /hello" ,
1283+ f"{ base } { app_root_path } /hello" ,
1284+ f"{ base } { serve_root_path } /hello" ,
1285+ f"{ base } { app_root_path } { serve_root_path } /hello" ,
1286+ f"{ base } { serve_root_path } { app_root_path } /hello" ,
1287+ f"{ base } { app_root_path } { app_root_path } /hello" ,
1288+ f"{ base } { serve_root_path } { serve_root_path } /hello" ,
1289+ ]
1290+
1291+ tested = set ()
1292+ working_url_params = []
1293+ for test_url in test_urls :
1294+ if test_url not in tested :
1295+ response = httpx .get (test_url )
1296+ if response .status_code == 200 :
1297+ body = response .json ()
1298+ params = {}
1299+ params ["url" ] = test_url
1300+ params ["root_path" ] = body ["root_path" ]
1301+ params ["path" ] = body ["path" ]
1302+ working_url_params .append (params )
1303+ tested .add (test_url )
1304+ if expected_params_1 :
1305+ assert (
1306+ len (working_url_params ) > 0
1307+ ), "working urls array is expected to have at least 1 item!"
1308+ assert working_url_params [0 ]["url" ].endswith (expected_params_1 [0 ])
1309+ assert working_url_params [0 ]["root_path" ] == expected_params_1 [1 ]
1310+ assert working_url_params [0 ]["path" ] == expected_params_1 [2 ]
1311+ if expected_params_2 :
1312+ assert (
1313+ len (working_url_params ) > 1
1314+ ), "working urls array is expected to have at least 2 items!"
1315+ assert working_url_params [1 ]["url" ].endswith (expected_params_2 [0 ])
1316+ assert working_url_params [1 ]["root_path" ] == expected_params_2 [1 ]
1317+ assert working_url_params [1 ]["path" ] == expected_params_2 [2 ]
1318+ else :
1319+ assert len (working_url_params ) == 0
12681320
12691321
12701322if __name__ == "__main__" :
0 commit comments