Skip to content

Commit c47a210

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 ea78c09 commit c47a210

File tree

1 file changed

+28
-3
lines changed

1 file changed

+28
-3
lines changed

tests/conftest.py

+28-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
from contextlib import asynccontextmanager
77
import functools
88
import itertools
9+
import gc
910
from json import JSONDecoder, loads
1011
import logging
1112
import sqlite3
1213
import ssl
1314
import threading
1415
from typing import Any
1516
from unittest.mock import AsyncMock, MagicMock, Mock, patch
17+
import warnings
1618

1719
from aiohttp import client
1820
from aiohttp.pytest_plugin import AiohttpClient
@@ -188,12 +190,14 @@ async def guard_func(*args, **kwargs):
188190

189191

190192
@pytest.fixture(autouse=True)
191-
def verify_cleanup():
193+
def verify_cleanup(event_loop: asyncio.AbstractEventLoop):
192194
"""Verify that the test has cleaned up resources correctly."""
193195
threads_before = frozenset(threading.enumerate())
194-
196+
tasks_before = asyncio.all_tasks(event_loop)
195197
yield
196198

199+
event_loop.run_until_complete(event_loop.shutdown_default_executor())
200+
197201
if len(INSTANCES) >= 2:
198202
count = len(INSTANCES)
199203
for inst in INSTANCES:
@@ -204,6 +208,26 @@ def verify_cleanup():
204208
for thread in threads:
205209
assert isinstance(thread, threading._DummyThread)
206210

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

208232
@pytest.fixture(autouse=True)
209233
def bcrypt_cost():
@@ -382,7 +406,7 @@ def exc_handle(loop, context):
382406

383407

384408
@pytest.fixture
385-
async def stop_hass():
409+
async def stop_hass(event_loop):
386410
"""Make sure all hass are stopped."""
387411
orig_hass = ha.HomeAssistant
388412

@@ -403,6 +427,7 @@ def mock_hass():
403427
with patch.object(hass_inst.loop, "stop"):
404428
await hass_inst.async_block_till_done()
405429
await hass_inst.async_stop(force=True)
430+
await event_loop.shutdown_default_executor()
406431

407432

408433
@pytest.fixture

0 commit comments

Comments
 (0)