pythonasyncioapiasyncfastapiframeworkjsonjson-schemaopenapiopenapi3pydanticpython-typespython3redocreststarletteswaggerswagger-uiuvicornweb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
50 lines
1.3 KiB
50 lines
1.3 KiB
import sys
|
|
import threading
|
|
|
|
from fastapi import APIRouter, FastAPI
|
|
from fastapi.routing import _IncludedRouter
|
|
from fastapi.testclient import TestClient
|
|
|
|
N_ROUTES = 120
|
|
N_THREADS = 6
|
|
|
|
|
|
def build_app() -> FastAPI:
|
|
app = FastAPI()
|
|
router = APIRouter()
|
|
for i in range(N_ROUTES):
|
|
|
|
def endpoint(i: int = i) -> dict[str, int]:
|
|
return {"i": i}
|
|
|
|
router.add_api_route(f"/r{i}", endpoint, methods=["GET"])
|
|
app.include_router(router)
|
|
return app
|
|
|
|
|
|
def test_concurrent_first_requests_do_not_corrupt_candidate_cache() -> None:
|
|
app = build_app()
|
|
old_interval = sys.getswitchinterval()
|
|
sys.setswitchinterval(1e-5)
|
|
try:
|
|
barrier = threading.Barrier(N_THREADS)
|
|
statuses: list[int] = []
|
|
|
|
def worker() -> None:
|
|
client = TestClient(app)
|
|
barrier.wait()
|
|
statuses.append(client.get(f"/r{N_ROUTES - 1}").status_code)
|
|
|
|
threads = [threading.Thread(target=worker) for _ in range(N_THREADS)]
|
|
for thread in threads:
|
|
thread.start()
|
|
for thread in threads:
|
|
thread.join()
|
|
finally:
|
|
sys.setswitchinterval(old_interval)
|
|
|
|
assert statuses == [200] * N_THREADS
|
|
included = next(
|
|
route for route in app.router.routes if isinstance(route, _IncludedRouter)
|
|
)
|
|
assert len(included.effective_candidates()) == N_ROUTES
|
|
|