AgentEvalTool/tests/integration/test_router_orm_guards.py
sinohqb eb4944a8bd feat(intelligent-eval): terminal-state discipline watchdogs (ADR-0011)
常见故障自愈有上限,超限收敛终态且可见:任务 attempts 上限、会话过期、
planning 双闸、executing 超窗兜底、触发失败计数判死、孤儿 agent 双管、
fire-and-forget 触发;open_session 预算硬闸门、settle 按终态区分、报告
scores 归一化;cron 池遗留面全删。
2026-08-20 14:34:17 +08:00

129 lines
3.7 KiB
Python

"""Router ORM contract guards (Gitea issue #6 / T3).
These tests pin the observable behaviour of router endpoints that currently
embed ORM writes directly (S2). When those handlers are later moved into a
service, the tests should still pass unchanged — that is the contract.
"""
import pytest
from agenteval.intelligent_eval.models import IntelligentEvalStatus
from agenteval.storage.db import (
IntelligentEvalDB,
IntelligentEvalDecisionLogDB,
)
from agenteval.web.app import app
from agenteval.web.deps import get_db
from fastapi.testclient import TestClient
from sqlmodel import Session, SQLModel, create_engine, select
@pytest.fixture()
def client(tmp_path):
from agenteval.storage.db import ( # noqa: F401
IntelligentEvalDB,
IntelligentEvalSessionDB,
IntelligentEvalTaskQueueDB,
)
engine = create_engine(
f"sqlite:///{tmp_path / 'test.db'}",
connect_args={"check_same_thread": False},
)
SQLModel.metadata.create_all(engine)
session = Session(engine)
def override_get_db():
try:
yield session
finally:
pass
app.dependency_overrides[get_db] = override_get_db
yield TestClient(app)
app.dependency_overrides.clear()
session.close()
engine.dispose()
@pytest.fixture()
def db_session(client):
return next(app.dependency_overrides[get_db]())
# T3.2 — decision-logs POST persists to DB
def test_create_decision_log_persists(client: TestClient, db_session: Session):
import uuid
eval_db = IntelligentEvalDB(
id=str(uuid.uuid4()),
name="eval-dl",
target_id="t1",
status=IntelligentEvalStatus.EXECUTING.value,
)
db_session.add(eval_db)
db_session.commit()
response = client.post(
f"/api/intelligent-evals/{eval_db.id}/decision-logs",
json={
"decision_type": "execute_session",
"reason": "slot_due",
"context": {"slot": "8-10h", "deficit": 2},
"cron_id": "cron-1",
},
)
assert response.status_code == 200
logs = db_session.exec(
select(IntelligentEvalDecisionLogDB).where(
IntelligentEvalDecisionLogDB.eval_id == eval_db.id
)
).all()
assert len(logs) == 1
assert logs[0].decision_type == "execute_session"
assert logs[0].reason == "slot_due"
def test_create_decision_log_404_for_unknown_eval(client: TestClient):
import uuid
response = client.post(
f"/api/intelligent-evals/{uuid.uuid4()}/decision-logs",
json={
"decision_type": "execute_session",
"reason": "slot_due",
"context": {},
"cron_id": "cron-1",
},
)
assert response.status_code == 404
# T3.3 — decision-logs GET lists logs
def test_list_decision_logs_returns_inserted(client: TestClient, db_session: Session):
import uuid
eval_db = IntelligentEvalDB(
id=str(uuid.uuid4()),
name="eval-dl-list",
target_id="t1",
status=IntelligentEvalStatus.EXECUTING.value,
)
db_session.add(eval_db)
db_session.commit()
for dtype in ("execute_session", "wait", "start_analysis"):
r = client.post(
f"/api/intelligent-evals/{eval_db.id}/decision-logs",
json={"decision_type": dtype, "reason": "test", "context": {}, "cron_id": "cron-1"},
)
assert r.status_code == 200
response = client.get(f"/api/intelligent-evals/{eval_db.id}/decision-logs")
assert response.status_code == 200
data = response.json()
assert "logs" in data
types = {log["decision_type"] for log in data["logs"]}
assert types == {"execute_session", "wait", "start_analysis"}