Files
Aether/tests/services/test_error_classifier_thinking.py
fawney19 440721368f feat: Antigravity 和 Codex 服务支持
- 新增 Antigravity 服务:签名缓存、URL 可用性检测、信封处理
- 新增 Codex 服务:信封处理、元数据收集器
- 重构 provider transport 支持新的服务架构
- 新增 stream_bridge 和 upstream_stream_bridge 处理流式响应
- 优化 OAuth 工具函数
- 添加相关测试用例
2026-02-05 15:59:41 +08:00

171 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
ErrorClassifier Thinking 错误模式测试
测试 ErrorClassifier 对 Thinking 相关错误的识别:
- 签名验证失败
- 结构错误(缺少 thinking 块前缀)
"""
from unittest.mock import MagicMock
import pytest
from src.services.orchestration.error_classifier import ErrorClassifier
class TestThinkingErrorPatterns:
"""测试 Thinking 错误模式匹配"""
@pytest.fixture
def classifier(self) -> ErrorClassifier:
mock_db = MagicMock()
return ErrorClassifier(db=mock_db)
# === 签名错误测试 ===
def test_detect_invalid_signature_with_backticks(self, classifier: ErrorClassifier) -> None:
"""检测带反引号的签名错误"""
error = '{"error": {"message": "invalid `signature` in `thinking` block"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_invalid_signature_without_backticks(self, classifier: ErrorClassifier) -> None:
"""检测不带反引号的签名错误"""
error = '{"error": {"message": "invalid signature in thinking block"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_signature_field_required(self, classifier: ErrorClassifier) -> None:
"""检测签名字段缺失错误"""
error = '{"error": {"message": "thinking.signature: field required"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_signature_path_pattern(self, classifier: ErrorClassifier) -> None:
"""检测签名路径模式(如 messages.0.content.0.thinking.signature"""
error = '{"error": {"message": "messages.0.content.0.thinking.signature: invalid"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_signature_verification_failed(self, classifier: ErrorClassifier) -> None:
"""检测签名验证失败"""
error = '{"error": {"message": "signature verification failed"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_thought_signature_patterns(self, classifier: ErrorClassifier) -> None:
"""检测 Antigravity/Gemini thoughtSignature 相关错误"""
error = '{"error": {"message": "invalid thoughtSignature in thought part"}}'
assert classifier._is_thinking_error(error) is True
error2 = '{"error": {"message": "thought_signature verification failed"}}'
assert classifier._is_thinking_error(error2) is True
# === 结构错误测试 ===
def test_detect_must_start_with_thinking_block(self, classifier: ErrorClassifier) -> None:
"""检测必须以 thinking 块开头的错误"""
error = '{"error": {"message": "content must start with a thinking block"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_or_redacted(self, classifier: ErrorClassifier) -> None:
"""检测期望 thinking 或 redacted_thinking 的错误"""
error = '{"error": {"message": "expected thinking or redacted_thinking"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_with_backticks(self, classifier: ErrorClassifier) -> None:
"""检测带反引号的 expected thinking 错误"""
error = '{"error": {"message": "expected `thinking`"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_found_tool_use(self, classifier: ErrorClassifier) -> None:
"""检测 expected thinking, found xxx 错误(统一模式匹配)"""
error = '{"error": {"message": "expected thinking, found tool_use"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_found_tool_use_backticks(
self, classifier: ErrorClassifier
) -> None:
"""检测带反引号的 expected `thinking`, found xxx 错误"""
error = '{"error": {"message": "expected `thinking`, found `tool_use`"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_found_text(self, classifier: ErrorClassifier) -> None:
"""检测 expected thinking, found text 错误"""
error = '{"error": {"message": "expected thinking, found text"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_thinking_found_text_backticks(
self, classifier: ErrorClassifier
) -> None:
"""检测带反引号的 expected `thinking`, found text 错误"""
error = '{"error": {"message": "expected `thinking`, found `text`"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_redacted_thinking(self, classifier: ErrorClassifier) -> None:
"""检测 expected redacted_thinking 错误"""
error = '{"error": {"message": "expected redacted_thinking, found text"}}'
assert classifier._is_thinking_error(error) is True
def test_detect_expected_redacted_thinking_backticks(self, classifier: ErrorClassifier) -> None:
"""检测带反引号的 expected redacted_thinking 错误"""
error = '{"error": {"message": "expected `redacted_thinking`, found `text`"}}'
assert classifier._is_thinking_error(error) is True
# === 真实错误响应测试 ===
def test_real_claude_signature_error(self, classifier: ErrorClassifier) -> None:
"""测试真实的 Claude 签名错误响应"""
error = """{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "messages.2.content.0: invalid `signature` in `thinking` block: signature is for a different request"
}
}"""
assert classifier._is_thinking_error(error) is True
def test_real_claude_structure_error(self, classifier: ErrorClassifier) -> None:
"""测试真实的 Claude 结构错误响应"""
error = """{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "messages.1.content: when `thinking` is enabled, the first content block in an assistant turn containing `tool_use` blocks must start with a `thinking` or `redacted_thinking` block. expected thinking or redacted_thinking, found tool_use."
}
}"""
assert classifier._is_thinking_error(error) is True
# === 负面测试 ===
def test_not_thinking_error_rate_limit(self, classifier: ErrorClassifier) -> None:
"""速率限制错误不应被识别为 thinking 错误"""
error = '{"error": {"message": "rate limit exceeded"}}'
assert classifier._is_thinking_error(error) is False
def test_not_thinking_error_invalid_api_key(self, classifier: ErrorClassifier) -> None:
"""API Key 错误不应被识别为 thinking 错误"""
error = '{"error": {"message": "invalid api key"}}'
assert classifier._is_thinking_error(error) is False
def test_not_thinking_error_model_not_found(self, classifier: ErrorClassifier) -> None:
"""模型不存在错误不应被识别为 thinking 错误"""
error = '{"error": {"message": "model not found"}}'
assert classifier._is_thinking_error(error) is False
def test_not_thinking_error_empty(self, classifier: ErrorClassifier) -> None:
"""空错误文本不应被识别为 thinking 错误"""
assert classifier._is_thinking_error("") is False
assert classifier._is_thinking_error(None) is False
def test_not_thinking_error_generic_signature(self, classifier: ErrorClassifier) -> None:
"""通用 signature 字样(非 thinking 相关)不应被误判"""
# 这个应该不匹配,因为模式要求是 thinking 相关的 signature
error = '{"error": {"message": "request signature mismatch"}}'
assert classifier._is_thinking_error(error) is False
# === 大小写不敏感测试 ===
def test_case_insensitive_matching(self, classifier: ErrorClassifier) -> None:
"""测试大小写不敏感匹配"""
error = '{"error": {"message": "INVALID `SIGNATURE` IN `THINKING` BLOCK"}}'
assert classifier._is_thinking_error(error) is True
error2 = '{"error": {"message": "Expected Thinking, Found Tool_Use"}}'
assert classifier._is_thinking_error(error2) is True