ForcePilot/backend/test/unit/channel/channels/feishu/test_feishu.py
Kris 9e503becd3
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat(plugin): 实现完整的插件注册管理系统
新增了插件相关的完整领域模型、应用服务、基础设施实现,包括:
1. 插件状态、注册模式、来源等基础枚举和数据结构
2. 插件清单解析、发现、加载工具类
3. 插件注册表领域服务和内存存储实现
4. 插件相关的命令、查询、事件定义
5. 插件REST API接口和DTO映射
6. 集成了原有通道适配器到插件系统
7. 新增内置插件注册和自动发现能力
2026-05-31 16:44:13 +08:00

241 lines
8.5 KiB
Python

from __future__ import annotations
import pytest
from yuxi.channel.channels.feishu.adapter import FeishuAdapter
from yuxi.channel.channels.feishu.config import FeishuConfig
from yuxi.channel.channels.feishu.translator import FeishuTranslator, _extract_attachments, _extract_text
from yuxi.channel.domain.model.shared.channel_type import ChannelType
class TestFeishuTranslator:
def test_translate_p2p_message(self) -> None:
raw = {
"event": {
"message": {
"message_id": "msg-001",
"content": '{"text": "hello"}',
"chat_type": "p2p",
},
"sender": {
"sender_id": {"user_id": "ou-123"},
},
}
}
msg = FeishuTranslator.translate_event(raw)
assert msg.message_id == "msg-001"
assert msg.content == "hello"
assert msg.channel_type == ChannelType.FEISHU
assert msg.sender.id == "ou-123"
assert msg.metadata["is_group"] is False
def test_translate_group_message(self) -> None:
raw = {
"event": {
"message": {
"message_id": "msg-002",
"content": '{"text": "group hello"}',
"chat_type": "group",
"chat_id": "oc-456",
},
"sender": {
"sender_id": {"user_id": "ou-789"},
},
}
}
msg = FeishuTranslator.translate_event(raw)
assert msg.metadata["is_group"] is True
assert msg.metadata["group_id"] == "oc-456"
def test_translate_missing_fields_defaults(self) -> None:
raw = {}
msg = FeishuTranslator.translate_event(raw)
assert msg.message_id == ""
assert msg.content == ""
def test_translate_image_attachment(self) -> None:
raw = {
"event": {
"message": {
"message_id": "msg-img",
"content": '{"image_key": "img_key_123"}',
"message_type": "image",
"chat_type": "p2p",
},
"sender": {"sender_id": {"user_id": "u1"}},
}
}
msg = FeishuTranslator.translate_event(raw)
assert len(msg.attachments) == 1
assert msg.attachments[0].url == "img_key_123"
assert msg.attachments[0].media_type == "image"
def test_translate_file_attachment(self) -> None:
raw = {
"event": {
"message": {
"message_id": "msg-file",
"content": '{"file_key": "fk_123", "file_name": "doc.pdf"}',
"message_type": "file",
"chat_type": "p2p",
},
"sender": {"sender_id": {"user_id": "u1"}},
}
}
msg = FeishuTranslator.translate_event(raw)
assert len(msg.attachments) == 1
assert msg.attachments[0].url == "fk_123"
assert msg.attachments[0].filename == "doc.pdf"
assert msg.attachments[0].media_type == "file"
class TestExtractText:
def test_json_text_field(self) -> None:
message = {"content": '{"text": "hello"}'}
assert _extract_text(message) == "hello"
def test_empty_content(self) -> None:
message = {"content": ""}
assert _extract_text(message) == ""
def test_invalid_json_returns_raw(self) -> None:
message = {"content": "not-json"}
assert _extract_text(message) == "not-json"
def test_dict_without_text_returns_raw(self) -> None:
message = {"content": {"other": "value"}}
assert _extract_text(message) == {"other": "value"}
class TestExtractAttachments:
def test_image_type(self) -> None:
body = {
"event": {
"message": {
"message_type": "image",
"content": '{"image_key": "ik_1"}',
}
}
}
attachments = _extract_attachments(body)
assert len(attachments) == 1
assert attachments[0].media_type == "image"
def test_file_type(self) -> None:
body = {
"event": {
"message": {
"message_type": "file",
"content": '{"file_key": "fk_1", "file_name": "a.txt"}',
}
}
}
attachments = _extract_attachments(body)
assert len(attachments) == 1
assert attachments[0].media_type == "file"
assert attachments[0].filename == "a.txt"
def test_text_type_no_attachment(self) -> None:
body = {
"event": {
"message": {
"message_type": "text",
"content": '{"text": "hi"}',
}
}
}
assert _extract_attachments(body) == []
def test_invalid_json_no_attachment(self) -> None:
body = {
"event": {
"message": {
"message_type": "image",
"content": "not-json",
}
}
}
assert _extract_attachments(body) == []
class TestFeishuConfig:
def test_defaults(self) -> None:
config = FeishuConfig()
assert config.app_id == ""
assert config.app_secret == ""
assert config.verification_token == ""
assert config.ws_enabled is True
def test_with_values(self) -> None:
config = FeishuConfig(app_id="id1", app_secret="s1", verification_token="vt1", ws_enabled=False)
assert config.app_id == "id1"
assert config.verification_token == "vt1"
class TestFeishuAdapter:
def test_channel_type(self) -> None:
adapter = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
assert adapter.channel_type == ChannelType.FEISHU.value
def test_get_default_config(self) -> None:
config = FeishuAdapter.get_default_config()
assert "app_id" in config
assert "app_secret" in config
assert "verification_token" in config
@pytest.mark.asyncio
async def test_is_healthy_before_open(self) -> None:
adapter = FeishuAdapter(app_id="test", app_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 = FeishuAdapter(app_id="test", app_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 = FeishuAdapter(app_id="test", app_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 = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
raw = {
"event": {
"message": {"message_id": "m1", "content": '{"text": "hi"}', "chat_type": "p2p"},
"sender": {"sender_id": {"user_id": "u1"}},
}
}
msg = await adapter.receive_message(raw)
assert msg.message_id == "m1"
@pytest.mark.asyncio
async def test_send_typing_is_noop(self) -> None:
adapter = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
await adapter.send_typing("session-1")
@pytest.mark.asyncio
async def test_send_media_returns_false(self) -> None:
adapter = FeishuAdapter(app_id="test", app_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_client_returns_failure(self) -> None:
adapter = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
result = await adapter.send_message("session-1", "hello", channel_type="feishu", metadata={})
assert result.success is False
def test_ws_connection_is_none_when_disabled(self) -> None:
adapter = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
assert adapter.ws_connection is None
def test_route_contributor_has_router(self) -> None:
adapter = FeishuAdapter(app_id="test", app_secret="test", ws_enabled=False)
contributor = adapter.route_contributor
assert contributor.router is not None