import pytest from app.pipeline.state_machine import ( next_state_on_approve, next_state_on_reject, can_transition, STEPS, USER_GATES, ) def test_steps_sequence(): assert STEPS == ["cover", "video", "thumb", "meta", "review", "publish"] def test_user_gates_excludes_review(): assert "review" not in USER_GATES assert "publish" in USER_GATES assert "cover" in USER_GATES def test_approve_progression(): assert next_state_on_approve("cover_pending") == "video_pending" assert next_state_on_approve("video_pending") == "thumb_pending" assert next_state_on_approve("thumb_pending") == "meta_pending" assert next_state_on_approve("meta_pending") == "ai_review" assert next_state_on_approve("publish_pending") == "publishing" def test_approve_invalid_state_raises(): with pytest.raises(ValueError): next_state_on_approve("ai_review") # 자동 전이 — approve 호출 자체가 무효 def test_reject_keeps_same_state(): # 반려는 같은 *_pending 상태를 유지(재생성 트리거) assert next_state_on_reject("cover_pending") == "cover_pending" assert next_state_on_reject("publish_pending") == "publish_pending" def test_can_transition_blocks_terminal_states(): assert not can_transition("published", "cover_pending") assert not can_transition("cancelled", "cover_pending") assert not can_transition("failed", "cover_pending") def test_can_transition_allows_cancel_from_anywhere(): assert can_transition("cover_pending", "cancelled") assert can_transition("publishing", "cancelled") def test_can_transition_allows_failed_from_pending(): assert can_transition("video_pending", "failed") assert can_transition("publishing", "failed")