Skip to content

Commit af1dc9e

Browse files
committed
Make sure executors, tasks and timers are closed
Some test will trigger warnings on garbage collect, these warnings spills over into next test. Some test trigger tasks that raise errors on shutdown, these spill over into next test. This is to mimic older pytest-aiohttp and it's behaviour on test cleanup. Discussions on similar changes for pytest-aiohttp are here: pytest-dev/pytest-asyncio#309
1 parent 181ffc9 commit af1dc9e

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

tests/conftest.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
from collections.abc import AsyncGenerator, Callable, Generator
66
from contextlib import asynccontextmanager
77
import functools
8+
import gc
89
from json import JSONDecoder, loads
910
import logging
1011
import sqlite3
1112
import ssl
1213
import threading
1314
from typing import Any
1415
from unittest.mock import AsyncMock, MagicMock, Mock, patch
16+
import warnings
1517

1618
from aiohttp import client
1719
from aiohttp.pytest_plugin import AiohttpClient
@@ -187,12 +189,14 @@ async def guard_func(*args, **kwargs):
187189

188190

189191
@pytest.fixture(autouse=True)
190-
def verify_cleanup():
192+
def verify_cleanup(event_loop: asyncio.AbstractEventLoop):
191193
"""Verify that the test has cleaned up resources correctly."""
192194
threads_before = frozenset(threading.enumerate())
193-
195+
tasks_before = asyncio.all_tasks(event_loop)
194196
yield
195197

198+
event_loop.run_until_complete(event_loop.shutdown_default_executor())
199+
196200
if len(INSTANCES) >= 2:
197201
count = len(INSTANCES)
198202
for inst in INSTANCES:
@@ -203,6 +207,26 @@ def verify_cleanup():
203207
for thread in threads:
204208
assert isinstance(thread, threading._DummyThread)
205209

210+
# Warn and clean-up lingering tasks and timers
211+
# before moving on to the next test.
212+
tasks = asyncio.all_tasks(event_loop) - tasks_before
213+
for task in tasks:
214+
warnings.warn(f"Linger task after test {task}")
215+
task.cancel()
216+
if tasks:
217+
event_loop.run_until_complete(asyncio.wait(tasks))
218+
219+
for handle in event_loop._scheduled: # pylint: disable=protected-access
220+
if not handle.cancelled():
221+
warnings.warn(f"Lingering timer after test {handle}")
222+
handle.cancel()
223+
224+
# Make sure garbage collect run in same test as allocation
225+
# this is to mimic the behavior of pytest-aiohttp, and is
226+
# required to avoid warnings from spilling over into next
227+
# test case.
228+
gc.collect()
229+
206230

207231
@pytest.fixture(autouse=True)
208232
def bcrypt_cost():
@@ -381,7 +405,7 @@ def exc_handle(loop, context):
381405

382406

383407
@pytest.fixture
384-
async def stop_hass():
408+
async def stop_hass(event_loop):
385409
"""Make sure all hass are stopped."""
386410
orig_hass = ha.HomeAssistant
387411

@@ -402,6 +426,7 @@ def mock_hass():
402426
with patch.object(hass_inst.loop, "stop"):
403427
await hass_inst.async_block_till_done()
404428
await hass_inst.async_stop(force=True)
429+
await event_loop.shutdown_default_executor()
405430

406431

407432
@pytest.fixture

0 commit comments

Comments
 (0)