Give EvalRun.summary a typed RunSummary value (unified RunError, lenient legacy parsing) so readers stop reaching into a schemaless dict, and route every cross-run rollup — dashboard, scenario ranking, trend, campaign report — through one aggregate_runs seam. Fixes the divergence where stats averaged pass_rate over completed-only runs while the campaign report counted faults as 0.0. Cross-run rule (ADR-0004): genuine faults count 0.0, user-cancelled runs are excluded from both denominators.
57 lines
2.0 KiB
Python
57 lines
2.0 KiB
Python
"""Startup cleanup of orphan runs (interrupted by server restart)."""
|
||
|
||
from agenteval.models import EvalRun, RunStatus
|
||
from agenteval.storage.repository import RunRepository
|
||
|
||
|
||
def _make_run(session, status: RunStatus) -> str:
|
||
run = RunRepository(session).create(EvalRun(
|
||
target_id="t-1", scenario_id="s-1", status=status,
|
||
))
|
||
return run.id
|
||
|
||
|
||
def test_mark_orphans_failed(db_session):
|
||
repo = RunRepository(db_session)
|
||
running_id = _make_run(db_session, RunStatus.RUNNING)
|
||
pending_id = _make_run(db_session, RunStatus.PENDING)
|
||
completed_id = _make_run(db_session, RunStatus.COMPLETED)
|
||
failed_id = _make_run(db_session, RunStatus.FAILED)
|
||
|
||
count = repo.mark_orphans_failed()
|
||
|
||
assert count == 2
|
||
for rid in (running_id, pending_id):
|
||
run = repo.get(rid)
|
||
assert run.status == RunStatus.FAILED
|
||
assert run.summary.error.code == "interrupted"
|
||
assert run.completed_at is not None
|
||
# 已完结的运行不受影响
|
||
assert repo.get(completed_id).status == RunStatus.COMPLETED
|
||
assert repo.get(failed_id).status == RunStatus.FAILED
|
||
assert repo.get(completed_id).summary is None
|
||
|
||
|
||
def test_mark_orphans_failed_noop_when_clean(db_session):
|
||
repo = RunRepository(db_session)
|
||
_make_run(db_session, RunStatus.COMPLETED)
|
||
assert repo.mark_orphans_failed() == 0
|
||
|
||
|
||
def test_update_preserves_scenario_version_and_triggered_by(db_session):
|
||
"""update() 不得丢字段:scenario_version / triggered_by 必须回写(漂移回归)。"""
|
||
from agenteval.models import RunTrigger
|
||
|
||
repo = RunRepository(db_session)
|
||
run = repo.create(EvalRun(
|
||
target_id="t-1", scenario_id="s-1", status=RunStatus.RUNNING,
|
||
scenario_version=4, triggered_by=RunTrigger.AI_ASSISTANT,
|
||
))
|
||
run.scenario_version = 5
|
||
run.triggered_by = RunTrigger.CLI
|
||
run.status = RunStatus.COMPLETED
|
||
updated = repo.update(run)
|
||
|
||
assert updated.scenario_version == 5
|
||
assert updated.triggered_by == RunTrigger.CLI
|