ForcePilot/backend/test/unit/channels/contract/dtos/test_plugin.py
Kris 3ae9c0bd21 test: 批量修复与新增单元测试用例,清理废弃测试目录
1.  删除了 test/unit/external_systems/framework/ 下的废弃空测试目录
2.  修复多处测试断言逻辑、参数传递与测试数据构造
3.  新增日志级别、缓存令牌、流事件等DTO单元测试
4.  补充路由绑定、会话仓储、outbox仓储的测试覆盖
5.  更新测试用例中的异常类型、参数校验与业务逻辑断言
2026-07-11 21:43:16 +08:00

227 lines
6.4 KiB
Python

"""plugin.py DTO 单元测试。
覆盖 ``Permission`` / ``EnvVar`` / ``DomainEvent`` / ``PluginSummary`` /
``InstallPluginCmd`` / ``InstallPluginResult`` / ``UninstallPluginResult`` /
``PluginConfigResult`` / ``UpdatePluginConfigCmd`` /
``BatchPluginLifecycleCmd`` / ``BatchPluginLifecycleResult`` 的字段赋值、
默认值、不可变语义与 ``__post_init__`` 校验逻辑。
"""
from __future__ import annotations
import dataclasses
from datetime import datetime
import pytest
from yuxi.channels.contract.dtos.common import Operator, OperatorRole
from yuxi.channels.contract.dtos.plugin import (
BatchPluginLifecycleCmd,
BatchPluginLifecycleResult,
BatchPluginLifecycleSuccessItem,
DomainEvent,
EnvVar,
InstallPluginCmd,
InstallPluginResult,
Permission,
PluginConfigResult,
PluginSummary,
UninstallPluginResult,
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"