mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-22 03:49:18 +02:00
test: close the coroutines that mocked create_task, wait_for, run_coroutine_threadsafe, spawn_background_task and AsyncMock sessions left unawaited (reported as unraisable warnings in unrelated later tests); the Spoolman recovery tests archive under their own tmp_path instead of the shared archive/
This commit is contained in:
@@ -35,7 +35,11 @@ async def _complete(printer_id, status, update):
|
||||
session = AsyncMock()
|
||||
session.__aenter__ = AsyncMock(return_value=session)
|
||||
session.__aexit__ = AsyncMock(return_value=False)
|
||||
session.execute = AsyncMock(return_value=MagicMock())
|
||||
# Plain mocks for what the reads return: an AsyncMock's results are
|
||||
# AsyncMocks too, so a plain call on one (completed_at.astimezone(),
|
||||
# .first()) leaves an unawaited coroutine, reported in a later test.
|
||||
for read in ("execute", "get", "scalar", "scalars"):
|
||||
setattr(session, read, AsyncMock(return_value=MagicMock()))
|
||||
tasks_before = set(asyncio.all_tasks())
|
||||
with (
|
||||
patch("backend.app.main.async_session", return_value=session),
|
||||
|
||||
@@ -422,10 +422,21 @@ class TestPrinterManager:
|
||||
mock_loop.is_running.return_value = True
|
||||
manager._loop = mock_loop
|
||||
|
||||
manager.mark_printer_offline(1)
|
||||
# The stand-in loop never runs the callback, so the scheduled
|
||||
# coroutine is closed here instead of being reported in a later test.
|
||||
def _close_and_stand_in(coro, loop):
|
||||
coro.close()
|
||||
return MagicMock()
|
||||
|
||||
with patch(
|
||||
"backend.app.services.printer_manager.asyncio.run_coroutine_threadsafe",
|
||||
side_effect=_close_and_stand_in,
|
||||
) as scheduled:
|
||||
manager.mark_printer_offline(1)
|
||||
|
||||
# Callback should be scheduled via run_coroutine_threadsafe
|
||||
mock_loop.is_running.assert_called()
|
||||
scheduled.assert_called_once()
|
||||
# State should be updated
|
||||
assert mock_client.state.connected is False
|
||||
|
||||
|
||||
@@ -375,15 +375,20 @@ class TestSmartPlugManager:
|
||||
"""Verify scheduler can be started."""
|
||||
assert manager._scheduler_task is None
|
||||
|
||||
# Mock _schedule_loop to return a mock coroutine to avoid unawaited coroutine warning
|
||||
# The patched loops are AsyncMocks, so each call still builds a
|
||||
# coroutine: the stand-in create_task closes it, or it is reported
|
||||
# unawaited in a later test.
|
||||
def _close_and_stand_in(coro, **_):
|
||||
coro.close()
|
||||
return MagicMock()
|
||||
|
||||
with (
|
||||
patch.object(manager, "_schedule_loop") as mock_loop,
|
||||
patch.object(manager, "_snapshot_loop"),
|
||||
patch.object(manager, "_power_alert_loop") as mock_power_alert,
|
||||
patch.object(manager, "_relay_energy_loop") as mock_relay_energy,
|
||||
patch("asyncio.create_task") as mock_create,
|
||||
patch("asyncio.create_task", side_effect=_close_and_stand_in),
|
||||
):
|
||||
mock_create.return_value = MagicMock()
|
||||
manager.start_scheduler()
|
||||
|
||||
assert manager._scheduler_task is not None
|
||||
|
||||
@@ -4213,21 +4213,20 @@ class TestSlicerProxyManager:
|
||||
)
|
||||
|
||||
# Mock asyncio.create_task and asyncio.gather to prevent actual
|
||||
# server start. Close every coroutine handed to gather — otherwise
|
||||
# the ~110 run_with_logging() coros built inside start() are
|
||||
# garbage-collected unfinalized and surface later as
|
||||
# PytestUnraisableExceptionWarning at random in other tests.
|
||||
async def _close_pending(*coros, **_):
|
||||
for c in coros:
|
||||
if asyncio.iscoroutine(c):
|
||||
c.close()
|
||||
# server start. Close every coroutine handed to create_task (gather
|
||||
# only sees the stand-in tasks) — otherwise the ~110
|
||||
# run_with_logging() coros built inside start() are garbage-collected
|
||||
# unfinalized and surface later as PytestUnraisableExceptionWarning at
|
||||
# random in other tests.
|
||||
def _close_and_stand_in(coro, **_):
|
||||
coro.close()
|
||||
return MagicMock()
|
||||
|
||||
with (
|
||||
patch("asyncio.create_task") as mock_create_task,
|
||||
patch("asyncio.gather", side_effect=_close_pending),
|
||||
patch("asyncio.create_task", side_effect=_close_and_stand_in),
|
||||
patch("asyncio.gather", new=AsyncMock()),
|
||||
patch.object(SlicerProxyManager, "_log_activity"),
|
||||
):
|
||||
mock_create_task.return_value = MagicMock()
|
||||
await mgr.start()
|
||||
|
||||
# FTP, FileTransfer, RTSP should be TCPProxy (transparent)
|
||||
|
||||
@@ -118,15 +118,9 @@ class TestCheckPort:
|
||||
async def test_unreachable_port(self):
|
||||
from backend.app.api.routes.support import _check_port
|
||||
|
||||
with (
|
||||
patch(
|
||||
"backend.app.api.routes.support.asyncio.open_connection",
|
||||
side_effect=ConnectionRefusedError,
|
||||
),
|
||||
patch(
|
||||
"backend.app.api.routes.support.asyncio.wait_for",
|
||||
side_effect=ConnectionRefusedError,
|
||||
),
|
||||
with patch(
|
||||
"backend.app.api.routes.support.asyncio.open_connection",
|
||||
side_effect=ConnectionRefusedError,
|
||||
):
|
||||
result = await _check_port("192.168.1.1", 8883, timeout=1.0)
|
||||
|
||||
@@ -137,10 +131,12 @@ class TestCheckPort:
|
||||
async def test_timeout(self):
|
||||
from backend.app.api.routes.support import _check_port
|
||||
|
||||
with patch(
|
||||
"backend.app.api.routes.support.asyncio.wait_for",
|
||||
side_effect=asyncio.TimeoutError,
|
||||
):
|
||||
# Closes the connect it was handed: left unawaited, it is reported in a later test.
|
||||
async def _times_out(coro, timeout):
|
||||
coro.close()
|
||||
raise TimeoutError
|
||||
|
||||
with patch("backend.app.api.routes.support.asyncio.wait_for", side_effect=_times_out):
|
||||
result = await _check_port("192.168.1.1", 8883, timeout=0.1)
|
||||
|
||||
assert result is False
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
solid test
|
||||
endsolid test
|
||||
Reference in New Issue
Block a user