1. 删除了 test/unit/external_systems/framework/ 下的废弃空测试目录 2. 修复多处测试断言逻辑、参数传递与测试数据构造 3. 新增日志级别、缓存令牌、流事件等DTO单元测试 4. 补充路由绑定、会话仓储、outbox仓储的测试覆盖 5. 更新测试用例中的异常类型、参数校验与业务逻辑断言
144 lines
4.0 KiB
Python
144 lines
4.0 KiB
Python
"""streaming.py DTO 单元测试。
|
|
|
|
覆盖 ``ChunkMode`` / ``RenderStrategy`` / ``StreamChunk`` / ``ChunkResult`` /
|
|
``StreamingCompleted`` / ``StreamingCapability`` / ``StreamingConfig`` 的
|
|
字段赋值、默认值、不可变语义与 ``__post_init__`` 校验逻辑。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import dataclasses
|
|
|
|
import pytest
|
|
from yuxi.channels.contract.dtos.streaming import (
|
|
ChunkMode,
|
|
ChunkResult,
|
|
RenderStrategy,
|
|
StreamChunk,
|
|
StreamingCapability,
|
|
StreamingCompleted,
|
|
StreamingConfig,
|
|
)
|
|
from yuxi.channels.contract.errors import ValidationError
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestChunkMode:
|
|
"""分块模式枚举测试。"""
|
|
|
|
def test_str_values(self):
|
|
assert ChunkMode.NONE == "none"
|
|
assert ChunkMode.TEXT == "text"
|
|
assert ChunkMode.BLOCK == "block"
|
|
assert ChunkMode.FULL_UPDATE == "full_update"
|
|
assert ChunkMode.PARTIAL_UPDATE == "partial_update"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestRenderStrategy:
|
|
"""卡片渲染策略枚举测试。"""
|
|
|
|
def test_str_values(self):
|
|
assert RenderStrategy.APPEND == "append"
|
|
assert RenderStrategy.REPLACE == "replace"
|
|
assert RenderStrategy.MERGE == "merge"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestStreamChunk:
|
|
"""流式分块 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned_with_defaults(self):
|
|
# Act
|
|
chunk = StreamChunk(content="hello", sequence=0)
|
|
# Assert
|
|
assert chunk.is_final is False
|
|
|
|
def test_is_frozen(self):
|
|
# Arrange
|
|
chunk = StreamChunk(content="hello", sequence=0)
|
|
# Act / Assert
|
|
with pytest.raises(dataclasses.FrozenInstanceError):
|
|
chunk.content = "other" # type: ignore[misc]
|
|
|
|
def test_empty_content_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
StreamChunk(content="", sequence=0)
|
|
assert exc_info.value.field == "content"
|
|
|
|
def test_negative_sequence_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
StreamChunk(content="hello", sequence=-1)
|
|
assert exc_info.value.field == "sequence"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestChunkResult:
|
|
"""分块结果 DTO 测试。"""
|
|
|
|
def test_fields_are_assigned_with_defaults(self):
|
|
# Act
|
|
result = ChunkResult(
|
|
chunk=StreamChunk(content="hello", sequence=0),
|
|
success=True,
|
|
)
|
|
# Assert
|
|
assert result.error is None
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestStreamingCompleted:
|
|
"""流式完成结果 DTO 测试。"""
|
|
|
|
def test_valid_construction(self):
|
|
# Act
|
|
result = StreamingCompleted(total_chunks=5, duration_ms=1000)
|
|
# Assert
|
|
assert result.total_chunks == 5
|
|
|
|
def test_zero_total_chunks_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
StreamingCompleted(total_chunks=0, duration_ms=100)
|
|
assert exc_info.value.field == "total_chunks"
|
|
|
|
def test_negative_duration_raises(self):
|
|
# Act / Assert
|
|
with pytest.raises(ValidationError) as exc_info:
|
|
StreamingCompleted(total_chunks=1, duration_ms=-1)
|
|
assert exc_info.value.field == "duration_ms"
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestStreamingCapability:
|
|
"""流式能力 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
cap = StreamingCapability()
|
|
# Assert
|
|
assert cap.supports_streaming is False
|
|
assert cap.supports_typing_indicator is False
|
|
assert cap.chunk_mode == ChunkMode.NONE
|
|
assert cap.min_chunk_interval_ms == 0
|
|
assert cap.max_chunk_length == 0
|
|
|
|
|
|
@pytest.mark.unit
|
|
class TestStreamingConfig:
|
|
"""流式配置 DTO 测试。"""
|
|
|
|
def test_defaults(self):
|
|
# Act
|
|
config = StreamingConfig()
|
|
# Assert
|
|
assert config.streaming_enabled is False
|
|
assert config.enable_typing is True
|
|
assert config.min_chunk_interval_ms == 200
|
|
assert config.streaming_ttl_ms == 60000
|
|
assert config.typing_ttl_ms == 10000
|