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

131 lines
3.7 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.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]