55from collections .abc import AsyncGenerator , Callable , Generator
66from contextlib import asynccontextmanager
77import functools
8+ import gc
89from json import JSONDecoder , loads
910import logging
1011import sqlite3
1112import ssl
1213import threading
1314from typing import Any
1415from unittest .mock import AsyncMock , MagicMock , Mock , patch
16+ import warnings
1517
1618from aiohttp import client
1719from 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 )
208232def 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