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

235 lines
6.8 KiB
Python

"""dashboard.py DTO 单元测试。
覆盖 ``AccountStats`` / ``MessageStats`` / ``SessionStats`` /
``OutboxStatsSummary`` / ``DashboardOverview`` / ``DashboardOverviewQuery`` /
``DashboardDeliveryQuery`` / ``ChannelDeliveryStat`` /
``DashboardDeliveryResult`` / ``DashboardTodoResult`` / ``RealtimeQuery`` /
``ChannelRealtimeStat`` / ``RealtimeMetricsResult`` 的字段赋值、默认值、
不可变语义与 ``__post_init__`` 校验逻辑。
"""
from __future__ import annotations
import dataclasses
from datetime import datetime, timezone
import pytest
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.channels.contract.dtos.dashboard import (
AccountStats,
ChannelDeliveryStat,
ChannelRealtimeStat,
DashboardDeliveryQuery,
DashboardDeliveryResult,
DashboardOverview,
DashboardOverviewQuery,
DashboardTodoResult,
MessageStats,
OutboxStatsSummary,
RealtimeMetricsResult,
RealtimeQuery,
SessionStats,
)
from yuxi.channels.contract.errors import ValidationError
pytestmark = pytest.mark.unit
def _aware_dt() -> datetime:
return datetime(2024, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
def _naive_dt() -> datetime:
return datetime(2024, 1, 1, 12, 0, 0)
@pytest.mark.unit
class TestAccountStats:
"""账户统计快照 DTO 测试。"""
def test_fields_are_assigned_with_defaults(self):
# Act
stats = AccountStats(
total=10, by_channel={"wechat": 10}, by_status={"active": 8, "disabled": 2}
)
# Assert
assert stats.by_onboarding_status == {}
@pytest.mark.unit
class TestDashboardOverviewQuery:
"""全局总览查询 DTO 测试。"""
def test_defaults(self):
# Act
query = DashboardOverviewQuery()
# Assert
assert query.channel_type is None
assert query.start_time is None
def test_naive_start_time_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
DashboardOverviewQuery(start_time=_naive_dt())
assert exc_info.value.field == "start_time"
def test_naive_end_time_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
DashboardOverviewQuery(end_time=_naive_dt())
assert exc_info.value.field == "end_time"
def test_reversed_time_range_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
DashboardOverviewQuery(
start_time=datetime(2024, 1, 2, tzinfo=timezone.utc),
end_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
)
assert exc_info.value.field == "time_range"
@pytest.mark.unit
class TestDashboardDeliveryQuery:
"""投递总览查询 DTO 测试。"""
def test_defaults(self):
# Act
query = DashboardDeliveryQuery()
# Assert
assert query.channel_type is None
def test_naive_start_time_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
DashboardDeliveryQuery(start_time=_naive_dt())
assert exc_info.value.field == "start_time"
def test_reversed_time_range_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
DashboardDeliveryQuery(
start_time=datetime(2024, 1, 2, tzinfo=timezone.utc),
end_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
)
assert exc_info.value.field == "time_range"
@pytest.mark.unit
class TestRealtimeQuery:
"""实时监控查询 DTO 测试。"""
def test_defaults(self):
# Act
query = RealtimeQuery()
# Assert
assert query.window_seconds == 60
def test_is_frozen(self):
# Arrange
query = RealtimeQuery()
# Act / Assert
with pytest.raises(dataclasses.FrozenInstanceError):
query.window_seconds = 10 # type: ignore[misc]
def test_window_below_min_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
RealtimeQuery(window_seconds=9)
assert exc_info.value.field == "window_seconds"
def test_window_above_max_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
RealtimeQuery(window_seconds=301)
assert exc_info.value.field == "window_seconds"
def test_window_at_min_boundary_is_valid(self):
# Act
query = RealtimeQuery(window_seconds=10)
# Assert
assert query.window_seconds == 10
def test_window_at_max_boundary_is_valid(self):
# Act
query = RealtimeQuery(window_seconds=300)
# Assert
assert query.window_seconds == 300
@pytest.mark.unit
class TestDashboardDeliveryResult:
"""投递总览结果 DTO 测试。"""
def test_fields_are_assigned(self):
# Act
result = DashboardDeliveryResult(
total_sent=100,
success_count=90,
failed_count=10,
success_rate=90.0,
avg_latency_ms=50.0,
p95_latency_ms=100.0,
p99_latency_ms=200.0,
current_queue_depth=5,
dead_letter_count=1,
by_channel=(
ChannelDeliveryStat(channel_type="wechat", sent=50, success_rate=95.0),
),
)
# Assert
assert result.success_rate == 90.0
assert result.by_channel[0].channel_type == "wechat"
def test_success_rate_can_be_none(self):
# Act
result = DashboardDeliveryResult(
total_sent=0,
success_count=0,
failed_count=0,
success_rate=None,
avg_latency_ms=None,
p95_latency_ms=None,
p99_latency_ms=None,
current_queue_depth=0,
dead_letter_count=0,
by_channel=(),
)
# Assert
assert result.success_rate is None
@pytest.mark.unit
class TestDashboardTodoResult:
"""工作台待办计数聚合结果 DTO 测试。"""
def test_fields_are_assigned(self):
# Act
result = DashboardTodoResult(
pending_pairings=3, pending_reviews=5, dead_letter_count=2
)
# Assert
assert result.pending_pairings == 3
@pytest.mark.unit
class TestRealtimeMetricsResult:
"""实时监控结果 DTO 测试。"""
def test_fields_are_assigned(self):
# Act
result = RealtimeMetricsResult(
window_seconds=60,
messages_per_second=10.5,
active_sessions=100,
active_conversations=95,
queue_depth=5,
worker_utilization=None,
by_channel=(
ChannelRealtimeStat(channel_type="wechat", mps=5.0, active_sessions=50),
),
)
# Assert
assert result.worker_utilization is None
assert result.by_channel[0].mps == 5.0