# tests/core/test_integration.py """ Smoke test: полный цикл через dispatcher + реальные managers + MockPlatformClient. Имитирует что делает адаптер (Telegram или Matrix) при получении события. """ import pytest from core.auth import AuthManager from core.chat import ChatManager from core.handler import EventDispatcher from core.handlers import register_all from core.protocol import ( Attachment, IncomingCallback, IncomingCommand, IncomingMessage, OutgoingMessage, OutgoingUI, ) from core.settings import SettingsManager from core.store import InMemoryStore from sdk.mock import MockPlatformClient from sdk.prototype_state import PrototypeStateStore from sdk.real import RealPlatformClient from sdk.upstream_agent_api import MsgEventTextChunk class FakeAgentApi: def __init__(self, agent_id: str, base_url: str, chat_id: str) -> None: self.agent_id = agent_id self.base_url = base_url self.chat_id = chat_id self.calls: list[tuple[str, list[str]]] = [] self.connect_calls = 0 self.close_calls = 0 async def connect(self) -> None: self.connect_calls += 1 async def close(self) -> None: self.close_calls += 1 async def send_message(self, text: str, attachments: list[str] | None = None): self.calls.append((text, attachments or [])) yield MsgEventTextChunk(text=f"[REAL] {text}") class FakeAgentApiFactory: def __init__(self) -> None: self.created_chat_ids: list[str] = [] self.instances: dict[str, list[FakeAgentApi]] = {} def __call__(self, agent_id: str, base_url: str, chat_id: str) -> FakeAgentApi: chat_api = FakeAgentApi(agent_id, base_url, chat_id) self.created_chat_ids.append(chat_id) self.instances.setdefault(chat_id, []).append(chat_api) return chat_api @pytest.fixture def dispatcher(): platform = MockPlatformClient() store = InMemoryStore() d = EventDispatcher( platform=platform, chat_mgr=ChatManager(platform, store), auth_mgr=AuthManager(platform, store), settings_mgr=SettingsManager(platform, store), ) register_all(d) return d @pytest.fixture def real_dispatcher(): agent_api = FakeAgentApiFactory() platform = RealPlatformClient( agent_id="matrix-bot", agent_base_url="http://platform-agent:8000", agent_api_cls=agent_api, prototype_state=PrototypeStateStore(), platform="matrix", ) store = InMemoryStore() d = EventDispatcher( platform=platform, chat_mgr=ChatManager(platform, store), auth_mgr=AuthManager(platform, store), settings_mgr=SettingsManager(platform, store), ) register_all(d) return d, agent_api async def test_full_flow_start_then_message(dispatcher): start = IncomingCommand(user_id="tg_123", platform="telegram", chat_id="C1", command="start") result = await dispatcher.dispatch(start) assert any(isinstance(r, OutgoingMessage) for r in result) msg = IncomingMessage(user_id="tg_123", platform="telegram", chat_id="C1", text="Привет!") result = await dispatcher.dispatch(msg) texts = [r.text for r in result if isinstance(r, OutgoingMessage)] assert any("[MOCK]" in t for t in texts) async def test_new_chat_command(dispatcher): start = IncomingCommand(user_id="u1", platform="matrix", chat_id="C1", command="start") await dispatcher.dispatch(start) new = IncomingCommand( user_id="u1", platform="matrix", chat_id="C2", command="new", args=["Анализ"], ) result = await dispatcher.dispatch(new) assert any("Анализ" in r.text for r in result if isinstance(r, OutgoingMessage)) async def test_settings_menu(dispatcher): start = IncomingCommand(user_id="u1", platform="telegram", chat_id="C1", command="start") await dispatcher.dispatch(start) s = IncomingCommand(user_id="u1", platform="telegram", chat_id="C1", command="settings") result = await dispatcher.dispatch(s) assert any(isinstance(r, OutgoingUI) for r in result) async def test_voice_message_fallback(dispatcher): start = IncomingCommand(user_id="u1", platform="telegram", chat_id="C1", command="start") await dispatcher.dispatch(start) voice = IncomingMessage( user_id="u1", platform="telegram", chat_id="C1", text="", attachments=[Attachment(type="audio")], ) result = await dispatcher.dispatch(voice) assert any("голосов" in r.text.lower() for r in result if isinstance(r, OutgoingMessage)) async def test_toggle_skill_callback(dispatcher): start = IncomingCommand(user_id="u1", platform="telegram", chat_id="C1", command="start") await dispatcher.dispatch(start) cb = IncomingCallback( user_id="u1", platform="telegram", chat_id="C1", action="toggle_skill", payload={"skill": "browser", "enabled": True}, ) result = await dispatcher.dispatch(cb) assert any("browser" in r.text for r in result if isinstance(r, OutgoingMessage)) async def test_full_flow_with_real_platform_uses_direct_agent_api(real_dispatcher): dispatcher, agent_api = real_dispatcher start = IncomingCommand(user_id="u1", platform="matrix", chat_id="C1", command="start") result = await dispatcher.dispatch(start) assert any(isinstance(r, OutgoingMessage) for r in result) msg = IncomingMessage(user_id="u1", platform="matrix", chat_id="C1", text="Привет!") result = await dispatcher.dispatch(msg) texts = [r.text for r in result if isinstance(r, OutgoingMessage)] assert texts == ["[REAL] Привет!"] assert agent_api.created_chat_ids == ["C1"] assert [instance.calls for instance in agent_api.instances["C1"]] == [[("Привет!", [])]] async def test_full_flow_with_real_platform_forwards_workspace_attachment(real_dispatcher): dispatcher, agent_api = real_dispatcher start = IncomingCommand(user_id="u1", platform="matrix", chat_id="C1", command="start") await dispatcher.dispatch(start) msg = IncomingMessage( user_id="u1", platform="matrix", chat_id="C1", text="Посмотри файл", attachments=[ Attachment( type="document", filename="report.pdf", mime_type="application/pdf", workspace_path="surfaces/matrix/u1/room/inbox/report.pdf", ) ], ) await dispatcher.dispatch(msg) assert [instance.calls for instance in agent_api.instances["C1"]] == [ [("Посмотри файл", ["surfaces/matrix/u1/room/inbox/report.pdf"])] ]