"""Tests for the campaign start_date scheduling gate on test execution. Block 3 fix: `Campaign.start_date` was persisted and displayed but never actually enforced — a test belonging to a campaign scheduled for the future could still be started immediately. `start_execution` now blocks this. """ from datetime import datetime, timedelta import pytest from app.domain.errors import BusinessRuleViolation from app.models.campaign import Campaign, CampaignTest from app.models.enums import TestState from app.models.technique import Technique from app.models.test import Test from app.services.test_workflow_service import start_execution def _seed_test_in_campaign(db, owner_id, start_date): tech = Technique(mitre_id="T1059.003", name="Windows Command Shell", tactic="execution", platforms=["windows"]) db.add(tech) db.flush() campaign = Campaign(name="Scheduled Campaign", type="custom", status="active", created_by=owner_id, start_date=start_date) db.add(campaign) db.flush() test = Test(technique_id=tech.id, name="Scheduled test", state=TestState.draft, created_by=owner_id) db.add(test) db.flush() db.add(CampaignTest(campaign_id=campaign.id, test_id=test.id, order_index=0)) db.commit() db.refresh(test) return test def test_start_execution_blocked_before_campaign_start_date(db, red_tech_user): future = datetime.utcnow() + timedelta(days=7) test = _seed_test_in_campaign(db, red_tech_user.id, future) with pytest.raises(BusinessRuleViolation): start_execution(db, test, red_tech_user) def test_start_execution_allowed_after_campaign_start_date(db, red_tech_user): past = datetime.utcnow() - timedelta(days=1) test = _seed_test_in_campaign(db, red_tech_user.id, past) result = start_execution(db, test, red_tech_user) assert result.state == TestState.red_executing def test_start_execution_allowed_for_standalone_test(db, red_tech_user): """A test with no campaign at all is never gated by this check.""" tech = Technique(mitre_id="T1059.004", name="Unix Shell", tactic="execution", platforms=["linux"]) db.add(tech) db.flush() test = Test(technique_id=tech.id, name="Standalone test", state=TestState.draft, created_by=red_tech_user.id) db.add(test) db.commit() db.refresh(test) result = start_execution(db, test, red_tech_user) assert result.state == TestState.red_executing def test_start_execution_allowed_when_campaign_has_no_start_date(db, red_tech_user): test = _seed_test_in_campaign(db, red_tech_user.id, None) result = start_execution(db, test, red_tech_user) assert result.state == TestState.red_executing