c5d0f4c63e
- 移除 conftest 中对 app.api.deps 的全局依赖覆盖:该覆盖会绕过真实 会话鉴权,导致 /auth/*、文档变更、用户管理等鉴权测试(期望 1005/1006/1001) 误判为通过。鉴权测试现走真实 UserStore/SessionStore。 - 检索与知识类查询端点(POST /search、GET /knowledge/categories、GET /knowledge/stats)改为免登录:与测试套件明确声明的「查询类端点免登录」 设计意图一致,同时保留文档变更、/auth/*、Settings 变更端点的登录要求。 变更文件:tests/conftest.py、app/api/v1/search.py、app/api/v1/knowledge.py
82 lines
3.0 KiB
Python
82 lines
3.0 KiB
Python
"""pytest 全局夹具
|
||
|
||
鉴权采用 app.api.deps 的会话体系(UserStore / SessionStore):
|
||
- 文档变更类端点(POST /documents、/documents/upload、DELETE /documents/{id})、
|
||
/auth/* 与 Settings 变更端点需要登录;
|
||
- 查询类端点(POST /search、GET /knowledge/*、GET /documents*、
|
||
GET /documents/{id}/file)免登录。
|
||
|
||
auth_stores / admin_headers 夹具注入内存存储并签发真实 session token,
|
||
供需要登录的接口测试使用;查询类端点测试直接无 token 调用即可,无需覆盖依赖。
|
||
|
||
另外清理 LLM 客户端 / 解析插件 / 去重策略三处进程级缓存,避免跨测试串扰
|
||
(不同测试可能注入不同的 redis/ollama 实例,缓存按配置签名而非实例区分)。
|
||
"""
|
||
|
||
import asyncio
|
||
from typing import Any
|
||
|
||
import pytest
|
||
|
||
|
||
@pytest.fixture
|
||
def auth_stores(monkeypatch: pytest.MonkeyPatch):
|
||
"""注入内存 UserStore/SessionStore 到 deps 单例,并预置 admin 账号(admin/admin-pass-123)
|
||
|
||
同时关闭 lifespan 的默认管理员引导,避免测试库被写入随机密码账号。
|
||
返回 (user_store, session_store),测试可直接操作用户数据。
|
||
"""
|
||
import app.main as main_module
|
||
from app.api import deps
|
||
from app.core.sessions import SessionStore
|
||
from app.core.users import UserStore
|
||
|
||
user_store = UserStore(None)
|
||
session_store = SessionStore(None)
|
||
monkeypatch.setattr(deps, "_user_store", user_store)
|
||
monkeypatch.setattr(deps, "_session_store", session_store)
|
||
|
||
async def _noop_bootstrap(*args: Any, **kwargs: Any) -> None:
|
||
return None
|
||
|
||
monkeypatch.setattr(main_module, "bootstrap_admin", _noop_bootstrap)
|
||
|
||
async def _seed() -> None:
|
||
await user_store.create("admin", "admin-pass-123", role="admin")
|
||
|
||
asyncio.run(_seed())
|
||
return user_store, session_store
|
||
|
||
|
||
@pytest.fixture
|
||
def admin_headers(auth_stores) -> dict[str, str]:
|
||
"""为内存 admin 签发真实 session,返回 Authorization Bearer 请求头"""
|
||
_, session_store = auth_stores
|
||
|
||
async def _login() -> str:
|
||
return await session_store.create("admin", "admin")
|
||
|
||
token = asyncio.run(_login())
|
||
return {"Authorization": f"Bearer {token}"}
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _invalidate_runtime_caches():
|
||
"""每个测试前后清理 LLM/解析插件/去重策略进程级缓存
|
||
|
||
这三处缓存按 runtime_settings 配置签名而非实例区分,跨测试若配置相同
|
||
会复用旧实例(绑定到上个测试的 redis/ollama 替身),导致串扰。
|
||
"""
|
||
# 延迟导入避免循环依赖
|
||
from app.core.dedup import invalidate_dedup_strategy_cache
|
||
from app.core.file_parser import invalidate_parser_plugin_cache
|
||
from app.services.llm import invalidate_llm_client_cache
|
||
|
||
invalidate_llm_client_cache()
|
||
invalidate_parser_plugin_cache()
|
||
invalidate_dedup_strategy_cache()
|
||
yield
|
||
invalidate_llm_client_cache()
|
||
invalidate_parser_plugin_cache()
|
||
invalidate_dedup_strategy_cache()
|