完成渠道模块的单元测试目录搭建,新增多个领域模型、端口、中间件、事件、服务以及基础设施层的单元测试文件,同时补充了conftest.py的环境变量配置,完善测试基础环境。
147 lines
6.0 KiB
Python
147 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from yuxi.channel.application.service.delivery_service import DeliveryService
|
|
from yuxi.channel.domain.exception.agent_crash_error import AgentCrashError
|
|
from yuxi.channel.domain.model.message.dispatch_result import DispatchResult, SendResult
|
|
from yuxi.channel.domain.model.session.channel_session import ChannelSession
|
|
|
|
|
|
class TestDeliveryService:
|
|
@pytest.fixture
|
|
def mock_adapters(self):
|
|
adapter = AsyncMock()
|
|
adapter.send_message.return_value = SendResult(success=True)
|
|
adapter.capabilities.media = True
|
|
return {"web": adapter}
|
|
|
|
@pytest.fixture
|
|
def mock_message_repo(self):
|
|
return AsyncMock()
|
|
|
|
@pytest.fixture
|
|
def mock_outbox_repo(self):
|
|
return AsyncMock()
|
|
|
|
@pytest.fixture
|
|
def mock_event_publisher(self):
|
|
return AsyncMock()
|
|
|
|
@pytest.fixture
|
|
def mock_agent_port(self):
|
|
agent = AsyncMock()
|
|
agent.stream_chat.return_value = "Hello, user!"
|
|
return agent
|
|
|
|
@pytest.fixture
|
|
def delivery_service(self, mock_adapters, mock_message_repo, mock_outbox_repo, mock_event_publisher, mock_agent_port):
|
|
return DeliveryService(
|
|
adapters=mock_adapters,
|
|
message_repo=mock_message_repo,
|
|
outbox_repo=mock_outbox_repo,
|
|
event_publisher=mock_event_publisher,
|
|
agent_port=mock_agent_port,
|
|
)
|
|
|
|
@pytest.fixture
|
|
def sample_session(self):
|
|
return ChannelSession(
|
|
id=1,
|
|
thread_id="thread123",
|
|
user_id="user1",
|
|
agent_id="1",
|
|
channel_type="web",
|
|
channel_session_key="key1",
|
|
status="active",
|
|
title=None,
|
|
)
|
|
|
|
@pytest.fixture
|
|
def sample_payload(self):
|
|
return {
|
|
"message_id": "msg123",
|
|
"channel_type": "web",
|
|
"content": "Hello",
|
|
"sender_id": "user1",
|
|
"session_id": "session123",
|
|
"trace_id": "trace123",
|
|
"metadata": {"deliver": True},
|
|
"attachments": [{"url": "http://example.com/image.png", "media_type": "image"}],
|
|
}
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_success(self, delivery_service, sample_payload, sample_session):
|
|
result = await delivery_service.deliver(sample_payload, sample_session)
|
|
assert result.success is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_no_deliver(self, delivery_service, mock_message_repo, sample_payload, sample_session):
|
|
sample_payload["metadata"]["deliver"] = False
|
|
result = await delivery_service.deliver(sample_payload, sample_session)
|
|
assert result.success is True
|
|
mock_message_repo.save_assistant_message.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_agent_crash(self, delivery_service, mock_agent_port, sample_payload, sample_session):
|
|
mock_agent_port.stream_chat.side_effect = AgentCrashError("agent crashed")
|
|
result = await delivery_service.deliver(sample_payload, sample_session)
|
|
assert result.success is False
|
|
assert result.error == "agent_crash"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_send_failure(self, delivery_service, mock_adapters, mock_outbox_repo, sample_payload, sample_session):
|
|
mock_adapters["web"].send_message.return_value = SendResult(success=False, error="send failed")
|
|
result = await delivery_service.deliver(sample_payload, sample_session)
|
|
mock_outbox_repo.enqueue.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_no_adapter(self, delivery_service, sample_payload, sample_session):
|
|
sample_payload["channel_type"] = "unknown"
|
|
result = await delivery_service.deliver(sample_payload, sample_session)
|
|
assert result.success is False
|
|
assert "no adapter" in result.error
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_publishes_event(self, delivery_service, mock_event_publisher, sample_payload, sample_session):
|
|
await delivery_service.deliver(sample_payload, sample_session)
|
|
mock_event_publisher.publish.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_saves_message(self, delivery_service, mock_message_repo, sample_payload, sample_session):
|
|
await delivery_service.deliver(sample_payload, sample_session)
|
|
mock_message_repo.save_assistant_message.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_with_media(self, delivery_service, mock_adapters, sample_payload, sample_session):
|
|
await delivery_service.deliver(sample_payload, sample_session)
|
|
mock_adapters["web"].send_media.assert_awaited_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_typing_indicator(self, delivery_service, mock_adapters, sample_payload, sample_session):
|
|
mock_adapters["web"].capabilities.typing = True
|
|
await delivery_service.deliver(sample_payload, sample_session)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_call_agent_timeout(self, delivery_service, mock_agent_port, sample_payload, sample_session):
|
|
mock_agent_port.stream_chat.side_effect = TimeoutError("timeout")
|
|
with pytest.raises(AgentCrashError):
|
|
await delivery_service._call_agent(sample_payload, sample_session, "Hello", "web", "msg123", "trace123")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_try_send_success(self, delivery_service, mock_adapters, sample_session):
|
|
result = await delivery_service._try_send(
|
|
mock_adapters["web"], "thread123", "Hello", "web", "trace123", "msg123"
|
|
)
|
|
assert result.success is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_try_send_failure(self, delivery_service, mock_adapters, sample_session):
|
|
mock_adapters["web"].send_message.side_effect = Exception("send error")
|
|
result = await delivery_service._try_send(
|
|
mock_adapters["web"], "thread123", "Hello", "web", "trace123", "msg123"
|
|
)
|
|
assert result.success is False
|