surfaces/tests/core/test_integration.py
Mikhail Putilovskij 36730ae716 feat: implement core/ and platform/ with full test coverage
- platform/interface.py: PlatformClient Protocol + Pydantic models (User,
  MessageResponse, UserSettings) — no explicit session management, Master
  handles container lifecycle
- platform/mock.py: MockPlatformClient with simulated latency, [MOCK]
  responses, is_new correctly True only on first creation
- core/protocol.py: unified dataclasses for all events and responses
  (IncomingMessage/Command/Callback, OutgoingMessage/UI/Notification,
  AuthFlow, ChatContext, SettingsAction, etc.)
- core/store.py: StateStore Protocol + InMemoryStore (tests) + SQLiteStore
  (prod) with JSON serialization
- core/chat.py: ChatManager — chat metadata (C1/C2/C3), not container
  lifecycle (that's the platform's job)
- core/auth.py: AuthManager — start_flow / confirm / is_authenticated
- core/settings.py: SettingsManager — get/apply with store cache
- core/handler.py: EventDispatcher — registry-based routing with keys
  (command name, action name, attachment type, "*" catch-all)
- core/handlers/: register_all() + start/new/message/callback/settings
  handlers; voice slot falls back to stub text until voice_handler added
- conftest.py: sys.path fix so local platform/ shadows stdlib platform
- docs/api-contract.md: rewritten for Lambda Lab 3.0 container model

46 tests passing, 0 warnings.
2026-03-29 21:42:02 +03:00

85 lines
3.2 KiB
Python

# tests/core/test_integration.py
"""
Smoke test: полный цикл через dispatcher + реальные managers + MockPlatformClient.
Имитирует что делает адаптер (Telegram или Matrix) при получении события.
"""
import pytest
from platform.mock import MockPlatformClient
from core.store import InMemoryStore
from core.chat import ChatManager
from core.auth import AuthManager
from core.settings import SettingsManager
from core.handler import EventDispatcher
from core.handlers import register_all
from core.protocol import (
IncomingCommand, IncomingMessage, IncomingCallback,
OutgoingMessage, OutgoingUI,
Attachment, SettingsAction,
)
@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
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))