7
7
import asyncio
8
8
from typing import List
9
9
from httpx import AsyncClient
10
+ from pydantic import BaseModel
10
11
from fastapi import FastAPI , APIRouter , Request
11
12
from fastapi .responses import JSONResponse
13
+ from fastapi .encoders import jsonable_encoder
12
14
from epsagon import trace_factory
13
15
from epsagon .common import ErrorCode
14
16
from epsagon .runners .fastapi import FastapiRunner
25
27
TEST_POST_DATA = {'post_test' : '123' }
26
28
CUSTOM_RESPONSE = ["A" ]
27
29
CUSTOM_RESPONSE_PATH = "/custom_response"
30
+ BASE_MODEL_RESPONSE_PATH = "/base_model_response"
31
+
32
+ class CustomBaseModel (BaseModel ):
33
+ data : List [str ]
28
34
29
35
def _get_response_data (key ):
30
36
return {key : key }
@@ -39,6 +45,9 @@ def handle():
39
45
def handle_custom_response (response_model = List [str ]):
40
46
return CUSTOM_RESPONSE
41
47
48
+ def handle_base_model_response (response_model = CustomBaseModel ):
49
+ return CustomBaseModel (data = CUSTOM_RESPONSE )
50
+
42
51
def handle_given_request (request : Request ):
43
52
assert request .method == 'POST'
44
53
loop = None
@@ -76,7 +85,16 @@ def handle_error():
76
85
def fastapi_app ():
77
86
app = FastAPI ()
78
87
app .add_api_route ("/" , handle , methods = ["GET" ])
79
- app .add_api_route (CUSTOM_RESPONSE_PATH , handle_custom_response , methods = ["GET" ])
88
+ app .add_api_route (
89
+ CUSTOM_RESPONSE_PATH ,
90
+ handle_custom_response ,
91
+ methods = ["GET" ]
92
+ )
93
+ app .add_api_route (
94
+ BASE_MODEL_RESPONSE_PATH ,
95
+ handle_base_model_response ,
96
+ methods = ["GET" ]
97
+ )
80
98
app .add_api_route (REQUEST_OBJ_PATH , handle_given_request , methods = ["POST" ])
81
99
app .add_api_route ("/a" , handle_a , methods = ["GET" ])
82
100
app .add_api_route ("/b" , handle_b , methods = ["GET" ])
@@ -119,11 +137,35 @@ async def test_fastapi_custom_response(trace_transport, fastapi_app):
119
137
assert runner .resource ['name' ].startswith ('127.0.0.1' )
120
138
assert runner .resource ['metadata' ]['Path' ] == CUSTOM_RESPONSE_PATH
121
139
assert runner .resource ['metadata' ]['Query Params' ] == { 'x' : 'testval' }
140
+ assert runner .resource ['metadata' ]['Response Data' ] == (
141
+ jsonable_encoder (CUSTOM_RESPONSE )
142
+ )
122
143
assert response_data == CUSTOM_RESPONSE
123
144
# validating no `zombie` traces exist
124
145
assert not trace_factory .traces
125
146
126
147
148
+ @pytest .mark .asyncio
149
+ async def test_fastapi_base_model_response (trace_transport , fastapi_app ):
150
+ """Sanity test."""
151
+ request_path = f'{ BASE_MODEL_RESPONSE_PATH } ?x=testval'
152
+ async with AsyncClient (app = fastapi_app , base_url = "http://test" ) as ac :
153
+ response = await ac .get (request_path )
154
+ response_data = response .json ()
155
+ runner = trace_transport .last_trace .events [0 ]
156
+ expected_response_data = CustomBaseModel (data = CUSTOM_RESPONSE )
157
+ assert isinstance (runner , FastapiRunner )
158
+ assert runner .resource ['name' ].startswith ('127.0.0.1' )
159
+ assert runner .resource ['metadata' ]['Path' ] == BASE_MODEL_RESPONSE_PATH
160
+ assert runner .resource ['metadata' ]['Query Params' ] == { 'x' : 'testval' }
161
+ assert runner .resource ['metadata' ]['Response Data' ] == (
162
+ jsonable_encoder (expected_response_data )
163
+ )
164
+ assert response_data == expected_response_data
165
+ # validating no `zombie` traces exist
166
+ assert not trace_factory .traces
167
+
168
+
127
169
@pytest .mark .asyncio
128
170
async def test_fastapi_given_request (trace_transport , fastapi_app ):
129
171
"""Sanity test."""
0 commit comments