* 滚木 * feat: 重构核心架构,增强类型安全与插件管理 本次提交对核心模块进行了深度重构,引入 Pydantic 增强配置管理的类型安全性,并全面优化了插件管理系统。 主要变更详情: 1. 核心架构与配置 - 重构配置加载模块:引入 Pydantic 模型 (`core/config_models.py`),提供严格的配置项类型检查、验证及默认值管理。 - 统一模块结构:规范化模块导入路径,移除冗余的 `__init__.py` 文件,提升项目结构的清晰度。 - 性能优化:集成 Redis 缓存支持 (`RedisManager`),有效降低高频 API 调用开销,提升响应速度。 2. 插件系统升级 - 实现热重载机制:新增插件文件变更监听功能,支持开发过程中自动重载插件,提升开发效率。 - 优化生命周期管理:改进插件加载与卸载逻辑,支持精确卸载指定插件及其关联的命令、事件处理器和定时任务。 3. 功能特性增强 - 新增媒体 API:引入 `MediaAPI` 模块,封装图片、语音等富媒体资源的获取与处理接口。 - 完善权限体系:重构权限管理系统,实现管理员与操作员的分级控制,支持更细粒度的命令权限校验。 4. 代码质量与稳定性 - 全面类型修复:解决 `mypy` 静态类型检查发现的大量类型错误(包括 `CommandManager`、`EventFactory` 及 `Bot` API 签名不匹配问题)。 - 增强错误处理:优化消息处理管道的异常捕获机制,完善关键路径的日志记录,提升系统运行稳定性。 * feat: 添加测试用例并优化代码结构 refactor(permission_manager): 调整初始化顺序和逻辑 fix(admin_manager): 修复初始化逻辑和目录创建问题 feat(ws): 优化Bot实例初始化条件 feat(message): 增强MessageSegment功能并添加测试 feat(events): 支持字符串格式的消息解析 test: 添加核心功能测试用例 refactor(plugin_manager): 改进插件路径处理 style: 清理无用导入和代码 chore: 更新依赖项
115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
import pytest
|
|
import asyncio
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
from core.managers.command_manager import CommandManager
|
|
from models.events.message import GroupMessageEvent
|
|
from models.message import MessageSegment
|
|
|
|
@pytest.fixture
|
|
def mock_bot():
|
|
bot = AsyncMock()
|
|
bot.self_id = 123456
|
|
return bot
|
|
|
|
@pytest.fixture
|
|
def command_manager():
|
|
# 创建一个新的 CommandManager 实例用于测试,避免单例状态污染
|
|
return CommandManager(prefixes=("/",))
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_registration_and_execution(command_manager, mock_bot):
|
|
"""测试命令注册和执行"""
|
|
|
|
# 定义一个命令处理函数
|
|
handler_mock = AsyncMock()
|
|
|
|
# 注册命令
|
|
@command_manager.command("test")
|
|
async def test_command(bot, event):
|
|
await handler_mock(bot, event)
|
|
|
|
# 构造触发命令的事件
|
|
event = MagicMock(spec=GroupMessageEvent)
|
|
event.post_type = "message"
|
|
event.message_type = "group"
|
|
event.raw_message = "/test"
|
|
event.message = [MessageSegment.text("/test")]
|
|
event.user_id = 111
|
|
event.group_id = 222
|
|
|
|
# 处理事件
|
|
await command_manager.handle_event(mock_bot, event)
|
|
|
|
# 验证处理函数被调用
|
|
handler_mock.assert_called_once_with(mock_bot, event)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_prefix_match(command_manager, mock_bot):
|
|
"""测试命令前缀匹配"""
|
|
handler_mock = AsyncMock()
|
|
|
|
@command_manager.command("hello")
|
|
async def hello_command(bot, event):
|
|
await handler_mock(bot, event)
|
|
|
|
# 1. 正确的前缀
|
|
event1 = MagicMock(spec=GroupMessageEvent)
|
|
event1.post_type = "message"
|
|
event1.raw_message = "/hello"
|
|
event1.message = [MessageSegment.text("/hello")]
|
|
await command_manager.handle_event(mock_bot, event1)
|
|
handler_mock.assert_called_once()
|
|
handler_mock.reset_mock()
|
|
|
|
# 2. 错误的前缀 (应该忽略)
|
|
event2 = MagicMock(spec=GroupMessageEvent)
|
|
event2.post_type = "message"
|
|
event2.raw_message = ".hello" # 假设前缀是 /
|
|
event2.message = [MessageSegment.text(".hello")]
|
|
await command_manager.handle_event(mock_bot, event2)
|
|
handler_mock.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ignore_self_message(command_manager, mock_bot):
|
|
"""测试忽略自身消息"""
|
|
# 模拟配置
|
|
with patch("core.managers.command_manager.global_config") as mock_config:
|
|
mock_config.bot.ignore_self_message = True
|
|
|
|
event = MagicMock(spec=GroupMessageEvent)
|
|
event.post_type = "message"
|
|
event.user_id = 123456 # 与 bot.self_id 相同
|
|
event.self_id = 123456
|
|
|
|
# Mock handle 方法来检测是否被调用
|
|
command_manager.message_handler.handle = AsyncMock()
|
|
|
|
await command_manager.handle_event(mock_bot, event)
|
|
|
|
# 应该直接返回,不调用 handler
|
|
command_manager.message_handler.handle.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_help_command(command_manager, mock_bot):
|
|
"""测试内置 help 命令"""
|
|
# 注册一个测试插件信息
|
|
command_manager.plugins["test_plugin"] = {
|
|
"name": "测试插件",
|
|
"description": "这是一个测试",
|
|
"usage": "/test"
|
|
}
|
|
|
|
event = MagicMock(spec=GroupMessageEvent)
|
|
event.post_type = "message"
|
|
event.raw_message = "/help"
|
|
event.message = [MessageSegment.text("/help")]
|
|
|
|
await command_manager.handle_event(mock_bot, event)
|
|
|
|
# 验证 bot.send 被调用,且内容包含插件信息
|
|
mock_bot.send.assert_called_once()
|
|
args, _ = mock_bot.send.call_args
|
|
sent_msg = args[1]
|
|
assert "测试插件" in sent_msg
|
|
assert "这是一个测试" in sent_msg
|