ForcePilot/backend/test/unit/channels/contract/dtos/test_lifecycle.py
Kris 08617091dc refactor: 整理项目包结构与导入路径
- 新增多个业务域的__init__.py模块文件,规范包导出结构
- 调整多个DTO文件的导入路径,统一模块组织方式
- 移除测试文件中多余的空行与导入语句
- 优化部分业务模块的包层级划分
2026-07-18 02:04:03 +08:00

138 lines
3.8 KiB
Python

"""lifecycle.py DTO 单元测试。
覆盖 ``LifecycleCmd`` 与 ``LifecycleResult`` 的字段赋值、默认值、不可变
语义与 ``__post_init__`` 校验逻辑。
"""
from __future__ import annotations
import dataclasses
from typing import Any
import pytest
from yuxi.channels.contract.dtos.plugin.lifecycle import (
LifecycleCmd,
LifecycleResult,
)
from yuxi.channels.contract.errors import ValidationError
pytestmark = pytest.mark.unit
@pytest.mark.unit
class TestLifecycleCmd:
"""生命周期命令 DTO 测试。"""
def test_fields_are_assigned(self):
# Arrange
# Act
cmd = LifecycleCmd(event="load", plugin_id="plugin-1")
# Assert
assert cmd.event == "load"
assert cmd.plugin_id == "plugin-1"
assert cmd.params is None
def test_with_params(self):
# Arrange
params: dict[str, Any] = {"force": True}
# Act
cmd = LifecycleCmd(event="start", plugin_id="plugin-1", params=params)
# Assert
assert cmd.params is params
@pytest.mark.parametrize(
"event",
["load", "start", "pause", "resume", "stop", "unload", "reload"],
)
def test_valid_events(self, event):
# Arrange
# Act
cmd = LifecycleCmd(event=event, plugin_id="plugin-1") # type: ignore[arg-type]
# Assert
assert cmd.event == event
def test_is_frozen(self):
# Arrange
cmd = LifecycleCmd(event="load", plugin_id="plugin-1")
# Act / Assert
with pytest.raises(dataclasses.FrozenInstanceError):
cmd.event = "stop" # type: ignore[misc]
def test_empty_plugin_id_raises_validation_error(self):
# Arrange
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
LifecycleCmd(event="load", plugin_id="")
assert exc_info.value.field == "plugin_id"
def test_invalid_event_raises_validation_error(self):
# Arrange
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
LifecycleCmd(event="invalid", plugin_id="plugin-1") # type: ignore[arg-type]
assert exc_info.value.field == "event"
@pytest.mark.unit
class TestLifecycleResult:
"""生命周期结果 DTO 测试。"""
def test_required_fields_are_assigned(self):
# Arrange
# Act
result = LifecycleResult(state="started")
# Assert
assert result.state == "started"
def test_defaults_are_correct(self):
# Arrange
# Act
result = LifecycleResult(state="started")
# Assert
assert result.error is None
assert result.error_code == ""
assert result.trace_id == ""
def test_failed_result_with_error(self):
# Arrange
# Act
result = LifecycleResult(
state="failed",
error="plugin crashed",
error_code="PLUGIN_FAILED",
trace_id="trace-1",
)
# Assert
assert result.state == "failed"
assert result.error == "plugin crashed"
assert result.error_code == "PLUGIN_FAILED"
assert result.trace_id == "trace-1"
@pytest.mark.parametrize(
"state",
[
"discovered",
"resolved",
"loaded",
"initialized",
"started",
"paused",
"stopped",
"unloaded",
"failed",
],
)
def test_valid_states(self, state):
# Arrange
# Act
result = LifecycleResult(state=state) # type: ignore[arg-type]
# Assert
assert result.state == state
def test_is_frozen(self):
# Arrange
result = LifecycleResult(state="started")
# Act / Assert
with pytest.raises(dataclasses.FrozenInstanceError):
result.state = "stopped" # type: ignore[misc]