ForcePilot/backend/test/unit/channel/interfaces/websocket/test_manager.py
Kris 6c95dc006a test: 新增渠道模块全链路单元测试用例与目录结构
完成渠道模块的单元测试目录搭建,新增多个领域模型、端口、中间件、事件、服务以及基础设施层的单元测试文件,同时补充了conftest.py的环境变量配置,完善测试基础环境。
2026-05-30 21:55:35 +08:00

230 lines
6.1 KiB
Python

from __future__ import annotations
import asyncio
import pytest
from uuid import uuid4
from yuxi.channel.interfaces.websocket.manager import WsConnectionManager
from yuxi.channel.domain.port.ws_connection_port import WsConnectionPort
from yuxi.channel.domain.port.channel_adapter_port import ChannelAdapterPort
from yuxi.channel.domain.model.message.unified_message import UnifiedMessage
from yuxi.channel.domain.model.message.peer import Peer
from yuxi.channel.domain.model.shared.channel_type import ChannelType
class _FakeWsConnection(WsConnectionPort):
def __init__(self, channel_type: str, connected: bool = True):
self._channel_type = channel_type
self._connected = connected
self.started = False
self.stopped = False
@property
def channel_type(self) -> str:
return self._channel_type
@property
def is_connected(self) -> bool:
return self._connected
async def start(self, loop, on_message) -> None:
self.started = True
async def stop(self) -> None:
self.stopped = True
class _FakeAdapter(ChannelAdapterPort):
def __init__(self, channel_type: str):
self._channel_type = channel_type
@property
def channel_type(self) -> str:
return self._channel_type
@property
def ws_connection(self):
return None
async def open(self) -> None:
pass
async def close(self) -> None:
pass
async def receive_message(self, raw: dict) -> UnifiedMessage:
return UnifiedMessage(
message_id="test",
channel_type=ChannelType.WEB,
sender=Peer(id="user", name="User"),
content="hello",
)
async def send_message(self, session_id: str, content: str, *, channel_type: str, metadata: dict):
from yuxi.channel.domain.model.message.dispatch_result import SendResult
return SendResult(success=True)
async def send_typing(self, session_id: str) -> None:
pass
async def send_media(self, session_id: str, *, url: str, media_type: str, metadata: dict) -> bool:
return True
async def is_healthy(self) -> bool:
return True
@property
def capabilities(self):
from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities
return ChannelCapabilities()
@classmethod
def get_default_config(cls) -> dict:
return {}
class _FakeInboundService:
def __init__(self):
self.submitted = []
async def submit(self, message, *, channel_type: str, trace_id: str = ""):
self.submitted.append({"message": message, "channel_type": channel_type, "trace_id": trace_id})
class _FakeMetrics:
pass
@pytest.fixture
def manager():
return WsConnectionManager(metrics=_FakeMetrics())
@pytest.mark.asyncio
async def test_ws_manager_register(manager):
conn = _FakeWsConnection("feishu")
manager.register(conn)
assert "feishu" in manager._connections
@pytest.mark.asyncio
async def test_ws_manager_set_adapters(manager):
adapters = {"feishu": _FakeAdapter("feishu")}
manager.set_adapters(adapters)
assert manager._adapters == adapters
@pytest.mark.asyncio
async def test_ws_manager_start_all(manager):
conn = _FakeWsConnection("feishu")
manager.register(conn)
inbound = _FakeInboundService()
loop = asyncio.get_event_loop()
await manager.start_all(loop, inbound)
assert conn.started is True
await manager.stop_all()
assert conn.stopped is True
@pytest.mark.asyncio
async def test_ws_manager_connections_status(manager):
conn1 = _FakeWsConnection("feishu", connected=True)
conn2 = _FakeWsConnection("dingtalk", connected=False)
manager.register(conn1)
manager.register(conn2)
status = manager.connections_status
assert status["feishu"] is True
assert status["dingtalk"] is False
@pytest.mark.asyncio
async def test_ws_manager_on_message(manager):
adapter = _FakeAdapter("feishu")
manager.set_adapters({"feishu": adapter})
inbound = _FakeInboundService()
loop = asyncio.get_event_loop()
await manager.start_all(loop, inbound)
raw = {
"channel_type": "feishu",
"header": {"event_id": "test-event-id"},
"content": "hello",
}
await manager._on_message(raw)
assert len(inbound.submitted) == 1
assert inbound.submitted[0]["channel_type"] == "feishu"
assert inbound.submitted[0]["trace_id"] == "test-event-id"
await manager.stop_all()
@pytest.mark.asyncio
async def test_ws_manager_on_message_no_adapter(manager):
manager.set_adapters({})
inbound = _FakeInboundService()
loop = asyncio.get_event_loop()
await manager.start_all(loop, inbound)
raw = {
"channel_type": "unknown",
"header": {"event_id": "test-event-id"},
}
await manager._on_message(raw)
assert len(inbound.submitted) == 0
await manager.stop_all()
@pytest.mark.asyncio
async def test_ws_manager_on_message_receive_error(manager):
class _BadAdapter(_FakeAdapter):
async def receive_message(self, raw: dict) -> UnifiedMessage:
raise ValueError("parse error")
manager.set_adapters({"feishu": _BadAdapter("feishu")})
inbound = _FakeInboundService()
loop = asyncio.get_event_loop()
await manager.start_all(loop, inbound)
raw = {
"channel_type": "feishu",
"header": {"event_id": "test-event-id"},
}
await manager._on_message(raw)
assert len(inbound.submitted) == 0
await manager.stop_all()
@pytest.mark.asyncio
async def test_ws_manager_on_message_submit_error(manager):
class _BadInboundService:
async def submit(self, message, *, channel_type: str, trace_id: str = ""):
raise ValueError("submit error")
adapter = _FakeAdapter("feishu")
manager.set_adapters({"feishu": adapter})
inbound = _BadInboundService()
loop = asyncio.get_event_loop()
await manager.start_all(loop, inbound)
raw = {
"channel_type": "feishu",
"header": {"event_id": "test-event-id"},
}
# Should not raise
await manager._on_message(raw)
await manager.stop_all()