AgentEvalTool/tests/integration/test_scenarios_api.py
sinohqb 43e05ee38d feat(scenario): system-maintained syllabus version (ticket 03)
场景新增整型 version(迁移回填 1,batch mode)。仅考纲字段
(cases / model_bindings / llm_config)变更时升版,元数据编辑不升版,
API 传入的 version 被忽略(ADR-0001)。前端场景列表展示版本标签。
2026-07-29 10:42:35 +08:00

129 lines
4.6 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.

"""Integration tests for /api/scenarios versioning (ticket 03).
场景版本由系统维护ADR-0001仅考纲字段cases / model_bindings /
llm_config变更时递增元数据编辑不升版API 不接受外部指定版本。
"""
import pytest
from cryptography.fernet import Fernet
from httpx import ASGITransport, AsyncClient
from agenteval.services.model_configs import ModelConfigService, SecretCipher
from agenteval.web.app import app
pytestmark = pytest.mark.anyio
@pytest.fixture()
def scenario_client(db_session, monkeypatch):
from agenteval.web import app as app_module
monkeypatch.setattr(app_module, "init_db", lambda: None)
from agenteval.web.deps import get_db
def _test_get_db():
try:
yield db_session
finally:
pass
app.dependency_overrides[get_db] = _test_get_db
yield db_session
app.dependency_overrides.clear()
def _client() -> AsyncClient:
return AsyncClient(transport=ASGITransport(app=app), base_url="http://test")
_BODY = {
"name": "版本测试场景",
"description": "初始",
"tags": ["v"],
"cases": [{"id": "c1", "type": "single", "messages": ["hi"]}],
}
async def _create(client) -> dict:
resp = await client.post("/api/scenarios", json=_BODY)
assert resp.status_code == 200, resp.text
return resp.json()
async def test_create_scenario_version_starts_at_1(scenario_client):
async with _client() as client:
created = await _create(client)
assert created["version"] == 1
async def test_editing_cases_bumps_version(scenario_client):
async with _client() as client:
created = await _create(client)
body = {**_BODY, "cases": _BODY["cases"] + [{"id": "c2", "type": "single", "messages": ["yo"]}]}
resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
assert resp.status_code == 200
assert resp.json()["version"] == 2
async def test_editing_llm_config_bumps_version(scenario_client):
async with _client() as client:
created = await _create(client)
body = {**_BODY, "llm_config": {"model": "gpt-x"}}
resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
assert resp.json()["version"] == 2
async def test_editing_model_bindings_bumps_version(scenario_client, db_session):
service = ModelConfigService(db_session, SecretCipher(Fernet.generate_key().decode("ascii")))
config = service.create(
name="judge", provider="openai_compatible", capability="chat",
endpoint_url="https://m.example.com/v1/chat/completions",
model_name="m", api_key="k", enabled=True, is_default=False, description="",
)
async with _client() as client:
created = await _create(client)
body = {**_BODY, "model_bindings": {"judge": config.id}}
resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
assert resp.status_code == 200, resp.text
assert resp.json()["version"] == 2
async def test_metadata_edit_does_not_bump_version(scenario_client):
async with _client() as client:
created = await _create(client)
body = {**_BODY, "name": "改名了", "description": "新描述", "tags": ["x", "y"]}
resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
assert resp.status_code == 200
assert resp.json()["version"] == 1
assert resp.json()["name"] == "改名了"
async def test_resaving_identical_syllabus_does_not_bump_version(scenario_client):
"""原样重存(考纲逐字节相同)不升版——序列化形态回归护栏。"""
async with _client() as client:
created = await _create(client)
resp = await client.put(f"/api/scenarios/{created['id']}", json=_BODY)
assert resp.status_code == 200
assert resp.json()["version"] == 1
async def test_external_version_is_ignored(scenario_client):
async with _client() as client:
resp = await client.post("/api/scenarios", json={**_BODY, "version": 99})
assert resp.json()["version"] == 1
created = resp.json()
body = {**_BODY, "version": 42} # 元数据未变、考纲未变 → 版本保持 1
resp = await client.put(f"/api/scenarios/{created['id']}", json=body)
assert resp.json()["version"] == 1
async def test_list_and_get_return_version(scenario_client):
async with _client() as client:
created = await _create(client)
listed = (await client.get("/api/scenarios")).json()
assert all("version" in s for s in listed)
got = (await client.get(f"/api/scenarios/{created['id']}")).json()
assert got["version"] == 1