Files
ewoooc/tests/test_deepseek_service.py
OoO f11b0cc732 test(p19): 補 Phase 14/15/16/17 unit test — 27 tests 全綠
Operation Ollama-First v5.0 / Phase 19 — 補完戰役紀律

tests/test_caller_registry.py (7 tests)
- registry 含 30+ 核心 caller (ADR-028 對齊)
- is_known_caller / assert_known_caller strict=False/True 行為
- ai_call_logger 整合:未知 caller log warning 不阻擋
- frozenset 不可變動

tests/test_deepseek_service.py (6 tests)
- is_available() 需 KEY + flag 雙條件
- generate flag OFF / 200 success / 500 / timeout
- usage tokens 解析(prompt_tokens / completion_tokens)

tests/test_ppt_vision_service.py (6 tests)
- flag OFF 不打 HTTP / 檔不存在
-  無視覺異常 / ⚠️ marker 解析
- HTTP 500 觸發 mark_unhealthy / timeout fail-safe

tests/test_low_quality_response_v2.py (8 tests)
- 規則 5 純英文回應 (中文 < 30%)
- 規則 6 thinking-mode 漏洞 <think>...</think>
- 規則 7 重複迴圈 (前 50 字 ≥ 3 次)
- 規則 8 佔位符 ({{var}} / [TODO] / <待填>)
- 合法繁中商業文字應通過 8 條規則

regression: 全戰役 unit test 累計 241 tests
- Phase 1: 52 (logger + report)
- Phase 2: 14 (ollama_resolve)
- Phase 3: 36 (qa/golden/nemotron/daily)
- Phase 7: 23 (anthropic + code_review)
- Phase 11: 70 (rag + learning + promotion)
- Phase 10.5: 8 (mcp_router)
- Phase 13: 10 (retry chain)
- Phase 19: 27 (caller_registry + deepseek + ppt_vision + lq_v2)  新

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 10:27:35 +08:00

119 lines
3.9 KiB
Python
Raw Permalink 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.
"""
tests/test_deepseek_service.py
─────────────────────────────────────────────────────────────────
Operation Ollama-First v5.0 / Phase 15 — DeepSeek 直連 service 驗證
"""
from unittest.mock import patch, MagicMock
import pytest
@pytest.fixture(autouse=True)
def _reset_env(monkeypatch):
"""每 test 清 env"""
monkeypatch.delenv('DEEPSEEK_DIRECT_ENABLED', raising=False)
monkeypatch.delenv('DEEPSEEK_API_KEY', raising=False)
yield
def test_is_available_requires_key_and_flag(monkeypatch):
from services.deepseek_service import DeepSeekService
svc = DeepSeekService()
# 無 key 無 flag → False
assert svc.is_available() is False
# 只有 flag → False
monkeypatch.setenv('DEEPSEEK_DIRECT_ENABLED', 'true')
assert svc.is_available() is False
# flag + key → True需 reload module 取新 env
monkeypatch.setenv('DEEPSEEK_API_KEY', 'sk-test')
import importlib
import services.deepseek_service as ds
importlib.reload(ds)
assert ds.deepseek_service.is_available() is True
def test_generate_returns_failure_when_unavailable(monkeypatch):
"""flag OFF 時 generate 直接 return failure不打 HTTP"""
monkeypatch.setenv('DEEPSEEK_DIRECT_ENABLED', 'false')
from services.deepseek_service import DeepSeekService
svc = DeepSeekService()
with patch('services.deepseek_service.requests.post') as mock_post:
resp = svc.generate('test prompt')
assert resp.success is False
assert 'DEEPSEEK_DIRECT_ENABLED=false' in (resp.error or '') or \
'API_KEY 未設' in (resp.error or '')
mock_post.assert_not_called()
def test_generate_success_parses_usage(monkeypatch):
"""正常 200 回應應解 usage tokens"""
monkeypatch.setenv('DEEPSEEK_DIRECT_ENABLED', 'true')
monkeypatch.setenv('DEEPSEEK_API_KEY', 'sk-test')
import importlib
import services.deepseek_service as ds
importlib.reload(ds)
fake_resp = MagicMock(status_code=200)
fake_resp.json.return_value = {
'model': 'deepseek-chat',
'choices': [{'message': {'content': 'Hello from DeepSeek'}}],
'usage': {'prompt_tokens': 100, 'completion_tokens': 50},
}
with patch('services.deepseek_service.requests.post', return_value=fake_resp):
resp = ds.deepseek_service.generate('hi', system_prompt='you are helpful')
assert resp.success is True
assert resp.content == 'Hello from DeepSeek'
assert resp.input_tokens == 100
assert resp.output_tokens == 50
assert resp.model == 'deepseek-chat'
def test_generate_http_500_returns_failure(monkeypatch):
monkeypatch.setenv('DEEPSEEK_DIRECT_ENABLED', 'true')
monkeypatch.setenv('DEEPSEEK_API_KEY', 'sk-test')
import importlib
import services.deepseek_service as ds
importlib.reload(ds)
fake_resp = MagicMock(status_code=500)
fake_resp.text = 'Internal Server Error'
with patch('services.deepseek_service.requests.post', return_value=fake_resp):
resp = ds.deepseek_service.generate('test')
assert resp.success is False
assert 'HTTP 500' in (resp.error or '')
def test_generate_timeout_returns_failure(monkeypatch):
monkeypatch.setenv('DEEPSEEK_DIRECT_ENABLED', 'true')
monkeypatch.setenv('DEEPSEEK_API_KEY', 'sk-test')
import importlib
import services.deepseek_service as ds
importlib.reload(ds)
import requests
with patch('services.deepseek_service.requests.post',
side_effect=requests.Timeout('60s')):
resp = ds.deepseek_service.generate('test')
assert resp.success is False
assert 'timeout' in (resp.error or '').lower()
def test_check_connection_when_unavailable():
from services.deepseek_service import DeepSeekService
svc = DeepSeekService()
# 無 key 無 flag
assert svc.check_connection() is False