mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-14 21:52:56 +08:00
* ✨ feat(env): 支持git更新 * ✨ feat(aliyun): 更新阿里云URL构建逻辑,支持组织名称并优化令牌解码处理 * ✨ feat(config): 修改错误提示信息,更新基础配置文件名称为.env.example * ⚡ 插件商店支持aliyun * ✨ feat(store): 优化插件数据获取逻辑,合并插件列表和额外插件列表 * 🐛 修复非git仓库的初始化更新 * ✨ feat(update): 增强更新提示信息,添加非git源的变更文件说明 * 🎨 代码格式化 * ✨ webui与resources支持git更新 * ✨ feat(update): 更新webui路径处理逻辑 * Fix/test_runwork (#2001) * fix(test): 修复测试工作流 - 修改自动更新模块中的导入路径 - 更新插件商店模块中的插件信息获取逻辑 - 优化插件添加、更新和移除流程 - 统一插件相关错误信息的格式 - 调整测试用例以适应新的插件管理逻辑 * test(builtin_plugins): 重构插件商店相关测试 - 移除 jsd 相关测试用例,只保留 gh(GitHub)的测试 - 删除了 test_plugin_store.py 文件,清理了插件商店的测试 - 更新了 test_search_plugin.py 中的插件版本号 - 调整了 test_update_plugin.py 中的已加载插件版本 - 移除了 StoreManager 类中的 is_external 变量 - 更新了 RepoFileManager 类中的文件获取逻辑,优先使用 GitHub * ✨ feat(submodule): 添加子模块管理功能,支持子模块的初始化、更新和信息获取 * ✨ feat(update): 移除资源管理器,重构更新逻辑,支持通过ZhenxunRepoManager进行资源和Web UI的更新 * test(auto_update): 修改更新检测消息格式 (#2003) - 移除了不必要的版本号后缀(如 "-e6f17c4") - 统一了版本更新消息的格式,删除了冗余信息 * 🐛 修复web zip更新路径问题 * ⚡ 文件获取优化使用ali * Fix/test (#2008) * test: 修复bot测试 - 在 test_check_update.py 中跳过两个测试函数 - 移除 test_check.py 中的 mocked_api 参数和相关调用 - 删除 test_add_plugin.py 中的多个测试函数 - 移除 test_remove_plugin.py 中的 mocked_api 参数和相关调用 - 删除 test_search_plugin.py 中的多个测试函数 - 移除 test_update_all_plugin.py 和 test_update_plugin.py 中的 mocked_api 参数和相关调用 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * 修复res zip更新路径问题 * 🐛 修复zhenxun更新zip占用问题 * ✨ feat(update): 优化资源更新逻辑,调整更新路径和消息处理 --------- Co-authored-by: molanp <104612722+molanp@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
205 lines
7.1 KiB
Python
205 lines
7.1 KiB
Python
from collections import namedtuple
|
||
from collections.abc import Callable
|
||
from pathlib import Path
|
||
import platform
|
||
from typing import cast
|
||
|
||
from nonebot.adapters.onebot.v11 import Bot
|
||
from nonebot.adapters.onebot.v11.event import GroupMessageEvent
|
||
from nonebug import App
|
||
from pytest_mock import MockerFixture
|
||
|
||
from tests.config import BotId, GroupId, MessageId, UserId
|
||
from tests.utils import _v11_group_message_event
|
||
|
||
platform_uname = platform.uname_result(
|
||
system="Linux",
|
||
node="zhenxun",
|
||
release="5.15.0-1027-azure",
|
||
version="#1 SMP Debian 5.15.0-1027-azure",
|
||
machine="x86_64",
|
||
) # type: ignore
|
||
cpuinfo_get_cpu_info = {"brand_raw": "Intel(R) Core(TM) i7-10700K"}
|
||
|
||
|
||
def init_mocker(mocker: MockerFixture, tmp_path: Path):
|
||
mock_psutil = mocker.patch("zhenxun.builtin_plugins.check.data_source.psutil")
|
||
|
||
# Define namedtuples for complex return values
|
||
CpuFreqs = namedtuple("CpuFreqs", ["current"]) # noqa: PYI024
|
||
VirtualMemoryInfo = namedtuple("VirtualMemoryInfo", ["used", "total", "percent"]) # noqa: PYI024
|
||
SwapInfo = namedtuple("SwapInfo", ["used", "total", "percent"]) # noqa: PYI024
|
||
DiskUsage = namedtuple("DiskUsage", ["used", "total", "free", "percent"]) # noqa: PYI024
|
||
|
||
# Set specific return values for psutil methods
|
||
mock_psutil.cpu_percent.return_value = 1.0 # CPU 使用率
|
||
mock_psutil.cpu_freq.return_value = CpuFreqs(current=0.0) # CPU 频率
|
||
mock_psutil.cpu_count.return_value = 1 # CPU 核心数
|
||
|
||
# Memory Info
|
||
mock_psutil.virtual_memory.return_value = VirtualMemoryInfo(
|
||
used=1 * 1024**3, # 1 GB in bytes for used memory
|
||
total=1 * 1024**3, # 1 GB in bytes for total memory
|
||
percent=100.0, # 100% of memory used
|
||
)
|
||
|
||
# Swap Info
|
||
mock_psutil.swap_memory.return_value = SwapInfo(
|
||
used=1 * 1024**3, # 1 GB in bytes for used swap space
|
||
total=1 * 1024**3, # 1 GB in bytes for total swap space
|
||
percent=100.0, # 100% of swap space used
|
||
)
|
||
|
||
# Disk Usage
|
||
mock_psutil.disk_usage.return_value = DiskUsage(
|
||
used=1 * 1024**3, # 1 GB in bytes for used disk space
|
||
total=1 * 1024**3, # 1 GB in bytes for total disk space
|
||
free=0, # No free space
|
||
percent=100.0, # 100% of disk space used
|
||
)
|
||
|
||
mock_cpuinfo = mocker.patch("zhenxun.builtin_plugins.check.data_source.cpuinfo")
|
||
mock_cpuinfo.get_cpu_info.return_value = cpuinfo_get_cpu_info
|
||
|
||
mock_platform = mocker.patch("zhenxun.builtin_plugins.check.data_source.platform")
|
||
mock_platform.uname.return_value = platform_uname
|
||
|
||
mock_template_to_pic = mocker.patch("zhenxun.builtin_plugins.check.template_to_pic")
|
||
mock_template_to_pic_return = mocker.AsyncMock()
|
||
mock_template_to_pic.return_value = mock_template_to_pic_return
|
||
|
||
mock_build_message = mocker.patch(
|
||
"zhenxun.builtin_plugins.check.MessageUtils.build_message"
|
||
)
|
||
mock_build_message_return = mocker.AsyncMock()
|
||
mock_build_message.return_value = mock_build_message_return
|
||
|
||
mock_template_path_new = tmp_path / "resources" / "template"
|
||
mocker.patch(
|
||
"zhenxun.builtin_plugins.check.TEMPLATE_PATH", new=mock_template_path_new
|
||
)
|
||
return (
|
||
mock_psutil,
|
||
mock_cpuinfo,
|
||
mock_platform,
|
||
mock_template_to_pic,
|
||
mock_template_to_pic_return,
|
||
mock_build_message,
|
||
mock_build_message_return,
|
||
mock_template_path_new,
|
||
)
|
||
|
||
|
||
async def test_check(
|
||
app: App,
|
||
mocker: MockerFixture,
|
||
create_bot: Callable,
|
||
tmp_path: Path,
|
||
) -> None:
|
||
"""
|
||
测试自检
|
||
"""
|
||
from zhenxun.builtin_plugins.check import _self_check_matcher
|
||
|
||
(
|
||
mock_psutil,
|
||
mock_cpuinfo,
|
||
mock_platform,
|
||
mock_template_to_pic,
|
||
mock_template_to_pic_return,
|
||
mock_build_message,
|
||
mock_build_message_return,
|
||
mock_template_path_new,
|
||
) = init_mocker(mocker, tmp_path)
|
||
async with app.test_matcher(_self_check_matcher) as ctx:
|
||
bot = create_bot(ctx)
|
||
bot: Bot = cast(Bot, bot)
|
||
raw_message = "自检"
|
||
event: GroupMessageEvent = _v11_group_message_event(
|
||
message=raw_message,
|
||
self_id=BotId.QQ_BOT,
|
||
user_id=UserId.SUPERUSER,
|
||
group_id=GroupId.GROUP_ID_LEVEL_5,
|
||
message_id=MessageId.MESSAGE_ID_3,
|
||
to_me=True,
|
||
)
|
||
ctx.receive_event(bot=bot, event=event)
|
||
ctx.should_ignore_rule(_self_check_matcher)
|
||
|
||
mock_template_to_pic.assert_awaited_once()
|
||
mock_build_message.assert_called_once_with(mock_template_to_pic_return)
|
||
mock_build_message_return.send.assert_awaited_once()
|
||
|
||
|
||
async def test_check_arm(
|
||
app: App,
|
||
mocker: MockerFixture,
|
||
create_bot: Callable,
|
||
tmp_path: Path,
|
||
) -> None:
|
||
"""
|
||
测试自检(arm)
|
||
"""
|
||
from zhenxun.builtin_plugins.check import _self_check_matcher
|
||
|
||
platform_uname_arm = platform.uname_result(
|
||
system="Linux",
|
||
node="zhenxun",
|
||
release="5.15.0-1017-oracle",
|
||
version="#22~20.04.1-Ubuntu SMP Wed Aug 24 11:13:15 UTC 2022",
|
||
machine="aarch64",
|
||
) # type: ignore
|
||
mock_subprocess_check_output = mocker.patch(
|
||
"zhenxun.builtin_plugins.check.data_source.subprocess.check_output"
|
||
)
|
||
mock_environ_copy = mocker.patch(
|
||
"zhenxun.builtin_plugins.check.data_source.os.environ.copy"
|
||
)
|
||
mock_environ_copy_return = mocker.MagicMock()
|
||
mock_environ_copy.return_value = mock_environ_copy_return
|
||
(
|
||
mock_psutil,
|
||
mock_cpuinfo,
|
||
mock_platform,
|
||
mock_template_to_pic,
|
||
mock_template_to_pic_return,
|
||
mock_build_message,
|
||
mock_build_message_return,
|
||
mock_template_path_new,
|
||
) = init_mocker(mocker, tmp_path)
|
||
|
||
mock_platform.uname.return_value = platform_uname_arm
|
||
mock_cpuinfo.get_cpu_info.return_value = {}
|
||
mock_psutil.cpu_freq.return_value = {}
|
||
|
||
async with app.test_matcher(_self_check_matcher) as ctx:
|
||
bot = create_bot(ctx)
|
||
bot: Bot = cast(Bot, bot)
|
||
raw_message = "自检"
|
||
event: GroupMessageEvent = _v11_group_message_event(
|
||
message=raw_message,
|
||
self_id=BotId.QQ_BOT,
|
||
user_id=UserId.SUPERUSER,
|
||
group_id=GroupId.GROUP_ID_LEVEL_5,
|
||
message_id=MessageId.MESSAGE_ID_3,
|
||
to_me=True,
|
||
)
|
||
ctx.receive_event(bot=bot, event=event)
|
||
ctx.should_ignore_rule(_self_check_matcher)
|
||
mock_subprocess_check_output.assert_has_calls(
|
||
[
|
||
mocker.call(["lscpu"], env=mock_environ_copy_return),
|
||
mocker.call().decode(),
|
||
mocker.call().decode().splitlines(),
|
||
mocker.call().decode().splitlines().__iter__(),
|
||
mocker.call(["dmidecode", "-s", "processor-frequency"]),
|
||
mocker.call().decode(),
|
||
mocker.call().decode().split(),
|
||
mocker.call().decode().split().__getitem__(0),
|
||
mocker.call().decode().split().__getitem__().__float__(),
|
||
] # type: ignore
|
||
)
|
||
mock_template_to_pic.assert_awaited_once()
|
||
mock_build_message.assert_called_once_with(mock_template_to_pic_return)
|
||
mock_build_message_return.send.assert_awaited_once()
|