完成渠道模块的单元测试目录搭建,新增多个领域模型、端口、中间件、事件、服务以及基础设施层的单元测试文件,同时补充了conftest.py的环境变量配置,完善测试基础环境。
180 lines
5.2 KiB
Python
180 lines
5.2 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from yuxi.channel.application.pipeline.builder import build_inbound_pipeline
|
|
from yuxi.channel.application.service.auth_service import AuthService
|
|
from yuxi.channel.domain.service.pipeline import Pipeline
|
|
|
|
|
|
class _FakeRateLimiter:
|
|
async def check_and_incr(
|
|
self, key: str, *, max_attempts: int, window_seconds: int, lockout_seconds: int = 0
|
|
) -> bool:
|
|
return True
|
|
|
|
async def is_locked(self, key: str) -> tuple[bool, int]:
|
|
return False, 0
|
|
|
|
async def reset(self, key: str) -> None:
|
|
pass
|
|
|
|
|
|
class _FakeCache:
|
|
async def get(self, key: str) -> str | None:
|
|
return None
|
|
|
|
async def set(self, key: str, value: str, *, ex: int | None = None, nx: bool = False) -> bool:
|
|
return True
|
|
|
|
async def delete(self, key: str) -> None:
|
|
pass
|
|
|
|
async def incr(self, key: str) -> int:
|
|
return 1
|
|
|
|
async def expire(self, key: str, seconds: int) -> None:
|
|
pass
|
|
|
|
async def ttl(self, key: str) -> int:
|
|
return 0
|
|
|
|
async def eval(self, script: str, keys: list[str], args: list[str | int]) -> tuple:
|
|
return ()
|
|
|
|
|
|
class _FakeQueue:
|
|
async def enqueue(self, payload: dict) -> str:
|
|
return "msg-id"
|
|
|
|
async def dequeue(self, *, count: int = 1, block: int = 5000, consumer_name: str = "") -> list[dict]:
|
|
return []
|
|
|
|
async def ack(self, message_id: str) -> None:
|
|
pass
|
|
|
|
async def pending_count(self) -> int:
|
|
return 0
|
|
|
|
|
|
class _FakeKeywordMatcher:
|
|
def match(self, content: str) -> str | None:
|
|
return None
|
|
|
|
def update_keywords(self, keywords: set[str]) -> None:
|
|
pass
|
|
|
|
|
|
class _FakeSignatureVerifier:
|
|
async def verify(self, payload: dict, signature: str, timestamp: str) -> bool:
|
|
return True
|
|
|
|
|
|
class _FakeMetrics:
|
|
async def record_middleware_duration(self, middleware: str, channel_type: str, duration_s: float) -> None:
|
|
pass
|
|
|
|
async def record_pipeline_duration(self, channel_type: str, duration_s: float) -> None:
|
|
pass
|
|
|
|
async def record_pipeline_total(self, channel_type: str) -> None:
|
|
pass
|
|
|
|
async def record_pipeline_aborted(self, channel_type: str, reason: str) -> None:
|
|
pass
|
|
|
|
async def record_worker_dispatch_duration(self, channel_type: str, duration_s: float) -> None:
|
|
pass
|
|
|
|
async def record_worker_dispatch_total(self, channel_type: str, result: str) -> None:
|
|
pass
|
|
|
|
async def record_worker_step_duration(self, step: str, channel_type: str, duration_s: float) -> None:
|
|
pass
|
|
|
|
async def set_outbox_pending(self, count: int) -> None:
|
|
pass
|
|
|
|
async def record_outbox_enqueued(self, channel_type: str) -> None:
|
|
pass
|
|
|
|
async def set_sse_connections(self, count: int) -> None:
|
|
pass
|
|
|
|
async def record_auth_attempts(self, result: str) -> None:
|
|
pass
|
|
|
|
async def record_bot_loop_blocked(self, channel_type: str, context: str) -> None:
|
|
pass
|
|
|
|
async def record_access_policy_blocked(self, channel_type: str, policy: str) -> None:
|
|
pass
|
|
|
|
async def record_mention_gate_skipped(self, channel_type: str) -> None:
|
|
pass
|
|
|
|
async def record_hooks_received(self, match_path: str) -> None:
|
|
pass
|
|
|
|
async def record_content_filter_blocked(self, channel_type: str) -> None:
|
|
pass
|
|
|
|
async def set_circuit_breaker_state(self, agent_config_id: int, state: int) -> None:
|
|
pass
|
|
|
|
async def record_circuit_breaker_rejected(self, agent_config_id: int) -> None:
|
|
pass
|
|
|
|
|
|
@pytest.fixture
|
|
def auth_service() -> AuthService:
|
|
return AuthService(rate_limit_port=_FakeRateLimiter(), token="token")
|
|
|
|
|
|
@pytest.fixture
|
|
def base_kwargs(auth_service: AuthService) -> dict:
|
|
return {
|
|
"auth_service": auth_service,
|
|
"cache_port": _FakeCache(),
|
|
"rate_limit_port": _FakeRateLimiter(),
|
|
"queue_port": _FakeQueue(),
|
|
}
|
|
|
|
|
|
def test_build_inbound_pipeline_returns_pipeline(base_kwargs: dict) -> None:
|
|
pipeline = build_inbound_pipeline(**base_kwargs)
|
|
assert isinstance(pipeline, Pipeline)
|
|
assert len(pipeline.middlewares) == 7
|
|
|
|
|
|
def test_build_inbound_pipeline_with_bot_id(base_kwargs: dict) -> None:
|
|
pipeline = build_inbound_pipeline(**base_kwargs, bot_id="bot-123")
|
|
assert isinstance(pipeline, Pipeline)
|
|
|
|
|
|
def test_build_inbound_pipeline_with_custom_matcher(base_kwargs: dict) -> None:
|
|
pipeline = build_inbound_pipeline(**base_kwargs, keyword_matcher=_FakeKeywordMatcher())
|
|
assert isinstance(pipeline, Pipeline)
|
|
|
|
|
|
def test_build_inbound_pipeline_with_signature_verifier(base_kwargs: dict) -> None:
|
|
pipeline = build_inbound_pipeline(**base_kwargs, signature_verifier=_FakeSignatureVerifier())
|
|
assert isinstance(pipeline, Pipeline)
|
|
|
|
|
|
def test_build_inbound_pipeline_with_metrics(base_kwargs: dict) -> None:
|
|
pipeline = build_inbound_pipeline(**base_kwargs, metrics=_FakeMetrics())
|
|
assert isinstance(pipeline, Pipeline)
|
|
|
|
|
|
def test_build_inbound_pipeline_with_channel_config(base_kwargs: dict) -> None:
|
|
config = {
|
|
"keyword_blocklist": ["bad"],
|
|
"allow_from": {"web": ["user-1"]},
|
|
"access_policies": {"web": {"dm_policy": "disabled"}},
|
|
}
|
|
pipeline = build_inbound_pipeline(**base_kwargs, channel_config=config)
|
|
assert isinstance(pipeline, Pipeline)
|