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

167 lines
6.2 KiB
Python

from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from yuxi.channels.manager import ChannelManager
from yuxi.channels.registry import ChannelRegistry
from yuxi.channels.services.runtime_state import RuntimeState
class TestChannelManagerPhases:
def test_initial_phase(self):
manager = ChannelManager()
assert manager.phase == "not_started"
@pytest.mark.asyncio
async def test_load_config_sets_phase(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
manager = ChannelManager()
await manager.load_config()
assert manager.phase == "config_loaded"
@pytest.mark.asyncio
async def test_load_config_idempotent(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
manager = ChannelManager()
await manager.load_config()
mock_config.channels = {"wx": {"enabled": True}}
await manager.load_config()
assert manager._channels_config == {}
@pytest.mark.asyncio
async def test_initialize_sets_fully_running(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
mock_pg = MagicMock()
mock_db = AsyncMock()
mock_pg.__aenter__ = AsyncMock(return_value=mock_db)
mock_pg.__aexit__ = AsyncMock(return_value=None)
with (
patch(
"yuxi.channels.manager.pg_manager.get_async_session_context",
return_value=mock_pg,
),
patch.object(ChannelManager, "_ensure_virtual_department", AsyncMock()),
patch.object(ChannelManager, "_ensure_default_agent_config", AsyncMock()),
):
manager = ChannelManager()
await manager.initialize()
assert manager.phase == "fully_running"
assert manager._initialized is True
@pytest.mark.asyncio
async def test_start_subscriptions_only_after_channels_started(self):
manager = ChannelManager()
assert manager.phase == "not_started"
await manager.start_subscriptions()
assert manager.phase == "not_started"
@pytest.mark.asyncio
async def test_prepare_bootstrap_only_after_config_loaded(self):
manager = ChannelManager()
await manager.prepare_bootstrap()
assert manager.phase == "not_started"
@pytest.mark.asyncio
async def test_start_channels_allows_from_config_loaded_or_bootstrapped(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
registry = ChannelRegistry()
manager = ChannelManager(registry=registry)
await manager.load_config()
assert manager.phase == "config_loaded"
await manager.start_channels()
assert manager.phase == "channels_started"
@pytest.mark.asyncio
async def test_startup_idempotent(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
manager = ChannelManager()
manager._initialized = True
await manager.startup()
assert manager.phase == "not_started"
@pytest.mark.asyncio
async def test_startup_creates_context(self):
with (
patch("yuxi.channels.manager._load_builtin_adapters"),
patch("yuxi.channels.manager._BUILTIN_ADAPTERS", {}),
patch("yuxi.config") as mock_config,
):
mock_config.channels = {}
mock_pg = MagicMock()
mock_db = AsyncMock()
mock_pg.__aenter__ = AsyncMock(return_value=mock_db)
mock_pg.__aexit__ = AsyncMock(return_value=None)
with (
patch(
"yuxi.channels.manager.pg_manager.get_async_session_context",
return_value=mock_pg,
),
patch.object(ChannelManager, "_ensure_virtual_department", AsyncMock()),
patch.object(ChannelManager, "_ensure_default_agent_config", AsyncMock()),
):
manager = ChannelManager()
await manager.startup()
assert manager.context is not None
assert manager.broadcaster is not None
assert manager.watcher is not None
assert manager.doctor is not None
assert manager.phase == "fully_running"
def test_new_properties_default(self):
manager = ChannelManager()
assert manager.context is None
assert manager.broadcaster is None
assert manager.watcher is None
assert manager.doctor is None
assert isinstance(manager.runtime_state, RuntimeState)
assert manager.runtime_state.phase == "not_started"
@pytest.mark.asyncio
async def test_diagnose_channels_no_doctor(self):
manager = ChannelManager()
issues = await manager.diagnose_channels()
assert issues == []
@pytest.mark.asyncio
async def test_auto_fix_no_doctor(self):
manager = ChannelManager()
result = await manager.auto_fix_channel(None)
assert result is False
@pytest.mark.asyncio
async def test_reload_config_no_watcher(self):
manager = ChannelManager()
result = await manager.reload_config_now()
assert result == {}