ForcePilot/backend/test/unit/channels/test_doctor.py
Kris 3264900bc9 test: 新增多渠道单元测试用例并配置测试环境变量
新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块
同时在测试配置中添加了测试用的OpenAI API密钥环境变量
2026-05-12 00:56:47 +08:00

129 lines
4.4 KiB
Python

from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock
import pytest
from yuxi.channels.services.doctor import ConfigDoctor, DiagnosisIssue
class TestDiagnosisIssue:
def test_create_issue(self):
issue = DiagnosisIssue(
severity="error",
channel_id="wx",
category="credential",
message="Missing app_id",
)
assert issue.severity == "error"
assert issue.channel_id == "wx"
assert issue.category == "credential"
assert issue.message == "Missing app_id"
assert issue.auto_fixable is False
def test_auto_fixable_flag(self):
issue = DiagnosisIssue(
severity="warning",
channel_id="tg",
category="connectivity",
message="Timeout",
auto_fixable=True,
)
assert issue.auto_fixable is True
def _make_channel_manager_mock():
manager = MagicMock()
manager._registry = MagicMock()
manager._registry.list_channels.return_value = ["wx", "tg"]
manager._registry.get.return_value = MagicMock()
manager._channels_config = {
"wx": {
"enabled": True,
"required_fields": ["app_id", "app_secret"],
"app_id": "test_id",
},
"tg": {
"enabled": True,
"token": "test_token",
},
}
manager._adapters = {}
return manager
class TestConfigDoctor:
@pytest.mark.asyncio
async def test_diagnose_all_channels(self):
manager = _make_channel_manager_mock()
doctor = ConfigDoctor(manager)
issues = await doctor.diagnose()
assert len(issues) >= 1
@pytest.mark.asyncio
async def test_diagnose_single_channel(self):
manager = _make_channel_manager_mock()
doctor = ConfigDoctor(manager)
issues = await doctor.diagnose(channel_id="wx")
missing_secret = [i for i in issues if "app_secret" in i.message]
assert len(missing_secret) == 1
assert missing_secret[0].severity == "error"
assert missing_secret[0].category == "credential"
@pytest.mark.asyncio
async def test_diagnose_missing_required_fields(self):
manager = _make_channel_manager_mock()
manager._channels_config["wx"]["required_fields"] = ["app_id", "app_secret", "token"]
doctor = ConfigDoctor(manager)
issues = await doctor.diagnose(channel_id="wx")
credential_issues = [i for i in issues if i.category == "credential"]
assert any("app_secret" in i.message for i in credential_issues)
assert any("token" in i.message for i in credential_issues)
assert not any("app_id" in i.message for i in credential_issues)
@pytest.mark.asyncio
async def test_diagnose_no_adapter_registered(self):
manager = MagicMock()
manager._registry.list_channels.return_value = ["unknown"]
manager._registry.get.return_value = None
manager._channels_config = {"unknown": {"enabled": True}}
manager._adapters = {}
doctor = ConfigDoctor(manager)
issues = await doctor.diagnose(channel_id="unknown")
registry_issues = [i for i in issues if i.category == "registry"]
assert len(registry_issues) == 1
assert registry_issues[0].severity == "error"
@pytest.mark.asyncio
async def test_auto_fix_non_fixable_returns_false(self):
manager = _make_channel_manager_mock()
doctor = ConfigDoctor(manager)
issue = DiagnosisIssue(
severity="error", channel_id="wx", category="credential", message="missing", auto_fixable=False
)
result = await doctor.auto_fix(issue)
assert result is False
@pytest.mark.asyncio
async def test_auto_fix_connectivity_restarts_channel(self):
manager = _make_channel_manager_mock()
manager.restart_channel = AsyncMock()
doctor = ConfigDoctor(manager)
issue = DiagnosisIssue(
severity="error", channel_id="wx", category="connectivity", message="timeout", auto_fixable=True
)
result = await doctor.auto_fix(issue)
assert result is True
manager.restart_channel.assert_called_once_with("wx")
@pytest.mark.asyncio
async def test_suggest_migration_returns_empty_list(self):
manager = _make_channel_manager_mock()
doctor = ConfigDoctor(manager)
suggestions = await doctor.suggest_migration()
assert suggestions == []