Skip to content

Commit a829bda

Browse files
authored
[serve] Improve test_root_path in test_fastapi.py (#60270)
## Description Update the `test_root_path` unit test in the `test_fastapi.py`. The new implementation is more descriptive in the expected values of the request urls, ASGI scope["root_path"], and scope["path"] for different root_path configurations provided via the app and serve layers. ## Related issues Relates to the PR #57555 --------- Signed-off-by: axreldable <aleksei.starikov.ax@gmail.com>
1 parent 424dc72 commit a829bda

File tree

1 file changed

+70
-18
lines changed

1 file changed

+70
-18
lines changed

python/ray/serve/tests/test_fastapi.py

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

12701322
if __name__ == "__main__":

0 commit comments

Comments
 (0)