合并两个不可分割的深化: Phase 2 — 智能作业结算统一(ADR-0012) - intelligence_jobs.execute(job_kind, campaign_id, ...) 作为结算的 唯一实现:建行 → 认领 → 校验 → generating → 落账,一处编排、 一处截断(500 字符)。两个 executor 退化为 ensure_queued / validate / work_fn 三个小 adapter。 - analysis.validate_analysis_request() 共享校验入口(活动终态 → 模型),路由捕获映射 400、executor 捕获落 failed 行,与 validate_comparison_request 先例同构。 - campaign_runner._auto_start_analysis 的跳过守卫收敛至 auto_intelligence_eligible 单一判断点。 - comparison.py 删除零调用的 build_comparison_payload; load_comparison_view 投影归位至 campaign_read_model。 - 新增 characterization 测试(认领竞争、重复触发、截断、恢复上限)。 Phase 3 — storage/repository.py 拆分 - AsyncJobRepository 及两个子类迁至 storage/async_job_repository.py(Phase 2 的 intelligence_jobs 与 comparison 必须 import 自该路径,故与 Phase 2 同 commit)。 - ExplorationSession / ExplorationMessage 迁至 storage/exploration_repository.py;repository.py 由 1180 行降至 约 814 行,grep 确认无残留符号。 - exploration 子模块与路由 import 全部更新;测试 import 跟随。 刻意不做:CAS 共享原语、app.py 五 registry 关停顺序归一 (ADR-0006 精神,等真实需求出现再议)。
101 lines
3.5 KiB
Python
101 lines
3.5 KiB
Python
"""Tests for load_campaign_view — the unified campaign read model."""
|
|
|
|
from uuid import uuid4
|
|
|
|
from agenteval.evaluation.report import load_campaign_view
|
|
from agenteval.models import (
|
|
Campaign,
|
|
CampaignPlanEntry,
|
|
CampaignStatus,
|
|
Case,
|
|
CaseType,
|
|
EvalTarget,
|
|
Scenario,
|
|
)
|
|
from agenteval.storage.async_job_repository import CampaignAnalysisRepository
|
|
from agenteval.storage.repository import (
|
|
CampaignRepository,
|
|
ScenarioRepository,
|
|
TargetRepository,
|
|
)
|
|
|
|
|
|
def _seed_campaign(db_session, *, status=CampaignStatus.COMPLETED):
|
|
target = TargetRepository(db_session).create(
|
|
EvalTarget(id=f"t-{uuid4().hex[:8]}", name="数字员工")
|
|
)
|
|
scenario = ScenarioRepository(db_session).create(
|
|
Scenario(
|
|
id=f"s-{uuid4().hex[:8]}",
|
|
name="查账单",
|
|
target_id=target.id,
|
|
cases=[Case(id="c-1", type=CaseType.SINGLE, messages=["你好"])],
|
|
)
|
|
)
|
|
campaign = CampaignRepository(db_session).create(
|
|
Campaign(
|
|
name="cycle",
|
|
target_id=target.id,
|
|
window_seconds=3600,
|
|
time_scale=1.0,
|
|
plan=[CampaignPlanEntry(scenario_id=scenario.id, offset_seconds=0, count=1)],
|
|
status=status,
|
|
started_at=None,
|
|
)
|
|
)
|
|
return campaign
|
|
|
|
|
|
def test_view_returns_all_four_keys(db_session):
|
|
"""View always returns report/exploration/analysis/comparison keys."""
|
|
campaign = _seed_campaign(db_session)
|
|
view = load_campaign_view(db_session, campaign)
|
|
assert "report" in view
|
|
assert "exploration" in view
|
|
assert "analysis" in view
|
|
assert "comparison" in view
|
|
|
|
|
|
def test_view_with_no_analysis_or_comparison(db_session):
|
|
"""No analysis, no comparison, no exploration → those keys are None."""
|
|
campaign = _seed_campaign(db_session)
|
|
view = load_campaign_view(db_session, campaign)
|
|
assert view["report"] is not None
|
|
assert view["analysis"] is None
|
|
assert view["comparison"] is None
|
|
assert view["exploration"] is None
|
|
|
|
|
|
def test_view_with_completed_analysis(db_session):
|
|
"""Completed analysis row → analysis key is non-None."""
|
|
campaign = _seed_campaign(db_session)
|
|
analyses = CampaignAnalysisRepository(db_session)
|
|
analyses.upsert(campaign.id, status="completed", result={"summary": "ok"})
|
|
view = load_campaign_view(db_session, campaign)
|
|
assert view["analysis"] is not None
|
|
assert view["analysis"]["summary"] == "ok"
|
|
|
|
|
|
def test_view_with_comparison(db_session):
|
|
"""Completed comparison row → comparison key is non-None and contains metric_diff."""
|
|
campaign = _seed_campaign(db_session)
|
|
# Create a baseline campaign for comparison
|
|
baseline = _seed_campaign(db_session)
|
|
comparisons = CampaignAnalysisRepository(db_session)
|
|
# Mark both as having completed analysis (required for comparison)
|
|
comparisons.upsert(baseline.id, status="completed", result={"summary": "baseline"})
|
|
comparisons.upsert(campaign.id, status="completed", result={"summary": "current"})
|
|
# Create a comparison row
|
|
from agenteval.storage.async_job_repository import CampaignPeriodComparisonRepository
|
|
|
|
cmp_repo = CampaignPeriodComparisonRepository(db_session)
|
|
cmp_repo.upsert(
|
|
campaign.id,
|
|
status="completed",
|
|
baseline_campaign_id=baseline.id,
|
|
result={"evolution": []},
|
|
)
|
|
view = load_campaign_view(db_session, campaign)
|
|
assert view["comparison"] is not None
|
|
assert view["comparison"]["status"] == "completed"
|