ForcePilot/backend/test/unit/channels/contract/dtos/test_plugin.py
Kris 002e6a356b chore: 批量整理代码变更,修复多类细节问题
1.  清理测试文件中未使用的导入与冗余代码
2.  修复审计日志与批量操作的空值约束,统一填充"global"作为默认渠道
3.  调整批量消息撤回的响应语义,对齐其他端点的部分成功契约
4.  修复访问规则批量克隆的唯一约束问题,新增后缀自动处理逻辑
5.  替换anyio为asyncio并行调用,修正时间UTC导入路径
6.  优化前端外部系统概览页的刷新状态提示与缓存逻辑
7.  修复测试用例中的断言与请求方式问题,适配httpx删除请求特性
8.  重构后端路由的依赖注入,移除冗余的数据库会话依赖
9.  调整测试用例的权限校验逻辑,修正强制登出的权限判断
10. 修复语义分块测试的numpy依赖问题,清理冗余导入
2026-07-13 20:48:29 +08:00

221 lines
6.3 KiB
Python

"""plugin.py DTO 单元测试。
覆盖 ``Permission`` / ``EnvVar`` / ``DomainEvent`` / ``PluginSummary`` /
``InstallPluginCmd`` / ``InstallPluginResult`` / ``UninstallPluginResult`` /
``PluginConfigResult`` / ``UpdatePluginConfigCmd`` /
``BatchPluginLifecycleCmd`` / ``BatchPluginLifecycleResult`` 的字段赋值、
默认值、不可变语义与 ``__post_init__`` 校验逻辑。
"""
from __future__ import annotations
from datetime import datetime
import pytest
from yuxi.channels.contract.dtos.common import Operator, OperatorRole
from yuxi.channels.contract.dtos.plugin import (
BatchPluginLifecycleCmd,
DomainEvent,
EnvVar,
InstallPluginCmd,
Permission,
PluginSummary,
UpdatePluginConfigCmd,
)
from yuxi.channels.contract.errors import ValidationError
pytestmark = pytest.mark.unit
def _make_operator() -> Operator:
return Operator(user_id="admin-1", role=OperatorRole.SUPERADMIN_USER)
@pytest.mark.unit
class TestPermission:
"""权限等级枚举测试。"""
def test_str_values(self):
assert Permission.REQUIRED_USER == "required_user"
assert Permission.ADMIN_USER == "admin_user"
assert Permission.SUPERADMIN_USER == "superadmin_user"
@pytest.mark.unit
class TestEnvVar:
"""环境变量声明 DTO 测试。"""
def test_defaults(self):
# Act
var = EnvVar(name="API_KEY", description="API key")
# Assert
assert var.required is True
assert var.default is None
assert var.sensitive is False
@pytest.mark.unit
class TestDomainEvent:
"""领域事件 DTO 测试。"""
def test_fields_are_assigned_with_defaults(self):
# Act
event = DomainEvent(
event_id="evt-1",
event_type="PluginLoaded",
payload={"key": "value"},
timestamp=datetime(2024, 1, 1),
)
# Assert
assert event.trace_id is None
@pytest.mark.unit
class TestPluginSummary:
"""插件摘要 DTO 测试。"""
def test_fields_are_assigned(self):
# Act
summary = PluginSummary(
plugin_id="wechat-plugin",
name="WeChat Plugin",
version="1.0.0",
channel_type="wechat",
state="started",
)
# Assert
assert summary.plugin_id == "wechat-plugin"
@pytest.mark.unit
class TestInstallPluginCmd:
"""安装插件命令 DTO 测试。"""
def test_valid_construction(self):
# Act
cmd = InstallPluginCmd(
operator=_make_operator(),
source_type="path",
source="/plugins/wechat",
)
# Assert
assert cmd.version is None
assert cmd.force is False
def test_empty_source_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
InstallPluginCmd(
operator=_make_operator(),
source_type="path",
source="",
)
assert exc_info.value.field == "source"
def test_invalid_source_type_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
InstallPluginCmd(
operator=_make_operator(),
source_type="invalid", # type: ignore[arg-type]
source="/path",
)
assert exc_info.value.field == "source_type"
@pytest.mark.unit
class TestUpdatePluginConfigCmd:
"""更新插件配置命令 DTO 测试。"""
def test_valid_construction(self):
# Act
cmd = UpdatePluginConfigCmd(
plugin_id="wechat-plugin",
operator=_make_operator(),
config={"key": "value"},
apply_mode="hot",
)
# Assert
assert cmd.account_id is None
def test_empty_plugin_id_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
UpdatePluginConfigCmd(
plugin_id="",
operator=_make_operator(),
config={"k": "v"},
apply_mode="hot",
)
assert exc_info.value.field == "plugin_id"
def test_empty_config_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
UpdatePluginConfigCmd(
plugin_id="p1",
operator=_make_operator(),
config={},
apply_mode="hot",
)
assert exc_info.value.field == "config"
def test_invalid_apply_mode_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
UpdatePluginConfigCmd(
plugin_id="p1",
operator=_make_operator(),
config={"k": "v"},
apply_mode="invalid", # type: ignore[arg-type]
)
assert exc_info.value.field == "apply_mode"
@pytest.mark.unit
class TestBatchPluginLifecycleCmd:
"""批量插件生命周期命令 DTO 测试。"""
def test_valid_with_plugin_ids(self):
# Act
cmd = BatchPluginLifecycleCmd(
operator=_make_operator(),
plugin_ids=("p1", "p2"),
)
# Assert
assert cmd.filter is None
def test_valid_with_filter(self):
# Act
cmd = BatchPluginLifecycleCmd(
operator=_make_operator(),
filter={"channel_type": "wechat"},
)
# Assert
assert cmd.plugin_ids == ()
def test_both_empty_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BatchPluginLifecycleCmd(operator=_make_operator())
assert exc_info.value.field == "plugin_ids"
def test_both_provided_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BatchPluginLifecycleCmd(
operator=_make_operator(),
plugin_ids=("p1",),
filter={"state": "stopped"},
)
assert exc_info.value.field == "plugin_ids"
def test_empty_string_in_plugin_ids_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BatchPluginLifecycleCmd(
operator=_make_operator(),
plugin_ids=("p1", ""),
)
assert exc_info.value.field == "plugin_ids"