"""Tests for idempotent Campaign completion and settlement ordering.""" import pytest from agenteval.evaluation.campaign_lifecycle import CampaignCancelError, complete_campaign from agenteval.models import Campaign, CampaignPlanEntry, CampaignStatus from agenteval.storage.repository import CampaignRepository def _campaign(session, status=CampaignStatus.RUNNING): return CampaignRepository(session).create( Campaign( id="campaign-1", name="campaign", target_id="t-1", status=status, window_seconds=60, plan=[CampaignPlanEntry(scenario_id="s-1", offset_seconds=0, count=1)], ) ) def test_complete_uses_cas_and_settles_after_commit(db_session): _campaign(db_session) observed = [] def settle(campaign_id, session): observed.append(CampaignRepository(session).get(campaign_id).status) completed = complete_campaign(db_session, "campaign-1", settle=settle) assert completed.status is CampaignStatus.COMPLETED assert completed.completed_at is not None assert observed == [CampaignStatus.COMPLETED] def test_complete_is_idempotency_guarded(db_session): _campaign(db_session) complete_campaign(db_session, "campaign-1") with pytest.raises(CampaignCancelError) as again: complete_campaign(db_session, "campaign-1") assert again.value.status_code == 409 def test_cancel_wins_completion_race(db_session): _campaign(db_session, CampaignStatus.CANCELLED) with pytest.raises(CampaignCancelError) as conflict: complete_campaign(db_session, "campaign-1") assert conflict.value.status_code == 409