1. 清理测试文件中未使用的导入与冗余代码 2. 修复审计日志与批量操作的空值约束,统一填充"global"作为默认渠道 3. 调整批量消息撤回的响应语义,对齐其他端点的部分成功契约 4. 修复访问规则批量克隆的唯一约束问题,新增后缀自动处理逻辑 5. 替换anyio为asyncio并行调用,修正时间UTC导入路径 6. 优化前端外部系统概览页的刷新状态提示与缓存逻辑 7. 修复测试用例中的断言与请求方式问题,适配httpx删除请求特性 8. 重构后端路由的依赖注入,移除冗余的数据库会话依赖 9. 调整测试用例的权限校验逻辑,修正强制登出的权限判断 10. 修复语义分块测试的numpy依赖问题,清理冗余导入
196 lines
5.6 KiB
Python
196 lines
5.6 KiB
Python
"""health.py DTO 单元测试。
|
|
|
|
覆盖 ``WorkerStatus`` / ``RedisStreamStatus`` / ``ConnectionPoolStatus`` /
|
|
``AccountHealthSnapshot`` / ``WorkerHealthSnapshot`` /
|
|
``TransportHealthSnapshot`` / ``DegradedComponentDetail`` / ``HealthQuery`` /
|
|
``HealthSnapshot`` / ``ChannelHealth`` / ``ProbeResult`` /
|
|
``AdapterProbeOutcome`` / ``DiagnosticsExportRequest`` / ``DiagnosticsBundle``
|
|
的字段赋值、默认值、不可变语义与 ``__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.health import (
|
|
AccountHealthSnapshot,
|
|
ConnectionPoolStatus,
|
|
DiagnosticsBundle,
|
|
DiagnosticsExportRequest,
|
|
HealthQuery,
|
|
HealthSnapshot,
|
|
RedisStreamStatus,
|
|
TransportHealthSnapshot,
|
|
WorkerStatus,
|
|
)
|
|
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 TestWorkerStatus:
|
|
"""队列 Worker 状态值对象测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
status = WorkerStatus(queue_name="default", available=True)
|
|
# Assert
|
|
assert status.queue_depth == 0
|
|
assert status.worker_utilization is None
|
|
assert status.summary == ""
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestRedisStreamStatus:
|
|
"""Redis 流状态值对象测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
status = RedisStreamStatus(available=True, db_size=100)
|
|
# Assert
|
|
assert status.summary == ""
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestConnectionPoolStatus:
|
|
"""数据库连接池状态值对象测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
status = ConnectionPoolStatus(available=True)
|
|
# Assert
|
|
assert status.size == 0
|
|
assert status.reason is None
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestAccountHealthSnapshot:
|
|
"""传输引擎单账号健康状态值对象测试。"""
|
|
|
|
def test_fields_are_assigned(self):
|
|
# Act
|
|
snap = AccountHealthSnapshot(
|
|
channel_type="wechat",
|
|
account_id="acc-1",
|
|
state="running",
|
|
last_activity_at=1000.0,
|
|
backoff_attempt=0,
|
|
consecutive_successes=5,
|
|
)
|
|
# Assert
|
|
assert snap.state == "running"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestTransportHealthSnapshot:
|
|
"""传输引擎健康状态值对象测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
snap = TransportHealthSnapshot(running=True)
|
|
# Assert
|
|
assert snap.puller is None
|
|
assert snap.stream is None
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestHealthQuery:
|
|
"""健康查询 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
query = HealthQuery()
|
|
# Assert
|
|
assert query.channel_filter is None
|
|
assert query.with_probe is False
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestHealthSnapshot:
|
|
"""健康快照 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
snap = HealthSnapshot(status="healthy", version="1.0.0")
|
|
# Assert
|
|
assert snap.degraded_components == ()
|
|
assert snap.channels == ()
|
|
assert snap.error_code == ""
|
|
assert snap.trace_id == ""
|
|
assert snap.probed_at is None
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
snap = HealthSnapshot(status="healthy", version="1.0.0")
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
snap.status = "unhealthy" # type: ignore[misc]
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestDiagnosticsExportRequest:
|
|
"""诊断导出请求 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
req = DiagnosticsExportRequest(operator=_make_operator())
|
|
# Assert
|
|
assert req.include_audit_logs is True
|
|
assert req.audit_log_count == 100
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
req = DiagnosticsExportRequest(operator=_make_operator())
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
req.audit_log_count = 50 # type: ignore[misc]
|
|
|
|
def test_zero_audit_log_count_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
DiagnosticsExportRequest(operator=_make_operator(), audit_log_count=0)
|
|
assert exc_info.value.field == "audit_log_count"
|
|
|
|
def test_excessive_audit_log_count_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
DiagnosticsExportRequest(operator=_make_operator(), audit_log_count=501)
|
|
assert exc_info.value.field == "audit_log_count"
|
|
|
|
def test_zero_error_log_count_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
DiagnosticsExportRequest(operator=_make_operator(), error_log_count=0)
|
|
assert exc_info.value.field == "error_log_count"
|
|
|
|
def test_excessive_error_log_count_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
DiagnosticsExportRequest(operator=_make_operator(), error_log_count=501)
|
|
assert exc_info.value.field == "error_log_count"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestDiagnosticsBundle:
|
|
"""诊断包 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
bundle = DiagnosticsBundle(
|
|
manifest_snapshot={},
|
|
plugin_states={},
|
|
exported_at=datetime(2024, 1, 1),
|
|
)
|
|
# Assert
|
|
assert bundle.audit_logs == ()
|
|
assert bundle.queue_depth == 0
|
|
assert bundle.worker_status is None
|