AgentEvalTool/tests/unit/test_campaign_report_loader.py
sinohqb f8d8450b1e refactor(report): unify campaign report loading behind one read model
「活动报告取数三件套」此前在报告/markdown/分析/对比等 7 处手写重复,
唯一深化产物 build_campaign_report_dict 被锁在周期对比私有角落。
升位为 report.py 的 load_campaign_report(session, campaign) 单一出口
(探索线 summarize_campaign_exploration 同口径),并把 8 处
scenario_names 推导式收敛为 ScenarioRepository.name_map() 窄方法。
纯结构重排、零行为变更,572 项测试全绿。
2026-08-04 03:30:29 +08:00

97 lines
3.6 KiB
Python
Raw Permalink 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.

"""活动报告读模型 load_campaign_report 与 ScenarioRepository.name_map 直测。
读模型是报告 / 分析 / 对比 / 导出共用的「取数 + 聚合」单一出口:
返回结果必须与手写三件套list_by_campaign + scenario_names + generate_campaign_report完全一致。
"""
from datetime import datetime, timedelta, timezone
import pytest
from agenteval.evaluation.report import generate_campaign_report, load_campaign_report
from agenteval.models import Campaign, CampaignPlanEntry, CampaignStatus, Case, CaseType, EvalRun, RunStatus, Scenario
from agenteval.storage.repository import CampaignRepository, RunRepository, ScenarioRepository
from sqlmodel import Session, SQLModel, create_engine
T0 = datetime(2026, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
@pytest.fixture()
def db_session(tmp_path):
from agenteval.storage.db import ( # noqa: F401
CampaignDB,
EvalResultDB,
EvalRunDB,
EvalTargetDB,
FileCategoryDB,
FileRecordDB,
ScenarioDB,
TurnDB,
)
engine = create_engine(
f"sqlite:///{tmp_path / 'loader.db'}",
connect_args={"check_same_thread": False},
)
SQLModel.metadata.create_all(engine)
session = Session(engine)
try:
yield session
finally:
session.close()
engine.dispose()
def _seed(session) -> Campaign:
ScenarioRepository(session).create(Scenario(
id="s-a", name="夜间问诊",
cases=[Case(id="c1", type=CaseType.SINGLE, messages=["hi"])],
))
campaign = CampaignRepository(session).create(Campaign(
name="cycle", target_id="t-1", window_seconds=12, time_scale=1.0,
plan=[CampaignPlanEntry(scenario_id="s-a", offset_seconds=0, count=1)],
))
campaign.status = CampaignStatus.RUNNING
campaign.started_at = T0
campaign = CampaignRepository(session).update(campaign)
RunRepository(session).create(EvalRun(
target_id="t-1", scenario_id="s-a", campaign_id=campaign.id,
status=RunStatus.COMPLETED, started_at=T0 + timedelta(seconds=1),
summary={"total_cases": 1, "passed_cases": 1, "pass_rate": 1.0, "avg_latency_ms": 100},
))
return campaign
def test_load_campaign_report_matches_manual_trio(db_session):
campaign = _seed(db_session)
report = load_campaign_report(db_session, campaign)
runs = RunRepository(db_session).list_by_campaign(campaign.id)
scenario_names = {s.id: s.name for s in ScenarioRepository(db_session).list_all()}
expected = generate_campaign_report(campaign, runs, scenario_names=scenario_names)
assert report == expected
cap = next(c for c in report["capability_summary"] if c["scenario_id"] == "s-a")
assert cap["scenario_name"] == "夜间问诊"
def test_load_campaign_report_empty_campaign(db_session):
campaign = CampaignRepository(db_session).create(Campaign(
name="empty", target_id="t-1", window_seconds=12,
plan=[CampaignPlanEntry(scenario_id="s-x", offset_seconds=0, count=1)],
))
report = load_campaign_report(db_session, campaign)
assert report["summary"]["total_runs"] == 0
assert report["capability_summary"] == []
def test_scenario_name_map(db_session):
_seed(db_session)
ScenarioRepository(db_session).create(Scenario(
id="s-b", name="缴费引导",
cases=[Case(id="c2", type=CaseType.SINGLE, messages=["缴费"])],
))
assert ScenarioRepository(db_session).name_map() == {"s-a": "夜间问诊", "s-b": "缴费引导"}
def test_scenario_name_map_empty(db_session):
assert ScenarioRepository(db_session).name_map() == {}