1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
131 lines
3.7 KiB
Python
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]
|