1616from pytest_mock import MockerFixture
1717from pytest_simcore .helpers .logging_tools import log_context
1818from servicelib .fastapi .lifespan_utils import (
19+ LifespanAlreadyCalledError ,
1920 LifespanOnShutdownError ,
2021 LifespanOnStartupError ,
22+ record_lifespan_called_once ,
2123)
2224
2325
@@ -186,7 +188,7 @@ async def lifespan_failing_on_startup(app: FastAPI) -> AsyncIterator[State]:
186188 startup_step (_name )
187189 except RuntimeError as exc :
188190 handle_error (_name , exc )
189- raise LifespanOnStartupError (module = _name ) from exc
191+ raise LifespanOnStartupError (lifespan_name = _name ) from exc
190192 yield {}
191193 shutdown_step (_name )
192194
@@ -201,7 +203,7 @@ async def lifespan_failing_on_shutdown(app: FastAPI) -> AsyncIterator[State]:
201203 shutdown_step (_name )
202204 except RuntimeError as exc :
203205 handle_error (_name , exc )
204- raise LifespanOnShutdownError (module = _name ) from exc
206+ raise LifespanOnShutdownError (lifespan_name = _name ) from exc
205207
206208 return {
207209 "startup_step" : startup_step ,
@@ -228,7 +230,7 @@ async def test_app_lifespan_with_error_on_startup(
228230 assert not failing_lifespan_manager ["startup_step" ].called
229231 assert not failing_lifespan_manager ["shutdown_step" ].called
230232 assert exception .error_context () == {
231- "module " : "lifespan_failing_on_startup" ,
233+ "lifespan_name " : "lifespan_failing_on_startup" ,
232234 "message" : "Failed during startup of lifespan_failing_on_startup" ,
233235 "code" : "RuntimeError.LifespanError.LifespanOnStartupError" ,
234236 }
@@ -250,7 +252,35 @@ async def test_app_lifespan_with_error_on_shutdown(
250252 assert failing_lifespan_manager ["startup_step" ].called
251253 assert not failing_lifespan_manager ["shutdown_step" ].called
252254 assert exception .error_context () == {
253- "module " : "lifespan_failing_on_shutdown" ,
255+ "lifespan_name " : "lifespan_failing_on_shutdown" ,
254256 "message" : "Failed during shutdown of lifespan_failing_on_shutdown" ,
255257 "code" : "RuntimeError.LifespanError.LifespanOnShutdownError" ,
256258 }
259+
260+
261+ async def test_lifespan_called_more_than_once (is_pdb_enabled : bool ):
262+ state = {}
263+
264+ app_lifespan = LifespanManager ()
265+
266+ @app_lifespan .add
267+ async def _one (_ , state : State ) -> AsyncIterator [State ]:
268+ called_state = record_lifespan_called_once (state , "test_lifespan_one" )
269+ yield {"other" : 0 , ** called_state }
270+
271+ @app_lifespan .add
272+ async def _two (_ , state : State ) -> AsyncIterator [State ]:
273+ called_state = record_lifespan_called_once (state , "test_lifespan_two" )
274+ yield {"something" : 0 , ** called_state }
275+
276+ app_lifespan .add (_one ) # added "by mistake"
277+
278+ with pytest .raises (LifespanAlreadyCalledError ) as err_info :
279+ async with ASGILifespanManager (
280+ FastAPI (lifespan = app_lifespan ),
281+ startup_timeout = None if is_pdb_enabled else 10 ,
282+ shutdown_timeout = None if is_pdb_enabled else 10 ,
283+ ):
284+ ...
285+
286+ assert err_info .value .lifespan_name == "test_lifespan_one"
0 commit comments