AgentEvalTool/tests/unit/test_llm_task_lifecycle.py

139 lines
5.1 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.

"""LLM 后台任务生命周期直测(架构保养第二轮候选 1
分析 / 对比 / judge 复核三条 LLM 任务链收进各自的 TaskRegistry
强引用防 GC、按 id 幂等、shutdown 统一收敛;启动清扫把滞留的
generating 行标记为 failed。
"""
import asyncio
import pytest
from agenteval.evaluation import analysis, comparison
from agenteval.exploration import judge
from agenteval.storage.repository import (
CampaignAnalysisRepository,
CampaignPeriodComparisonRepository,
)
from sqlmodel import Session, SQLModel, create_engine
@pytest.fixture()
def db_session(tmp_path):
from agenteval.storage.db import ( # noqa: F401
CampaignAnalysisDB,
CampaignDB,
CampaignPeriodComparisonDB,
)
engine = create_engine(
f"sqlite:///{tmp_path / 'llmtasks.db'}",
connect_args={"check_same_thread": False},
)
SQLModel.metadata.create_all(engine)
session = Session(engine)
try:
yield session
finally:
session.close()
engine.dispose()
async def test_start_analysis_registers_in_registry(monkeypatch):
monkeypatch.setattr(analysis, "execute_campaign_analysis", lambda *a, **kw: asyncio.sleep(0))
analysis.start_campaign_analysis("c-1", triggered_by="manual")
assert analysis.analysis_registry.is_running("c-1")
await analysis.analysis_registry.shutdown_all()
assert not analysis.analysis_registry.is_running("c-1")
async def test_start_comparison_registers_in_registry(monkeypatch):
monkeypatch.setattr(comparison, "execute_campaign_comparison", lambda *a, **kw: asyncio.sleep(0))
comparison.start_campaign_comparison("c-2", triggered_by="manual")
assert comparison.comparison_registry.is_running("c-2")
await comparison.comparison_registry.shutdown_all()
async def test_start_judge_registers_in_registry(monkeypatch):
monkeypatch.setattr(judge, "execute_judge_review", lambda *a, **kw: asyncio.sleep(0))
judge.start_judge_review("s-1")
assert judge.judge_registry.is_running("s-1")
await judge.judge_registry.shutdown_all()
async def test_launch_is_idempotent_for_live_id(monkeypatch):
gate = asyncio.Event()
async def hang(*args, **kwargs):
await gate.wait()
monkeypatch.setattr(analysis, "execute_campaign_analysis", hang)
analysis.start_campaign_analysis("c-dup", triggered_by="manual")
analysis.start_campaign_analysis("c-dup", triggered_by="manual")
assert len(analysis.analysis_registry._tasks) == 1
gate.set()
await analysis.analysis_registry.shutdown_all()
async def test_shutdown_all_cancels_hanging_task(monkeypatch):
async def hang(*args, **kwargs):
await asyncio.Event().wait()
monkeypatch.setattr(comparison, "execute_campaign_comparison", hang)
comparison.start_campaign_comparison("c-hang", triggered_by="manual")
assert comparison.comparison_registry.is_running("c-hang")
await comparison.comparison_registry.shutdown_all()
assert not comparison.comparison_registry.is_running("c-hang")
def test_mark_orphans_failed_flips_generating_analysis(db_session):
repo = CampaignAnalysisRepository(db_session)
repo.upsert("c-gen", status="generating", triggered_by="auto")
repo.upsert("c-done", status="completed", result={"ok": True}, triggered_by="auto")
count = repo.mark_orphans_failed()
assert count == 1
assert repo.get_by_campaign("c-gen").status == "failed"
assert repo.get_by_campaign("c-gen").error
assert repo.get_by_campaign("c-done").status == "completed"
def test_enqueue_analysis_persists_before_launch(db_session, monkeypatch):
from agenteval.evaluation import analysis
launched = []
monkeypatch.setattr(analysis, "get_session", lambda: db_session)
monkeypatch.setattr(analysis, "start_campaign_analysis", lambda cid, *, triggered_by: launched.append((cid, triggered_by)))
analysis.enqueue_campaign_analysis("c-queued", triggered_by="auto")
assert launched == [("c-queued", "auto")]
row = CampaignAnalysisRepository(db_session).get_by_campaign("c-queued")
assert row.status == "queued"
assert row.triggered_by == "auto"
def test_resume_queued_analysis_relaunches_persisted_jobs(db_session, monkeypatch):
from agenteval.evaluation import analysis
repo = CampaignAnalysisRepository(db_session)
repo.enqueue("c-queued", triggered_by="auto")
launched = []
monkeypatch.setattr(analysis, "start_campaign_analysis", lambda cid, *, triggered_by: launched.append((cid, triggered_by)))
assert analysis.resume_queued_campaign_analysis(db_session) == 1
assert launched == [("c-queued", "auto")]
def test_mark_orphans_failed_flips_generating_comparison(db_session):
repo = CampaignPeriodComparisonRepository(db_session)
repo.upsert("c-gen", status="generating", baseline_campaign_id="b-1", triggered_by="auto")
repo.upsert("c-done", status="completed", baseline_campaign_id="b-2", result={"ok": True}, triggered_by="auto")
count = repo.mark_orphans_failed()
assert count == 1
assert repo.get_by_campaign("c-gen").status == "failed"
assert repo.get_by_campaign("c-gen").error
assert repo.get_by_campaign("c-done").status == "completed"