Skip to content

Commit 847e8d2

Browse files
committed
Add async context manager resource cleanup tests
1 parent ee4cdbd commit 847e8d2

1 file changed

Lines changed: 57 additions & 0 deletions

File tree

test/unit/test_container_generator_factory.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@
1212
from test.conftest import Container
1313

1414

15+
class AsyncContextManagerResource:
16+
def __init__(self, cleanup_events: list[str]) -> None:
17+
self.cleanup_events = cleanup_events
18+
self.entered = False
19+
self.exited = False
20+
21+
async def __aenter__(self) -> "AsyncContextManagerResource":
22+
self.entered = True
23+
return self
24+
25+
async def __aexit__(self, *_: object) -> None:
26+
self.exited = True
27+
self.cleanup_events.append("resource")
28+
29+
1530
def test_cleans_up_on_exit(container: Container) -> None:
1631
_cleanup_performed = False
1732
Something = NewType("Something", str)
@@ -50,6 +65,26 @@ async def target(smth: Injected[Something]):
5065
assert _cleanup_performed
5166

5267

68+
async def test_async_generator_factory_closes_async_context_manager_on_container_close() -> None:
69+
cleanup_events: list[str] = []
70+
71+
@injectable
72+
async def some_factory() -> AsyncIterator[AsyncContextManagerResource]:
73+
async with AsyncContextManagerResource(cleanup_events) as resource:
74+
yield resource
75+
76+
container = wireup.create_async_container(injectables=[some_factory])
77+
resource = await container.get(AsyncContextManagerResource)
78+
79+
assert resource.entered
80+
assert not resource.exited
81+
82+
await container.close()
83+
84+
assert resource.exited
85+
assert cleanup_events == ["resource"]
86+
87+
5388
def test_injects_transient() -> None:
5489
_cleanups: list[str] = []
5590
Something = NewType("Something", str)
@@ -103,6 +138,28 @@ def f2(something: Something) -> Iterator[SomethingElse]:
103138
assert _cleanups == ["f2", "f1"]
104139

105140

141+
@pytest.mark.parametrize("lifetime", ["scoped", "transient"])
142+
async def test_async_generator_factory_closes_async_context_manager_on_scope_exit(
143+
lifetime: InjectableLifetime,
144+
) -> None:
145+
cleanup_events: list[str] = []
146+
147+
@injectable(lifetime=lifetime)
148+
async def some_factory() -> AsyncIterator[AsyncContextManagerResource]:
149+
async with AsyncContextManagerResource(cleanup_events) as resource:
150+
yield resource
151+
152+
container = wireup.create_async_container(injectables=[some_factory])
153+
154+
async with container.enter_scope() as scoped:
155+
resource = await scoped.get(AsyncContextManagerResource)
156+
assert resource.entered
157+
assert not resource.exited
158+
159+
assert resource.exited
160+
assert cleanup_events == ["resource"]
161+
162+
106163
def test_cleans_up_in_order() -> None:
107164
_cleanups: list[str] = []
108165
Something = NewType("Something", str)

0 commit comments

Comments
 (0)