新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块 同时在测试配置中添加了测试用的OpenAI API密钥环境变量
120 lines
3.8 KiB
Python
120 lines
3.8 KiB
Python
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from yuxi.channels.infra.config_watcher import ConfigWatcher
|
|
|
|
|
|
class TestConfigWatcherInit:
|
|
def test_default_values(self):
|
|
manager = MagicMock()
|
|
watcher = ConfigWatcher(manager)
|
|
assert watcher._last_config_hash is None
|
|
assert watcher._watched_prefixes == ["channels"]
|
|
assert watcher._noop_prefixes == []
|
|
assert watcher._running is False
|
|
|
|
def test_set_watched_prefixes(self):
|
|
manager = MagicMock()
|
|
watcher = ConfigWatcher(manager)
|
|
watcher.set_watched_prefixes(["channels.wechat", "channels.telegram"])
|
|
assert watcher._watched_prefixes == ["channels.wechat", "channels.telegram"]
|
|
|
|
def test_set_noop_prefixes(self):
|
|
manager = MagicMock()
|
|
watcher = ConfigWatcher(manager)
|
|
watcher.set_noop_prefixes(["channels.wechat.logLevel"])
|
|
assert watcher._noop_prefixes == ["channels.wechat.logLevel"]
|
|
|
|
|
|
class TestConfigWatcherCompute:
|
|
def test_compute_config_hash_consistent(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {"wx": {"enabled": True}}
|
|
watcher = ConfigWatcher(manager)
|
|
|
|
h1 = watcher._compute_config_hash()
|
|
h2 = watcher._compute_config_hash()
|
|
assert h1 == h2
|
|
|
|
def test_compute_config_hash_changes_with_config(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {"wx": {"enabled": True}}
|
|
watcher = ConfigWatcher(manager)
|
|
|
|
h1 = watcher._compute_config_hash()
|
|
manager._channels_config = {"wx": {"enabled": False}}
|
|
h2 = watcher._compute_config_hash()
|
|
assert h1 != h2
|
|
|
|
|
|
class TestConfigWatcherDiff:
|
|
def test_compute_diff_new_channel(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {"wx": {"enabled": True}}
|
|
manager._adapters = {}
|
|
watcher = ConfigWatcher(manager)
|
|
|
|
diff = watcher._compute_config_diff()
|
|
assert diff == {"wx": {"action": "start", "config": {"enabled": True}}}
|
|
|
|
def test_compute_diff_stopped_channel(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {}
|
|
manager._adapters = {"wx": MagicMock()}
|
|
watcher = ConfigWatcher(manager)
|
|
|
|
diff = watcher._compute_config_diff()
|
|
assert diff == {"wx": {"action": "stop"}}
|
|
|
|
def test_compute_diff_changed_channel(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {"wx": {"enabled": True}}
|
|
manager._adapters = {"wx": MagicMock()}
|
|
watcher = ConfigWatcher(manager)
|
|
|
|
diff = watcher._compute_config_diff()
|
|
assert diff == {"wx": {"action": "restart"}}
|
|
|
|
|
|
class TestConfigWatcherLifecycle:
|
|
@pytest.mark.asyncio
|
|
async def test_watch_starts_and_stops(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {}
|
|
manager._adapters = {}
|
|
|
|
watcher = ConfigWatcher(manager)
|
|
await watcher.watch(interval=60.0)
|
|
assert watcher._running is True
|
|
assert watcher._task is not None
|
|
|
|
await watcher.stop()
|
|
assert watcher._running is False
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_watch_idempotent(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {}
|
|
manager._adapters = {}
|
|
|
|
watcher = ConfigWatcher(manager)
|
|
await watcher.watch(interval=60.0)
|
|
task1 = watcher._task
|
|
await watcher.watch(interval=60.0)
|
|
assert watcher._task is task1
|
|
|
|
await watcher.stop()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reload_now_no_keys(self):
|
|
manager = MagicMock()
|
|
manager._channels_config = {"wx": {"enabled": True}}
|
|
manager._adapters = {}
|
|
manager.start_channel = AsyncMock()
|
|
|
|
watcher = ConfigWatcher(manager)
|
|
result = await watcher.reload_now()
|
|
assert "wx" in result |