新增了插件相关的完整领域模型、应用服务、基础设施实现,包括: 1. 插件状态、注册模式、来源等基础枚举和数据结构 2. 插件清单解析、发现、加载工具类 3. 插件注册表领域服务和内存存储实现 4. 插件相关的命令、查询、事件定义 5. 插件REST API接口和DTO映射 6. 集成了原有通道适配器到插件系统 7. 新增内置插件注册和自动发现能力
140 lines
5.3 KiB
Python
140 lines
5.3 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from yuxi.channel.channels.dingtalk.adapter import DingTalkAdapter
|
|
from yuxi.channel.channels.dingtalk.config import DingTalkConfig
|
|
from yuxi.channel.channels.dingtalk.translator import DingTalkTranslator
|
|
from yuxi.channel.domain.model.shared.channel_type import ChannelType
|
|
|
|
|
|
class TestDingTalkTranslator:
|
|
def test_translate_p2p_message(self) -> None:
|
|
raw = {
|
|
"event": {
|
|
"message": {
|
|
"message_id": "msg-001",
|
|
"content": "hello",
|
|
"chat_type": "p2p",
|
|
},
|
|
"sender": {
|
|
"sender_id": {"user_id": "user-123"},
|
|
},
|
|
}
|
|
}
|
|
msg = DingTalkTranslator.translate_event(raw)
|
|
assert msg.message_id == "msg-001"
|
|
assert msg.content == "hello"
|
|
assert msg.channel_type == ChannelType.DINGTALK
|
|
assert msg.sender.id == "user-123"
|
|
assert msg.metadata["is_group"] is False
|
|
assert msg.metadata["group_id"] == ""
|
|
|
|
def test_translate_group_message(self) -> None:
|
|
raw = {
|
|
"event": {
|
|
"message": {
|
|
"message_id": "msg-002",
|
|
"content": "group hello",
|
|
"chat_type": "group",
|
|
"chat_id": "chat-456",
|
|
},
|
|
"sender": {
|
|
"sender_id": {"user_id": "user-789"},
|
|
},
|
|
}
|
|
}
|
|
msg = DingTalkTranslator.translate_event(raw)
|
|
assert msg.metadata["is_group"] is True
|
|
assert msg.metadata["group_id"] == "chat-456"
|
|
|
|
def test_translate_missing_fields_defaults(self) -> None:
|
|
raw = {}
|
|
msg = DingTalkTranslator.translate_event(raw)
|
|
assert msg.message_id == ""
|
|
assert msg.content == ""
|
|
assert msg.sender.id == ""
|
|
|
|
|
|
class TestDingTalkConfig:
|
|
def test_defaults(self) -> None:
|
|
config = DingTalkConfig()
|
|
assert config.client_id == ""
|
|
assert config.client_secret == ""
|
|
assert config.ws_enabled is True
|
|
|
|
def test_with_values(self) -> None:
|
|
config = DingTalkConfig(client_id="id1", client_secret="secret1", ws_enabled=False)
|
|
assert config.client_id == "id1"
|
|
assert config.client_secret == "secret1"
|
|
assert config.ws_enabled is False
|
|
|
|
|
|
class TestDingTalkAdapter:
|
|
def test_channel_type(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
assert adapter.channel_type == ChannelType.DINGTALK.value
|
|
|
|
def test_get_default_config(self) -> None:
|
|
config = DingTalkAdapter.get_default_config()
|
|
assert "client_id" in config
|
|
assert "client_secret" in config
|
|
assert "ws_enabled" in config
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_is_healthy_before_open(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
assert await adapter.is_healthy() is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_is_healthy_after_open(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
await adapter.open()
|
|
assert await adapter.is_healthy() is True
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_close(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
await adapter.open()
|
|
await adapter.close()
|
|
assert await adapter.is_healthy() is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_receive_message(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
raw = {
|
|
"event": {
|
|
"message": {"message_id": "m1", "content": "hi", "chat_type": "p2p"},
|
|
"sender": {"sender_id": {"user_id": "u1"}},
|
|
}
|
|
}
|
|
msg = await adapter.receive_message(raw)
|
|
assert msg.message_id == "m1"
|
|
assert msg.content == "hi"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_typing_is_noop(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
await adapter.send_typing("session-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_media_returns_false(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
result = await adapter.send_media("session-1", url="http://x", media_type="image", metadata={})
|
|
assert result is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_message_without_token_returns_failure(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
result = await adapter.send_message("session-1", "hello", channel_type="dingtalk", metadata={})
|
|
assert result.success is False
|
|
|
|
def test_ws_connection_is_none_when_disabled(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
assert adapter.ws_connection is None
|
|
|
|
def test_route_contributor_has_router(self) -> None:
|
|
adapter = DingTalkAdapter(client_id="test", client_secret="test", ws_enabled=False)
|
|
contributor = adapter.route_contributor
|
|
assert contributor.router is not None
|