1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
208 lines
5.6 KiB
Python
208 lines
5.6 KiB
Python
"""session.py DTO 单元测试。
|
|
|
|
覆盖 ``ChannelSessionId`` / ``PeerId`` / ``ChatType`` / ``SessionOwner`` /
|
|
``OwnerTransferCmd`` / ``TemporarySessionPattern`` / ``CloseSessionCmd`` /
|
|
``SessionMessageItem`` / ``SessionStatsResult`` / ``BatchCloseSessionsCmd`` /
|
|
``BatchCloseResult`` 的字段赋值、默认值、不可变语义与 ``__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.session import (
|
|
BatchCloseResult,
|
|
BatchCloseSessionsCmd,
|
|
ChannelSessionId,
|
|
ChatType,
|
|
CloseSessionCmd,
|
|
OwnerTransferCmd,
|
|
PeerId,
|
|
SessionMessageItem,
|
|
SessionOwner,
|
|
SessionStatsResult,
|
|
TemporarySessionPattern,
|
|
)
|
|
from yuxi.channels.contract.errors import ValidationError
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
def _make_operator() -> Operator:
|
|
return Operator(user_id="admin-1", role=OperatorRole.ADMIN_USER)
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestChannelSessionId:
|
|
"""渠道会话 ID DTO 测试。"""
|
|
|
|
def test_value_is_assigned(self):
|
|
# Act
|
|
sid = ChannelSessionId(value="session-001")
|
|
# Assert
|
|
assert sid.value == "session-001"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestPeerId:
|
|
"""对端 ID DTO 测试。"""
|
|
|
|
def test_value_is_assigned(self):
|
|
# Act
|
|
pid = PeerId(value="peer-001")
|
|
# Assert
|
|
assert pid.value == "peer-001"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestChatType:
|
|
"""会话类型枚举测试。"""
|
|
|
|
def test_str_values(self):
|
|
assert ChatType.P2P == "p2p"
|
|
assert ChatType.GROUP == "group"
|
|
assert ChatType.KF == "kf"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestSessionOwner:
|
|
"""会话所有者 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned(self):
|
|
# Act
|
|
owner = SessionOwner(
|
|
conversation_id="conv-1",
|
|
owner_peer_id="peer-1",
|
|
created_at=datetime(2024, 1, 1),
|
|
)
|
|
# Assert
|
|
assert owner.owner_peer_id == "peer-1"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestOwnerTransferCmd:
|
|
"""所有者转移命令 DTO 测试。"""
|
|
|
|
def test_valid_construction(self):
|
|
# Act
|
|
cmd = OwnerTransferCmd(
|
|
session_id="sess-1",
|
|
new_owner_id="peer-2",
|
|
operator=_make_operator(),
|
|
)
|
|
# Assert
|
|
assert cmd.new_owner_id == "peer-2"
|
|
|
|
def test_empty_session_id_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
OwnerTransferCmd(
|
|
session_id="",
|
|
new_owner_id="peer-2",
|
|
operator=_make_operator(),
|
|
)
|
|
assert exc_info.value.field == "session_id"
|
|
|
|
def test_empty_new_owner_id_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
OwnerTransferCmd(
|
|
session_id="sess-1",
|
|
new_owner_id="",
|
|
operator=_make_operator(),
|
|
)
|
|
assert exc_info.value.field == "new_owner_id"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestCloseSessionCmd:
|
|
"""关闭会话命令 DTO 测试。"""
|
|
|
|
def test_valid_construction(self):
|
|
# Act
|
|
cmd = CloseSessionCmd(
|
|
session_id="sess-1",
|
|
operator=_make_operator(),
|
|
)
|
|
# Assert
|
|
assert cmd.reason is None
|
|
|
|
def test_empty_session_id_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
CloseSessionCmd(session_id="", operator=_make_operator())
|
|
assert exc_info.value.field == "session_id"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestBatchCloseSessionsCmd:
|
|
"""批量关闭会话命令 DTO 测试。"""
|
|
|
|
def test_valid_with_session_ids(self):
|
|
# Act
|
|
cmd = BatchCloseSessionsCmd(
|
|
operator=_make_operator(),
|
|
session_ids=("s1", "s2"),
|
|
)
|
|
# Assert
|
|
assert cmd.max_count == 100
|
|
assert cmd.filter is None
|
|
|
|
def test_valid_with_filter(self):
|
|
# Act
|
|
cmd = BatchCloseSessionsCmd(
|
|
operator=_make_operator(),
|
|
filter={"channel_type": "wechat"},
|
|
)
|
|
# Assert
|
|
assert cmd.session_ids == ()
|
|
|
|
def test_both_empty_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
BatchCloseSessionsCmd(operator=_make_operator())
|
|
assert exc_info.value.field == "session_ids"
|
|
|
|
def test_max_count_below_min_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
BatchCloseSessionsCmd(
|
|
operator=_make_operator(),
|
|
session_ids=("s1",),
|
|
max_count=0,
|
|
)
|
|
assert exc_info.value.field == "max_count"
|
|
|
|
def test_max_count_above_max_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
BatchCloseSessionsCmd(
|
|
operator=_make_operator(),
|
|
session_ids=("s1",),
|
|
max_count=1001,
|
|
)
|
|
assert exc_info.value.field == "max_count"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestSessionStatsResult:
|
|
"""会话统计结果 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned_with_defaults(self):
|
|
# Act
|
|
result = SessionStatsResult(
|
|
message_count=10,
|
|
user_message_count=5,
|
|
assistant_message_count=5,
|
|
started_at=datetime(2024, 1, 1),
|
|
last_activity_at=datetime(2024, 1, 2),
|
|
duration_seconds=86400,
|
|
)
|
|
# Assert
|
|
assert result.first_response_seconds is None
|
|
assert result.avg_response_seconds is None
|