"""knowledge_service 硬编码默认 DeepSeek Key 清理回归(2026-10-18 P2 代码卫生) 覆盖: 1. 缺 DEEPSEEK_API_KEY → 抛 DeepSeekKeyMissing(不再拿假 Key 发请求) 2. 有 DEEPSEEK_API_KEY → 正常走请求链路并返回内容 3. API 层:缺 Key 时 /knowledge/generate/daily 返回 503 且错误可观测(非静默模板兜底) 4. API 层:有 Key 时行为不变(200 + 写入摘要) """ import asyncio import types import pytest from fastapi.testclient import TestClient from sqlalchemy.orm import Session from app.services import knowledge_service from app.services.knowledge_service import DeepSeekKeyMissing from tests.conftest import create_test_user, get_token_for_user, auth_header class _FakeResp: status_code = 200 def json(self): return {"choices": [{"message": {"content": "测试摘要:本期无重大变化。"}}]} class _FakeAsyncClient: def __init__(self, *a, **kw): pass async def __aenter__(self): return self async def __aexit__(self, *a): return False async def post(self, *a, **kw): return _FakeResp() def _patch_httpx(monkeypatch): """只替换 knowledge_service 模块内的 httpx 引用,不动全局模块。""" monkeypatch.setattr( knowledge_service, "httpx", types.SimpleNamespace(AsyncClient=_FakeAsyncClient) ) # ── 服务层 ── def test_service_raises_when_key_missing(monkeypatch): monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False) with pytest.raises(DeepSeekKeyMissing) as ei: asyncio.run(knowledge_service._call_deepseek("hello")) assert "DEEPSEEK_API_KEY" in str(ei.value) def test_service_works_when_key_present(monkeypatch): monkeypatch.setenv("DEEPSEEK_API_KEY", "sk-test-not-a-real-key") _patch_httpx(monkeypatch) out = asyncio.run(knowledge_service._call_deepseek("hello")) assert out == "测试摘要:本期无重大变化。" def test_require_key_strips_blank(monkeypatch): monkeypatch.setenv("DEEPSEEK_API_KEY", " ") with pytest.raises(DeepSeekKeyMissing): knowledge_service._require_deepseek_key() # ── API 层 ── def test_api_generate_daily_returns_503_without_key(client: TestClient, db: Session, monkeypatch): create_test_user(db) token = get_token_for_user(client, username="testadmin") monkeypatch.delenv("DEEPSEEK_API_KEY", raising=False) r = client.post("/api/cma/knowledge/generate/daily", headers=auth_header(token)) assert r.status_code == 503, r.text detail = r.json()["detail"] assert "DEEPSEEK_API_KEY" in detail, detail def test_api_generate_daily_ok_with_key(client: TestClient, db: Session, monkeypatch): create_test_user(db) token = get_token_for_user(client, username="testadmin") monkeypatch.setenv("DEEPSEEK_API_KEY", "sk-test-not-a-real-key") _patch_httpx(monkeypatch) r = client.post("/api/cma/knowledge/generate/daily", headers=auth_header(token)) assert r.status_code == 200, r.text assert r.json()["summary"]["entity_id"] == 1