|
9 | 9 | from httpx import AsyncClient |
10 | 10 | from pydantic import BaseModel |
11 | 11 | from fastapi import FastAPI, APIRouter, Request |
| 12 | +from fastapi.routing import APIRoute |
12 | 13 | from fastapi.responses import JSONResponse |
13 | 14 | from fastapi.encoders import jsonable_encoder |
14 | 15 | from epsagon import trace_factory |
|
22 | 23 |
|
23 | 24 | RETURN_VALUE = 'testresponsedata' |
24 | 25 | ROUTER_RETURN_VALUE = 'router-endpoint-return-data' |
| 26 | +CUSTOM_ROUTE_RETURN_VALUE = 'custom-route-endpoint-return-data' |
25 | 27 | REQUEST_OBJ_PATH = '/given_request' |
26 | 28 | TEST_ROUTER_PREFIX = '/test-router-path' |
27 | 29 | TEST_ROUTER_PATH = '/test-router' |
| 30 | +TEST_CUSTOM_ROUTE_PATH = '/atest-custom-route' |
| 31 | +TEST_CUSTOM_ROUTE_PREFIX = '/test-custom-route-main' |
28 | 32 | MULTIPLE_THREADS_KEY = "multiple_threads" |
29 | 33 | MULTIPLE_THREADS_ROUTE = f'/{MULTIPLE_THREADS_KEY}' |
30 | 34 | MULTIPLE_THREADS_RETURN_VALUE = MULTIPLE_THREADS_KEY |
|
44 | 48 | class CustomBaseModel(BaseModel): |
45 | 49 | data: List[str] |
46 | 50 |
|
| 51 | +class CustomRouteClass(APIRoute): |
| 52 | + pass |
| 53 | + |
47 | 54 | def _get_response_data(key): |
48 | 55 | return {key: key} |
49 | 56 |
|
@@ -87,6 +94,9 @@ def handle_b(): |
87 | 94 | def handle_router_endpoint(): |
88 | 95 | return _get_response(ROUTER_RETURN_VALUE) |
89 | 96 |
|
| 97 | +def handle_custom_route_endpoint(): |
| 98 | + return _get_response(CUSTOM_ROUTE_RETURN_VALUE) |
| 99 | + |
90 | 100 | def multiple_threads_route(): |
91 | 101 | multiple_threads_handler() |
92 | 102 | return _get_response(MULTIPLE_THREADS_RETURN_VALUE) |
@@ -162,6 +172,9 @@ def _build_fastapi_app(): |
162 | 172 | router = APIRouter() |
163 | 173 | router.add_api_route(TEST_ROUTER_PATH, handle_router_endpoint) |
164 | 174 | app.include_router(router, prefix=TEST_ROUTER_PREFIX) |
| 175 | + router_with_custom_route = APIRouter(route_class=CustomRouteClass) |
| 176 | + router_with_custom_route.add_api_route(TEST_CUSTOM_ROUTE_PATH, handle_custom_route_endpoint) |
| 177 | + app.include_router(router_with_custom_route, prefix=TEST_CUSTOM_ROUTE_PREFIX) |
165 | 178 | return app |
166 | 179 |
|
167 | 180 | @pytest.fixture(scope='function', autouse=False) |
@@ -343,6 +356,25 @@ async def test_fastapi_custom_router(trace_transport, fastapi_app): |
343 | 356 | assert response_data == expected_response_data |
344 | 357 |
|
345 | 358 |
|
| 359 | +@pytest.mark.asyncio |
| 360 | +async def test_fastapi_custom_api_route(trace_transport, fastapi_app): |
| 361 | + """Custom api route sanity test.""" |
| 362 | + full_route_path= f'{TEST_CUSTOM_ROUTE_PREFIX}{TEST_CUSTOM_ROUTE_PATH}' |
| 363 | + async with AsyncClient(app=fastapi_app, base_url="http://test") as ac: |
| 364 | + response = await ac.get(full_route_path) |
| 365 | + response_data = response.json() |
| 366 | + runner = trace_transport.last_trace.events[0] |
| 367 | + assert isinstance(runner, FastapiRunner) |
| 368 | + assert runner.resource['name'].startswith('127.0.0.1') |
| 369 | + assert runner.resource['metadata']['Path'] == full_route_path |
| 370 | + assert runner.resource['metadata']['status_code'] == DEFAULT_SUCCESS_STATUS_CODE |
| 371 | + expected_response_data = _get_response_data(CUSTOM_ROUTE_RETURN_VALUE) |
| 372 | + assert runner.resource['metadata']['Response Data'] == ( |
| 373 | + expected_response_data |
| 374 | + ) |
| 375 | + assert response_data == expected_response_data |
| 376 | + |
| 377 | + |
346 | 378 | @pytest.mark.asyncio |
347 | 379 | async def test_fastapi_exception(trace_transport, fastapi_app): |
348 | 380 | """Test when the handler raises an exception.""" |
|
0 commit comments