"""Tests for the interrupt cleanup background loop in main.py.""" from __future__ import annotations import asyncio import logging from unittest.mock import MagicMock, patch import pytest from app.main import _interrupt_cleanup_loop @pytest.mark.unit @pytest.mark.asyncio async def test_cleanup_loop_calls_cleanup_expired() -> None: """The loop should call cleanup_expired after each sleep interval.""" manager = MagicMock() manager.cleanup_expired.return_value = () call_count = 0 original_sleep = asyncio.sleep async def _fake_sleep(seconds: float) -> None: nonlocal call_count call_count += 1 if call_count >= 2: raise asyncio.CancelledError await original_sleep(0) with patch("app.main.asyncio.sleep", side_effect=_fake_sleep): with pytest.raises(asyncio.CancelledError): await _interrupt_cleanup_loop(manager, interval=60) assert manager.cleanup_expired.call_count >= 1 @pytest.mark.unit @pytest.mark.asyncio async def test_cleanup_loop_survives_exceptions() -> None: """The loop should not die when cleanup_expired raises an exception.""" manager = MagicMock() manager.cleanup_expired.side_effect = [RuntimeError("db gone"), ()] call_count = 0 original_sleep = asyncio.sleep async def _fake_sleep(seconds: float) -> None: nonlocal call_count call_count += 1 if call_count >= 3: raise asyncio.CancelledError await original_sleep(0) with patch("app.main.asyncio.sleep", side_effect=_fake_sleep): with pytest.raises(asyncio.CancelledError): await _interrupt_cleanup_loop(manager, interval=60) # Should have been called twice: once raising, once returning () assert manager.cleanup_expired.call_count == 2 @pytest.mark.unit @pytest.mark.asyncio async def test_cleanup_loop_logs_expired_count(capsys: pytest.CaptureFixture[str]) -> None: """The loop should log when expired interrupts are found.""" fake_record = MagicMock() manager = MagicMock() manager.cleanup_expired.return_value = (fake_record, fake_record) call_count = 0 original_sleep = asyncio.sleep async def _fake_sleep(seconds: float) -> None: nonlocal call_count call_count += 1 if call_count >= 2: raise asyncio.CancelledError await original_sleep(0) with patch("app.main.asyncio.sleep", side_effect=_fake_sleep): with pytest.raises(asyncio.CancelledError): await _interrupt_cleanup_loop(manager, interval=60) captured = capsys.readouterr() assert "2 expired interrupt" in captured.out