ForcePilot/backend/test/unit/channels/contract/dtos/test_route.py
Kris 08617091dc refactor: 整理项目包结构与导入路径
- 新增多个业务域的__init__.py模块文件,规范包导出结构
- 调整多个DTO文件的导入路径,统一模块组织方式
- 移除测试文件中多余的空行与导入语句
- 优化部分业务模块的包层级划分
2026-07-18 02:04:03 +08:00

216 lines
6.6 KiB
Python

"""route.py DTO 单元测试。
覆盖 ``MatchSource`` / ``ConfigMatchSource`` / ``RouteBinding`` /
``MatchTier`` / ``BindingContext`` / ``ConfigFallbackChain`` /
``NestedWhitelistDecision`` / ``RouteBindingRule`` / ``SaveRouteBindingCmd`` /
``UpdateRouteBindingCmd`` / ``RouteBindingFilter`` 的字段赋值、默认值、
不可变语义与 ``__post_init__`` 校验逻辑。
"""
from __future__ import annotations
import dataclasses
import pytest
from yuxi.channels.contract.dtos.messaging.channel import ChannelType
from yuxi.channels.contract.dtos.routing.route import (
BindingContext,
ConfigFallbackChain,
ConfigMatchSource,
MatchSource,
MatchTier,
NestedWhitelistDecision,
RouteBinding,
)
from yuxi.channels.contract.errors import ValidationError
pytestmark = pytest.mark.unit
@pytest.mark.unit
class TestMatchSource:
"""匹配来源枚举测试。"""
def test_str_values(self):
assert MatchSource.EXPLICIT == "explicit"
assert MatchSource.SESSION == "session"
assert MatchSource.IDENTITY == "identity"
assert MatchSource.DEFAULT == "default"
assert MatchSource.CHAT_TYPE == "chat_type"
@pytest.mark.unit
class TestConfigMatchSource:
"""配置匹配来源枚举测试。"""
def test_str_values(self):
assert ConfigMatchSource.DIRECT == "direct"
assert ConfigMatchSource.PARENT == "parent"
assert ConfigMatchSource.WILDCARD == "wildcard"
assert ConfigMatchSource.CHANNEL_BINDING == "channel_binding"
@pytest.mark.unit
class TestRouteBinding:
"""路由绑定 DTO 测试。"""
def test_fields_are_assigned_with_defaults(self):
# Act
binding = RouteBinding(
channel_account_id="acc-1",
agent_binding="agent-slug",
match_source=MatchSource.EXPLICIT,
)
# Assert
assert binding.channel_session_id is None
assert binding.matched_layer is None
assert binding.config_match_source is None
def test_is_frozen(self):
# Arrange
binding = RouteBinding(
channel_account_id="a1",
agent_binding="slug",
match_source=MatchSource.DEFAULT,
)
# Act / Assert
with pytest.raises(dataclasses.FrozenInstanceError):
binding.agent_binding = "other" # type: ignore[misc]
def test_empty_channel_account_id_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
RouteBinding(
channel_account_id="",
agent_binding="slug",
match_source=MatchSource.DEFAULT,
)
assert exc_info.value.field == "channel_account_id"
def test_empty_agent_binding_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
RouteBinding(
channel_account_id="a1",
agent_binding="",
match_source=MatchSource.DEFAULT,
)
assert exc_info.value.field == "agent_binding"
@pytest.mark.unit
class TestMatchTier:
"""匹配层级 DTO 测试。"""
def test_defaults(self):
# Act
tier = MatchTier(name="explicit", priority=0, match_method="exact")
# Assert
assert tier.enabled is True
def test_empty_name_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
MatchTier(name="", priority=0, match_method="exact")
assert exc_info.value.field == "name"
def test_negative_priority_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
MatchTier(name="t", priority=-1, match_method="exact")
assert exc_info.value.field == "priority"
def test_invalid_match_method_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
MatchTier(name="t", priority=0, match_method="invalid") # type: ignore[arg-type]
assert exc_info.value.field == "match_method"
@pytest.mark.unit
class TestBindingContext:
"""绑定上下文 DTO 测试。"""
def test_valid_construction(self):
# Act
ctx = BindingContext(
session_key="session-key",
channel_type=ChannelType("wechat"),
account_id="acc-1",
chat_type="p2p",
peer_id="peer-1",
)
# Assert
assert ctx.conversation_id is None
assert ctx.unified_identity_id is None
def test_empty_session_key_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BindingContext(
session_key="",
channel_type=ChannelType("wechat"),
account_id="a1",
chat_type="p2p",
peer_id="p1",
)
assert exc_info.value.field == "session_key"
def test_empty_account_id_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BindingContext(
session_key="sk",
channel_type=ChannelType("wechat"),
account_id="",
chat_type="p2p",
peer_id="p1",
)
assert exc_info.value.field == "account_id"
def test_invalid_chat_type_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
BindingContext(
session_key="sk",
channel_type=ChannelType("wechat"),
account_id="a1",
chat_type="invalid", # type: ignore[arg-type]
peer_id="p1",
)
assert exc_info.value.field == "chat_type"
@pytest.mark.unit
class TestConfigFallbackChain:
"""配置回退链 DTO 测试。"""
def test_fields_are_assigned(self):
# Act
chain = ConfigFallbackChain(
match_key="wechat:*",
match_source=ConfigMatchSource.WILDCARD,
)
# Assert
assert chain.match_value is None
def test_empty_match_key_raises(self):
# Act / Assert
with pytest.raises(ValidationError) as exc_info:
ConfigFallbackChain(
match_key="",
match_source=ConfigMatchSource.DIRECT,
)
assert exc_info.value.field == "match_key"
@pytest.mark.unit
class TestNestedWhitelistDecision:
"""嵌套白名单决策 DTO 测试。"""
def test_defaults(self):
# Act
decision = NestedWhitelistDecision(outer_configured=True, outer_matched=False)
# Assert
assert decision.inner_decision is None