Coverage for tests/test_dependency_contextmanager.py: 100%
271 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-08 03:53 +0000
1import json 1abcde
2from typing import Dict 1abcde
4import pytest 1abcde
5from fastapi import BackgroundTasks, Depends, FastAPI 1abcde
6from fastapi.responses import StreamingResponse 1abcde
7from fastapi.testclient import TestClient 1abcde
9app = FastAPI() 1abcde
10state = { 1abcde
11 "/async": "asyncgen not started",
12 "/sync": "generator not started",
13 "/async_raise": "asyncgen raise not started",
14 "/sync_raise": "generator raise not started",
15 "context_a": "not started a",
16 "context_b": "not started b",
17 "bg": "not set",
18 "sync_bg": "not set",
19}
21errors = [] 1abcde
24async def get_state(): 1abcde
25 return state 1abcde
28class AsyncDependencyError(Exception): 1abcde
29 pass 1abcde
32class SyncDependencyError(Exception): 1abcde
33 pass 1abcde
36class OtherDependencyError(Exception): 1abcde
37 pass 1abcde
40async def asyncgen_state(state: Dict[str, str] = Depends(get_state)): 1abcde
41 state["/async"] = "asyncgen started" 1abcde
42 yield state["/async"] 1abcde
43 state["/async"] = "asyncgen completed" 1abcde
46def generator_state(state: Dict[str, str] = Depends(get_state)): 1abcde
47 state["/sync"] = "generator started" 1abcde
48 yield state["/sync"] 1abcde
49 state["/sync"] = "generator completed" 1abcde
52async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)): 1abcde
53 state["/async_raise"] = "asyncgen raise started" 1abcde
54 try: 1abcde
55 yield state["/async_raise"] 1abcde
56 except AsyncDependencyError: 1abcde
57 errors.append("/async_raise") 1abcde
58 raise 1abcde
59 finally:
60 state["/async_raise"] = "asyncgen raise finalized" 1abcde
63def generator_state_try(state: Dict[str, str] = Depends(get_state)): 1abcde
64 state["/sync_raise"] = "generator raise started" 1abcde
65 try: 1abcde
66 yield state["/sync_raise"] 1abcde
67 except SyncDependencyError: 1abcde
68 errors.append("/sync_raise") 1abcde
69 raise 1abcde
70 finally:
71 state["/sync_raise"] = "generator raise finalized" 1abcde
74async def context_a(state: dict = Depends(get_state)): 1abcde
75 state["context_a"] = "started a" 1abcde
76 try: 1abcde
77 yield state 1abcde
78 finally:
79 state["context_a"] = "finished a" 1abcde
82async def context_b(state: dict = Depends(context_a)): 1abcde
83 state["context_b"] = "started b" 1abcde
84 try: 1abcde
85 yield state 1abcde
86 finally:
87 state["context_b"] = f"finished b with a: {state['context_a']}" 1abcde
90@app.get("/async") 1abcde
91async def get_async(state: str = Depends(asyncgen_state)): 1abcde
92 return state 1abcde
95@app.get("/sync") 1abcde
96async def get_sync(state: str = Depends(generator_state)): 1abcde
97 return state 1abcde
100@app.get("/async_raise") 1abcde
101async def get_async_raise(state: str = Depends(asyncgen_state_try)): 1abcde
102 assert state == "asyncgen raise started" 1abcde
103 raise AsyncDependencyError() 1abcde
106@app.get("/sync_raise") 1abcde
107async def get_sync_raise(state: str = Depends(generator_state_try)): 1abcde
108 assert state == "generator raise started" 1abcde
109 raise SyncDependencyError() 1abcde
112@app.get("/async_raise_other") 1abcde
113async def get_async_raise_other(state: str = Depends(asyncgen_state_try)): 1abcde
114 assert state == "asyncgen raise started" 1abcde
115 raise OtherDependencyError() 1abcde
118@app.get("/sync_raise_other") 1abcde
119async def get_sync_raise_other(state: str = Depends(generator_state_try)): 1abcde
120 assert state == "generator raise started" 1abcde
121 raise OtherDependencyError() 1abcde
124@app.get("/context_b") 1abcde
125async def get_context_b(state: dict = Depends(context_b)): 1abcde
126 return state 1abcde
129@app.get("/context_b_raise") 1abcde
130async def get_context_b_raise(state: dict = Depends(context_b)): 1abcde
131 assert state["context_b"] == "started b" 1abcde
132 assert state["context_a"] == "started a" 1abcde
133 raise OtherDependencyError() 1abcde
136@app.get("/context_b_bg") 1abcde
137async def get_context_b_bg(tasks: BackgroundTasks, state: dict = Depends(context_b)): 1abcde
138 async def bg(state: dict): 1abcde
139 state["bg"] = f"bg set - b: {state['context_b']} - a: {state['context_a']}" 1abcde
141 tasks.add_task(bg, state) 1abcde
142 return state 1abcde
145# Sync versions
148@app.get("/sync_async") 1abcde
149def get_sync_async(state: str = Depends(asyncgen_state)): 1abcde
150 return state 1abcde
153@app.get("/sync_sync") 1abcde
154def get_sync_sync(state: str = Depends(generator_state)): 1abcde
155 return state 1abcde
158@app.get("/sync_async_raise") 1abcde
159def get_sync_async_raise(state: str = Depends(asyncgen_state_try)): 1abcde
160 assert state == "asyncgen raise started" 1abcde
161 raise AsyncDependencyError() 1abcde
164@app.get("/sync_sync_raise") 1abcde
165def get_sync_sync_raise(state: str = Depends(generator_state_try)): 1abcde
166 assert state == "generator raise started" 1abcde
167 raise SyncDependencyError() 1abcde
170@app.get("/sync_async_raise_other") 1abcde
171def get_sync_async_raise_other(state: str = Depends(asyncgen_state_try)): 1abcde
172 assert state == "asyncgen raise started" 1abcde
173 raise OtherDependencyError() 1abcde
176@app.get("/sync_sync_raise_other") 1abcde
177def get_sync_sync_raise_other(state: str = Depends(generator_state_try)): 1abcde
178 assert state == "generator raise started" 1abcde
179 raise OtherDependencyError() 1abcde
182@app.get("/sync_context_b") 1abcde
183def get_sync_context_b(state: dict = Depends(context_b)): 1abcde
184 return state 1abcde
187@app.get("/sync_context_b_raise") 1abcde
188def get_sync_context_b_raise(state: dict = Depends(context_b)): 1abcde
189 assert state["context_b"] == "started b" 1abcde
190 assert state["context_a"] == "started a" 1abcde
191 raise OtherDependencyError() 1abcde
194@app.get("/sync_context_b_bg") 1abcde
195async def get_sync_context_b_bg( 1abcde
196 tasks: BackgroundTasks, state: dict = Depends(context_b)
197):
198 async def bg(state: dict): 1abcde
199 state[ 1abcde
200 "sync_bg"
201 ] = f"sync_bg set - b: {state['context_b']} - a: {state['context_a']}"
203 tasks.add_task(bg, state) 1abcde
204 return state 1abcde
207@app.middleware("http") 1abcde
208async def middleware(request, call_next): 1abcde
209 response: StreamingResponse = await call_next(request) 1abcde
210 response.headers["x-state"] = json.dumps(state.copy()) 1abcde
211 return response 1abcde
214client = TestClient(app) 1abcde
217def test_async_state(): 1abcde
218 assert state["/async"] == "asyncgen not started" 1abcde
219 response = client.get("/async") 1abcde
220 assert response.status_code == 200, response.text 1abcde
221 assert response.json() == "asyncgen started" 1abcde
222 assert state["/async"] == "asyncgen completed" 1abcde
225def test_sync_state(): 1abcde
226 assert state["/sync"] == "generator not started" 1abcde
227 response = client.get("/sync") 1abcde
228 assert response.status_code == 200, response.text 1abcde
229 assert response.json() == "generator started" 1abcde
230 assert state["/sync"] == "generator completed" 1abcde
233def test_async_raise_other(): 1abcde
234 assert state["/async_raise"] == "asyncgen raise not started" 1abcde
235 with pytest.raises(OtherDependencyError): 1abcde
236 client.get("/async_raise_other") 1abcde
237 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
238 assert "/async_raise" not in errors 1abcde
241def test_sync_raise_other(): 1abcde
242 assert state["/sync_raise"] == "generator raise not started" 1abcde
243 with pytest.raises(OtherDependencyError): 1abcde
244 client.get("/sync_raise_other") 1abcde
245 assert state["/sync_raise"] == "generator raise finalized" 1abcde
246 assert "/sync_raise" not in errors 1abcde
249def test_async_raise_raises(): 1abcde
250 with pytest.raises(AsyncDependencyError): 1abcde
251 client.get("/async_raise") 1abcde
252 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
253 assert "/async_raise" in errors 1abcde
254 errors.clear() 1abcde
257def test_async_raise_server_error(): 1abcde
258 client = TestClient(app, raise_server_exceptions=False) 1abcde
259 response = client.get("/async_raise") 1abcde
260 assert response.status_code == 500, response.text 1abcde
261 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
262 assert "/async_raise" in errors 1abcde
263 errors.clear() 1abcde
266def test_context_b(): 1abcde
267 response = client.get("/context_b") 1abcde
268 data = response.json() 1abcde
269 assert data["context_b"] == "started b" 1abcde
270 assert data["context_a"] == "started a" 1abcde
271 assert state["context_b"] == "finished b with a: started a" 1abcde
272 assert state["context_a"] == "finished a" 1abcde
275def test_context_b_raise(): 1abcde
276 with pytest.raises(OtherDependencyError): 1abcde
277 client.get("/context_b_raise") 1abcde
278 assert state["context_b"] == "finished b with a: started a" 1abcde
279 assert state["context_a"] == "finished a" 1abcde
282def test_background_tasks(): 1abcde
283 response = client.get("/context_b_bg") 1abcde
284 data = response.json() 1abcde
285 assert data["context_b"] == "started b" 1abcde
286 assert data["context_a"] == "started a" 1abcde
287 assert data["bg"] == "not set" 1abcde
288 middleware_state = json.loads(response.headers["x-state"]) 1abcde
289 assert middleware_state["context_b"] == "finished b with a: started a" 1abcde
290 assert middleware_state["context_a"] == "finished a" 1abcde
291 assert middleware_state["bg"] == "not set" 1abcde
292 assert state["context_b"] == "finished b with a: started a" 1abcde
293 assert state["context_a"] == "finished a" 1abcde
294 assert state["bg"] == "bg set - b: finished b with a: started a - a: finished a" 1abcde
297def test_sync_raise_raises(): 1abcde
298 with pytest.raises(SyncDependencyError): 1abcde
299 client.get("/sync_raise") 1abcde
300 assert state["/sync_raise"] == "generator raise finalized" 1abcde
301 assert "/sync_raise" in errors 1abcde
302 errors.clear() 1abcde
305def test_sync_raise_server_error(): 1abcde
306 client = TestClient(app, raise_server_exceptions=False) 1abcde
307 response = client.get("/sync_raise") 1abcde
308 assert response.status_code == 500, response.text 1abcde
309 assert state["/sync_raise"] == "generator raise finalized" 1abcde
310 assert "/sync_raise" in errors 1abcde
311 errors.clear() 1abcde
314def test_sync_async_state(): 1abcde
315 response = client.get("/sync_async") 1abcde
316 assert response.status_code == 200, response.text 1abcde
317 assert response.json() == "asyncgen started" 1abcde
318 assert state["/async"] == "asyncgen completed" 1abcde
321def test_sync_sync_state(): 1abcde
322 response = client.get("/sync_sync") 1abcde
323 assert response.status_code == 200, response.text 1abcde
324 assert response.json() == "generator started" 1abcde
325 assert state["/sync"] == "generator completed" 1abcde
328def test_sync_async_raise_other(): 1abcde
329 with pytest.raises(OtherDependencyError): 1abcde
330 client.get("/sync_async_raise_other") 1abcde
331 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
332 assert "/async_raise" not in errors 1abcde
335def test_sync_sync_raise_other(): 1abcde
336 with pytest.raises(OtherDependencyError): 1abcde
337 client.get("/sync_sync_raise_other") 1abcde
338 assert state["/sync_raise"] == "generator raise finalized" 1abcde
339 assert "/sync_raise" not in errors 1abcde
342def test_sync_async_raise_raises(): 1abcde
343 with pytest.raises(AsyncDependencyError): 1abcde
344 client.get("/sync_async_raise") 1abcde
345 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
346 assert "/async_raise" in errors 1abcde
347 errors.clear() 1abcde
350def test_sync_async_raise_server_error(): 1abcde
351 client = TestClient(app, raise_server_exceptions=False) 1abcde
352 response = client.get("/sync_async_raise") 1abcde
353 assert response.status_code == 500, response.text 1abcde
354 assert state["/async_raise"] == "asyncgen raise finalized" 1abcde
355 assert "/async_raise" in errors 1abcde
356 errors.clear() 1abcde
359def test_sync_sync_raise_raises(): 1abcde
360 with pytest.raises(SyncDependencyError): 1abcde
361 client.get("/sync_sync_raise") 1abcde
362 assert state["/sync_raise"] == "generator raise finalized" 1abcde
363 assert "/sync_raise" in errors 1abcde
364 errors.clear() 1abcde
367def test_sync_sync_raise_server_error(): 1abcde
368 client = TestClient(app, raise_server_exceptions=False) 1abcde
369 response = client.get("/sync_sync_raise") 1abcde
370 assert response.status_code == 500, response.text 1abcde
371 assert state["/sync_raise"] == "generator raise finalized" 1abcde
372 assert "/sync_raise" in errors 1abcde
373 errors.clear() 1abcde
376def test_sync_context_b(): 1abcde
377 response = client.get("/sync_context_b") 1abcde
378 data = response.json() 1abcde
379 assert data["context_b"] == "started b" 1abcde
380 assert data["context_a"] == "started a" 1abcde
381 assert state["context_b"] == "finished b with a: started a" 1abcde
382 assert state["context_a"] == "finished a" 1abcde
385def test_sync_context_b_raise(): 1abcde
386 with pytest.raises(OtherDependencyError): 1abcde
387 client.get("/sync_context_b_raise") 1abcde
388 assert state["context_b"] == "finished b with a: started a" 1abcde
389 assert state["context_a"] == "finished a" 1abcde
392def test_sync_background_tasks(): 1abcde
393 response = client.get("/sync_context_b_bg") 1abcde
394 data = response.json() 1abcde
395 assert data["context_b"] == "started b" 1abcde
396 assert data["context_a"] == "started a" 1abcde
397 assert data["sync_bg"] == "not set" 1abcde
398 assert state["context_b"] == "finished b with a: started a" 1abcde
399 assert state["context_a"] == "finished a" 1abcde
400 assert ( 1abcde
401 state["sync_bg"]
402 == "sync_bg set - b: finished b with a: started a - a: finished a"
403 )