"""Verify real aiohttp sessions close on interruption and warmup races.""" import asyncio import uuid from unittest.mock import AsyncMock import pytest from implementations.minimax_tts import MiniMaxTTS from implementations.volcano_llm import VolcanoLLM from services.audio_session import AudioSession from services.interrupt_handler import interrupt_handler from services.conversation_history import conversation_history_manager from handlers.service_connection_handler import prepare_llm_service, prepare_tts_service @pytest.mark.asyncio @pytest.mark.parametrize('kind', ['llm', 'tts']) @pytest.mark.parametrize('phase', ['ready', 'connecting', 'cancelled', 'already_interrupted']) async def test_warmup_releases_provider_client(monkeypatch, kind, phase): key = ('warmup-test', uuid.uuid4().hex) service = VolcanoLLM() if kind == 'llm' else MiniMaxTTS() session = AudioSession(llm_service=service if kind == 'llm' else None, tts_service=service if kind == 'tts' else None) session.device_id, session.session_id = key monkeypatch.setattr(conversation_history_manager, 'get_history', AsyncMock(return_value=None)) prepare = prepare_llm_service if kind == 'llm' else prepare_tts_service original_connect = service.connect entered, resume = asyncio.Event(), asyncio.Event() async def delayed_connect(): if phase == 'cancelled': await original_connect() entered.set() await resume.wait() if phase != 'cancelled': await original_connect() task = None try: if phase == 'already_interrupted': await interrupt_handler.set_interrupt_state(key, True) if phase in ('connecting', 'cancelled'): monkeypatch.setattr(service, 'connect', delayed_connect) task = asyncio.create_task(prepare(session, *key, {})) if phase in ('connecting', 'cancelled'): await entered.wait() if phase == 'cancelled': task.cancel() with pytest.raises(asyncio.CancelledError): await task else: await interrupt_handler.handle_interrupt(key) resume.set() await task else: await task if phase == 'ready': assert service.connected await interrupt_handler.handle_interrupt(key) client = service.session if kind == 'llm' else service._client_session assert client is None or client.closed assert not service.connected finally: if task and not task.done(): task.cancel() await asyncio.gather(task, return_exceptions=True) await service.close() await interrupt_handler.remove_session(key)