1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
125 lines
3.7 KiB
Python
125 lines
3.7 KiB
Python
"""status.py DTO 单元测试。
|
|
|
|
覆盖 ``EventType`` / ``MessageStatus`` 枚举与 ``StatusPayload`` 的字段
|
|
赋值、默认值、不可变语义与 ``__post_init__`` 校验逻辑。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
from datetime import datetime
|
|
|
|
import pytest
|
|
from yuxi.channels.contract.dtos.status import (
|
|
EventType,
|
|
MessageStatus,
|
|
StatusPayload,
|
|
)
|
|
from yuxi.channels.contract.errors import ValidationError
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestEventType:
|
|
"""事件类型枚举测试。"""
|
|
|
|
def test_enum_values_are_correct(self):
|
|
assert EventType.MESSAGE == "message"
|
|
assert EventType.DELIVERED == "delivered"
|
|
assert EventType.READ == "read"
|
|
assert EventType.EDITED == "edited"
|
|
assert EventType.RECALLED == "recalled"
|
|
assert EventType.UNKNOWN == "unknown"
|
|
assert EventType.AGENT_MENTION == "agent_mention"
|
|
|
|
def test_enum_inherits_from_str(self):
|
|
assert issubclass(EventType, str)
|
|
|
|
def test_enum_has_seven_members(self):
|
|
assert len(list(EventType)) == 7
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestMessageStatus:
|
|
"""消息状态枚举测试。"""
|
|
|
|
def test_enum_values_are_correct(self):
|
|
assert MessageStatus.PENDING == "pending"
|
|
assert MessageStatus.SENT == "sent"
|
|
assert MessageStatus.DELIVERED == "delivered"
|
|
assert MessageStatus.READ == "read"
|
|
assert MessageStatus.FAILED == "failed"
|
|
|
|
def test_enum_has_five_members(self):
|
|
assert len(list(MessageStatus)) == 5
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestStatusPayload:
|
|
"""状态负载 DTO 测试。"""
|
|
|
|
def test_required_fields_are_assigned(self):
|
|
# Arrange
|
|
now = datetime(2026, 1, 1, 12, 0, 0)
|
|
# Act
|
|
payload = StatusPayload(
|
|
event_type=EventType.DELIVERED,
|
|
ref_channel_msg_id="cm-1",
|
|
timestamp=now,
|
|
)
|
|
# Assert
|
|
assert payload.event_type is EventType.DELIVERED
|
|
assert payload.ref_channel_msg_id == "cm-1"
|
|
assert payload.timestamp is now
|
|
assert payload.metadata is None
|
|
|
|
def test_with_metadata(self):
|
|
# Arrange
|
|
now = datetime(2026, 1, 1, 12, 0, 0)
|
|
# Act
|
|
payload = StatusPayload(
|
|
event_type=EventType.READ,
|
|
ref_channel_msg_id="cm-1",
|
|
timestamp=now,
|
|
metadata={"read_by": "user-1"},
|
|
)
|
|
# Assert
|
|
assert payload.metadata == {"read_by": "user-1"}
|
|
|
|
def test_empty_ref_for_non_message_event_is_valid(self):
|
|
# Arrange
|
|
now = datetime(2026, 1, 1, 12, 0, 0)
|
|
# Act - 非 MESSAGE 事件允许空 ref_channel_msg_id
|
|
payload = StatusPayload(
|
|
event_type=EventType.DELIVERED,
|
|
ref_channel_msg_id="",
|
|
timestamp=now,
|
|
)
|
|
# Assert
|
|
assert payload.ref_channel_msg_id == ""
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
now = datetime(2026, 1, 1, 12, 0, 0)
|
|
payload = StatusPayload(
|
|
event_type=EventType.MESSAGE,
|
|
ref_channel_msg_id="cm-1",
|
|
timestamp=now,
|
|
)
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
payload.event_type = EventType.READ # type: ignore[misc]
|
|
|
|
def test_empty_ref_for_message_event_raises_validation_error(self):
|
|
# Arrange
|
|
now = datetime(2026, 1, 1, 12, 0, 0)
|
|
# Act / Assert - MESSAGE 事件必须非空 ref_channel_msg_id
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
StatusPayload(
|
|
event_type=EventType.MESSAGE,
|
|
ref_channel_msg_id="",
|
|
timestamp=now,
|
|
)
|
|
assert exc_info.value.field == "ref_channel_msg_id"
|