* 滚木

* 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: 更新依赖项
This commit is contained in:
镀铬酸钾
2026-01-09 00:20:56 +08:00
committed by GitHub
parent 6d7dfc179d
commit fa81229f6f
42 changed files with 1461 additions and 697 deletions

View File

@@ -0,0 +1,114 @@
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