Coverage for tests/test_router_events.py: 100%
176 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
1from contextlib import asynccontextmanager 1klmno
2from typing import AsyncGenerator, Dict, Union 1klmno
4import pytest 1klmno
5from fastapi import APIRouter, FastAPI, Request 1klmno
6from fastapi.testclient import TestClient 1klmno
7from pydantic import BaseModel 1klmno
10class State(BaseModel): 1klmno
11 app_startup: bool = False 1klmno
12 app_shutdown: bool = False 1klmno
13 router_startup: bool = False 1klmno
14 router_shutdown: bool = False 1klmno
15 sub_router_startup: bool = False 1klmno
16 sub_router_shutdown: bool = False 1klmno
19@pytest.fixture 1klmno
20def state() -> State: 1klmno
21 return State() 1klmno
24@pytest.mark.filterwarnings( 1klmno
25 r"ignore:\s*on_event is deprecated, use lifespan event handlers instead.*:DeprecationWarning"
26)
27def test_router_events(state: State) -> None: 1klmno
28 app = FastAPI() 1abcde
30 @app.get("/") 1abcde
31 def main() -> Dict[str, str]: 1abcde
32 return {"message": "Hello World"} 1abcde
34 @app.on_event("startup") 1abcde
35 def app_startup() -> None: 1abcde
36 state.app_startup = True 1abcde
38 @app.on_event("shutdown") 1abcde
39 def app_shutdown() -> None: 1abcde
40 state.app_shutdown = True 1abcde
42 router = APIRouter() 1abcde
44 @router.on_event("startup") 1abcde
45 def router_startup() -> None: 1abcde
46 state.router_startup = True 1abcde
48 @router.on_event("shutdown") 1abcde
49 def router_shutdown() -> None: 1abcde
50 state.router_shutdown = True 1abcde
52 sub_router = APIRouter() 1abcde
54 @sub_router.on_event("startup") 1abcde
55 def sub_router_startup() -> None: 1abcde
56 state.sub_router_startup = True 1abcde
58 @sub_router.on_event("shutdown") 1abcde
59 def sub_router_shutdown() -> None: 1abcde
60 state.sub_router_shutdown = True 1abcde
62 router.include_router(sub_router) 1abcde
63 app.include_router(router) 1abcde
65 assert state.app_startup is False 1abcde
66 assert state.router_startup is False 1abcde
67 assert state.sub_router_startup is False 1abcde
68 assert state.app_shutdown is False 1abcde
69 assert state.router_shutdown is False 1abcde
70 assert state.sub_router_shutdown is False 1abcde
71 with TestClient(app) as client: 1abcde
72 assert state.app_startup is True 1abcde
73 assert state.router_startup is True 1abcde
74 assert state.sub_router_startup is True 1abcde
75 assert state.app_shutdown is False 1abcde
76 assert state.router_shutdown is False 1abcde
77 assert state.sub_router_shutdown is False 1abcde
78 response = client.get("/") 1abcde
79 assert response.status_code == 200, response.text 1abcde
80 assert response.json() == {"message": "Hello World"} 1abcde
81 assert state.app_startup is True 1abcde
82 assert state.router_startup is True 1abcde
83 assert state.sub_router_startup is True 1abcde
84 assert state.app_shutdown is True 1abcde
85 assert state.router_shutdown is True 1abcde
86 assert state.sub_router_shutdown is True 1abcde
89def test_app_lifespan_state(state: State) -> None: 1klmno
90 @asynccontextmanager 1pqrst
91 async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: 1pqrst
92 state.app_startup = True 1pqrst
93 yield 1pqrst
94 state.app_shutdown = True 1pqrst
96 app = FastAPI(lifespan=lifespan) 1pqrst
98 @app.get("/") 1pqrst
99 def main() -> Dict[str, str]: 1pqrst
100 return {"message": "Hello World"} 1pqrst
102 assert state.app_startup is False 1pqrst
103 assert state.app_shutdown is False 1pqrst
104 with TestClient(app) as client: 1pqrst
105 assert state.app_startup is True 1pqrst
106 assert state.app_shutdown is False 1pqrst
107 response = client.get("/") 1pqrst
108 assert response.status_code == 200, response.text 1pqrst
109 assert response.json() == {"message": "Hello World"} 1pqrst
110 assert state.app_startup is True 1pqrst
111 assert state.app_shutdown is True 1pqrst
114def test_router_nested_lifespan_state(state: State) -> None: 1klmno
115 @asynccontextmanager 1fghij
116 async def lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: 1fghij
117 state.app_startup = True 1fghij
118 yield {"app": True} 1fghij
119 state.app_shutdown = True 1fghij
121 @asynccontextmanager 1fghij
122 async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: 1fghij
123 state.router_startup = True 1fghij
124 yield {"router": True} 1fghij
125 state.router_shutdown = True 1fghij
127 @asynccontextmanager 1fghij
128 async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: 1fghij
129 state.sub_router_startup = True 1fghij
130 yield {"sub_router": True} 1fghij
131 state.sub_router_shutdown = True 1fghij
133 sub_router = APIRouter(lifespan=subrouter_lifespan) 1fghij
135 router = APIRouter(lifespan=router_lifespan) 1fghij
136 router.include_router(sub_router) 1fghij
138 app = FastAPI(lifespan=lifespan) 1fghij
139 app.include_router(router) 1fghij
141 @app.get("/") 1fghij
142 def main(request: Request) -> Dict[str, str]: 1fghij
143 assert request.state.app 1fghij
144 assert request.state.router 1fghij
145 assert request.state.sub_router 1fghij
146 return {"message": "Hello World"} 1fghij
148 assert state.app_startup is False 1fghij
149 assert state.router_startup is False 1fghij
150 assert state.sub_router_startup is False 1fghij
151 assert state.app_shutdown is False 1fghij
152 assert state.router_shutdown is False 1fghij
153 assert state.sub_router_shutdown is False 1fghij
155 with TestClient(app) as client: 1fghij
156 assert state.app_startup is True 1fghij
157 assert state.router_startup is True 1fghij
158 assert state.sub_router_startup is True 1fghij
159 assert state.app_shutdown is False 1fghij
160 assert state.router_shutdown is False 1fghij
161 assert state.sub_router_shutdown is False 1fghij
162 response = client.get("/") 1fghij
163 assert response.status_code == 200, response.text 1fghij
164 assert response.json() == {"message": "Hello World"} 1fghij
166 assert state.app_startup is True 1fghij
167 assert state.router_startup is True 1fghij
168 assert state.sub_router_startup is True 1fghij
169 assert state.app_shutdown is True 1fghij
170 assert state.router_shutdown is True 1fghij
171 assert state.sub_router_shutdown is True 1fghij
174def test_router_nested_lifespan_state_overriding_by_parent() -> None: 1klmno
175 @asynccontextmanager 1zABCD
176 async def lifespan( 1zABCD
177 app: FastAPI,
178 ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]:
179 yield { 1zABCD
180 "app_specific": True,
181 "overridden": "app",
182 }
184 @asynccontextmanager 1zABCD
185 async def router_lifespan( 1zABCD
186 app: FastAPI,
187 ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]:
188 yield { 1zABCD
189 "router_specific": True,
190 "overridden": "router", # should override parent
191 }
193 router = APIRouter(lifespan=router_lifespan) 1zABCD
194 app = FastAPI(lifespan=lifespan) 1zABCD
195 app.include_router(router) 1zABCD
197 with TestClient(app) as client: 1zABCD
198 assert client.app_state == { 1zABCD
199 "app_specific": True,
200 "router_specific": True,
201 "overridden": "app",
202 }
205def test_merged_no_return_lifespans_return_none() -> None: 1klmno
206 @asynccontextmanager 1EFGHI
207 async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: 1EFGHI
208 yield 1EFGHI
210 @asynccontextmanager 1EFGHI
211 async def router_lifespan(app: FastAPI) -> AsyncGenerator[None, None]: 1EFGHI
212 yield 1EFGHI
214 router = APIRouter(lifespan=router_lifespan) 1EFGHI
215 app = FastAPI(lifespan=lifespan) 1EFGHI
216 app.include_router(router) 1EFGHI
218 with TestClient(app) as client: 1EFGHI
219 assert not client.app_state 1EFGHI
222def test_merged_mixed_state_lifespans() -> None: 1klmno
223 @asynccontextmanager 1uvwxy
224 async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: 1uvwxy
225 yield 1uvwxy
227 @asynccontextmanager 1uvwxy
228 async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: 1uvwxy
229 yield {"router": True} 1uvwxy
231 @asynccontextmanager 1uvwxy
232 async def sub_router_lifespan(app: FastAPI) -> AsyncGenerator[None, None]: 1uvwxy
233 yield 1uvwxy
235 sub_router = APIRouter(lifespan=sub_router_lifespan) 1uvwxy
236 router = APIRouter(lifespan=router_lifespan) 1uvwxy
237 app = FastAPI(lifespan=lifespan) 1uvwxy
238 router.include_router(sub_router) 1uvwxy
239 app.include_router(router) 1uvwxy
241 with TestClient(app) as client: 1uvwxy
242 assert client.app_state == {"router": True} 1uvwxy