Files
MoviePilot/tests/test_discord_command_registration.py
T
jxxghp 7e851dbfa7 refactor(chain): 处理链功能域 mixin 化,清理未使用导入并根治兼容层循环导入
- ChainBase 拆分为 RecognitionMixin/MessageProcessingMixin/NotificationMixin
- TransferChain 拆分为 7 个功能 mixin(_mixins.py),SubscribeChain 音乐订阅域拆出 _music.py
- 斜杠命令交互四件套收敛为 InteractionChainMixin 委托,会话管理器移至 application 层,chain 层不再 re-export
- 模块基础类收敛到 app/modules/_base(notification/mediaserver 语义重命名)
- 清理 app/chain/__init__.py 24 个未使用导入,修正 49 处测试 patch 目标到实际命名空间
- 兼容层 legacy 符号不再并入 __all__,根治 schemas 初始化反向拉起 application.transfer 的循环导入
- 修复 bangumi 集数为字符串时 set_bangumi_info 抛 TypeError
- 新增重复代码等架构门禁测试;capability 清单校验排除下划线内部目录
2026-08-16 16:30:16 +08:00

119 lines
4.3 KiB
Python

import asyncio
from types import SimpleNamespace
from unittest.mock import AsyncMock, Mock, patch
from app.modules.discord import DiscordModule
from app.modules.discord.discord import Discord
from app.schemas import CommandRegisterEventData
def test_discord_module_register_commands_filters_event_subset():
"""Discord 模块注册命令时应复用渠道级 CommandRegister 事件过滤结果。"""
module = DiscordModule()
client = SimpleNamespace(register_commands=Mock(), delete_commands=Mock())
original_commands = {
"/sites": {"description": "管理站点"},
"/version": {"description": "当前版本"},
}
event = SimpleNamespace(
event_data=CommandRegisterEventData(
commands={"/sites": {"description": "管理站点"}, "/unknown": {"description": "无效"}},
origin="DiscordFilter",
service="discord-main",
)
)
with (
patch.object(
module,
"get_configs",
return_value={"discord-main": SimpleNamespace(name="discord-main", config={})},
),
patch.object(module, "get_instance", return_value=client),
patch("app.modules._base.notification.eventmanager.send_event", return_value=event),
):
module.register_commands(original_commands)
client.register_commands.assert_called_once_with(
{"/sites": {"description": "管理站点"}}
)
client.delete_commands.assert_not_called()
def test_discord_module_register_commands_deletes_when_event_canceled():
"""Discord 模块注册命令被事件取消时应清理应用命令。"""
module = DiscordModule()
client = SimpleNamespace(register_commands=Mock(), delete_commands=Mock())
event = SimpleNamespace(
event_data=CommandRegisterEventData(
commands={"/sites": {"description": "管理站点"}},
origin="DiscordFilter",
service="discord-main",
cancel=True,
)
)
with (
patch.object(
module,
"get_configs",
return_value={"discord-main": SimpleNamespace(name="discord-main", config={})},
),
patch.object(module, "get_instance", return_value=client),
patch("app.modules._base.notification.eventmanager.send_event", return_value=event),
):
module.register_commands({"/sites": {"description": "管理站点"}})
client.delete_commands.assert_called_once_with()
client.register_commands.assert_not_called()
def test_discord_normalizes_slash_command_names():
"""Discord 命令名称应符合平台只允许小写字母数字下划线连字符的约束。"""
assert Discord._normalize_slash_command_name("/sites") == "sites"
assert Discord._normalize_slash_command_name("/clear_cache") == "clear_cache"
assert Discord._normalize_slash_command_name("/INVALID") == "invalid"
assert Discord._normalize_slash_command_name("/中文") == ""
assert Discord._normalize_slash_command_name("/" + "a" * 33) == ""
def test_discord_handle_slash_command_forwards_to_message_chain():
"""Discord 斜杠命令回调应转发为统一消息入口可识别的命令文本。"""
client = Discord.__new__(Discord)
client._update_user_chat_mapping = Mock()
client._post_to_ds = AsyncMock()
user = SimpleNamespace(id=10001, display_name="tester", global_name=None, name="tester")
channel = SimpleNamespace(id=20001)
interaction = SimpleNamespace(
id=30001,
user=user,
channel=channel,
response=SimpleNamespace(
defer=AsyncMock(),
is_done=Mock(return_value=True),
send_message=AsyncMock(),
),
followup=SimpleNamespace(send=AsyncMock()),
)
asyncio.run(client._handle_slash_command(interaction, "/sites", "refresh"))
client._update_user_chat_mapping.assert_called_once_with("10001", "20001")
client._post_to_ds.assert_awaited_once_with(
{
"type": "message",
"userid": "10001",
"username": "tester",
"user_tag": str(user),
"text": "/sites refresh",
"message_id": "30001",
"chat_id": "20001",
"channel_type": "guild",
}
)
interaction.followup.send.assert_awaited_once_with(
"命令已提交,请稍等...",
ephemeral=True,
)