| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- """
- Unit tests for pipeline state management.
- Tests cover state definitions, transition rules, and validation functions.
- """
- import pytest
- from src.core.states import PipelineState
- from src.core.transitions import (
- is_transition_allowed,
- get_allowed_transitions,
- can_pause_from,
- can_resume_to,
- ALLOWED_TRANSITIONS,
- )
- class TestPipelineState:
- """Test PipelineState enum functionality."""
- def test_all_states_defined(self):
- """Test that all required states are defined."""
- required_states = {
- "IDLE",
- "FINGERPRINTING",
- "CLEANING",
- "TERM_EXTRACTION",
- "TRANSLATING",
- "UPLOADING",
- "PAUSED",
- "COMPLETED",
- "FAILED",
- }
- actual_states = {state.name for state in PipelineState}
- assert actual_states == required_states
- def test_state_values(self):
- """Test that state values are correct."""
- assert PipelineState.IDLE.value == "idle"
- assert PipelineState.FINGERPRINTING.value == "fingerprinting"
- assert PipelineState.CLEANING.value == "cleaning"
- assert PipelineState.TERM_EXTRACTION.value == "term_extraction"
- assert PipelineState.TRANSLATING.value == "translating"
- assert PipelineState.UPLOADING.value == "uploading"
- assert PipelineState.PAUSED.value == "paused"
- assert PipelineState.COMPLETED.value == "completed"
- assert PipelineState.FAILED.value == "failed"
- def test_is_terminal(self):
- """Test terminal state detection."""
- assert PipelineState.COMPLETED.is_terminal() is True
- assert PipelineState.FAILED.is_terminal() is True
- assert PipelineState.IDLE.is_terminal() is False
- assert PipelineState.TRANSLATING.is_terminal() is False
- def test_is_active(self):
- """Test active state detection."""
- active_states = {
- PipelineState.FINGERPRINTING,
- PipelineState.CLEANING,
- PipelineState.TERM_EXTRACTION,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- }
- for state in active_states:
- assert state.is_active() is True
- inactive_states = {
- PipelineState.IDLE,
- PipelineState.PAUSED,
- PipelineState.COMPLETED,
- PipelineState.FAILED,
- }
- for state in inactive_states:
- assert state.is_active() is False
- def test_can_pause(self):
- """Test states from which pausing is allowed."""
- assert PipelineState.TRANSLATING.can_pause() is True
- assert PipelineState.CLEANING.can_pause() is True
- assert PipelineState.IDLE.can_pause() is False
- assert PipelineState.COMPLETED.can_pause() is False
- def test_can_resume(self):
- """Test states from which resuming is allowed."""
- assert PipelineState.PAUSED.can_resume() is True
- assert PipelineState.IDLE.can_resume() is False
- assert PipelineState.TRANSLATING.can_resume() is False
- class TestStateTransitions:
- """Test state transition rules."""
- def test_idle_to_fingerprinting(self):
- """Test IDLE -> FINGERPRINTING transition."""
- assert is_transition_allowed(PipelineState.IDLE, PipelineState.FINGERPRINTING) is True
- def test_idle_to_other_states(self):
- """Test IDLE cannot transition to most states."""
- assert is_transition_allowed(PipelineState.IDLE, PipelineState.COMPLETED) is False
- assert is_transition_allowed(PipelineState.IDLE, PipelineState.TRANSLATING) is False
- assert is_transition_allowed(PipelineState.IDLE, PipelineState.FAILED) is False
- def test_normal_flow(self):
- """Test normal forward flow through the pipeline."""
- flow = [
- (PipelineState.IDLE, PipelineState.FINGERPRINTING),
- (PipelineState.FINGERPRINTING, PipelineState.CLEANING),
- (PipelineState.CLEANING, PipelineState.TERM_EXTRACTION),
- (PipelineState.TERM_EXTRACTION, PipelineState.TRANSLATING),
- (PipelineState.TRANSLATING, PipelineState.UPLOADING),
- (PipelineState.UPLOADING, PipelineState.COMPLETED),
- ]
- for from_state, to_state in flow:
- assert is_transition_allowed(from_state, to_state) is True, \
- f"Failed: {from_state} -> {to_state}"
- def test_failure_transitions(self):
- """Test transitions to FAILED state."""
- failure_sources = {
- PipelineState.FINGERPRINTING,
- PipelineState.CLEANING,
- PipelineState.TERM_EXTRACTION,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- }
- for state in failure_sources:
- assert is_transition_allowed(state, PipelineState.FAILED) is True
- def test_pause_to_resume(self):
- """Test PAUSED can resume to active states."""
- assert is_transition_allowed(PipelineState.PAUSED, PipelineState.FINGERPRINTING) is True
- assert is_transition_allowed(PipelineState.PAUSED, PipelineState.TRANSLATING) is True
- assert is_transition_allowed(PipelineState.PAUSED, PipelineState.UPLOADING) is True
- def test_failed_to_idle(self):
- """Test FAILED can reset to IDLE."""
- assert is_transition_allowed(PipelineState.FAILED, PipelineState.IDLE) is True
- def test_completed_to_idle(self):
- """Test COMPLETED can reset to IDLE."""
- assert is_transition_allowed(PipelineState.COMPLETED, PipelineState.IDLE) is True
- def test_invalid_transitions(self):
- """Test some invalid transitions."""
- # Cannot skip states
- assert is_transition_allowed(PipelineState.IDLE, PipelineState.TRANSLATING) is False
- # Cannot go backwards (except via FAILED/COMPLETED -> IDLE)
- assert is_transition_allowed(PipelineState.TRANSLATING, PipelineState.CLEANING) is False
- # Cannot go from COMPLETED to active states directly
- assert is_transition_allowed(PipelineState.COMPLETED, PipelineState.TRANSLATING) is False
- class TestTransitionHelpers:
- """Test helper functions for state transitions."""
- def test_get_allowed_transitions(self):
- """Test getting allowed transitions from a state."""
- allowed = get_allowed_transitions(PipelineState.IDLE)
- assert allowed == {PipelineState.FINGERPRINTING}
- allowed = get_allowed_transitions(PipelineState.TRANSLATING)
- assert PipelineState.UPLOADING in allowed
- assert PipelineState.FAILED in allowed
- assert PipelineState.CLEANING not in allowed
- def test_can_pause_from(self):
- """Test can_pause_from helper."""
- assert can_pause_from(PipelineState.TRANSLATING) is True
- assert can_pause_from(PipelineState.UPLOADING) is True
- assert can_pause_from(PipelineState.IDLE) is False
- assert can_pause_from(PipelineState.COMPLETED) is False
- def test_can_resume_to(self):
- """Test can_resume_to helper."""
- assert can_resume_to(PipelineState.TRANSLATING) is True
- assert can_resume_to(PipelineState.CLEANING) is True
- assert can_resume_to(PipelineState.COMPLETED) is False
- assert can_resume_to(PipelineState.FAILED) is False
- def test_allowed_transitions_completeness(self):
- """Test that all states have transition rules defined."""
- all_states = set(PipelineState)
- defined_states = set(ALLOWED_TRANSITIONS.keys())
- assert all_states == defined_states, \
- f"Missing transitions for: {all_states - defined_states}"
- class TestTransitionEdgeCases:
- """Test edge cases in state transitions."""
- def test_same_state_transition(self):
- """Test that staying in same state is not a transition."""
- # Transitions to same state should not be explicitly allowed
- # (they're handled as "no transition needed")
- result = is_transition_allowed(PipelineState.IDLE, PipelineState.IDLE)
- # This should be False since we didn't define it
- assert result is False
- def test_all_states_can_reach_terminal(self):
- """Test that all active states can reach a terminal state."""
- active_states = {
- PipelineState.FINGERPRINTING,
- PipelineState.CLEANING,
- PipelineState.TERM_EXTRACTION,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- }
- for state in active_states:
- # Can reach FAILED
- assert is_transition_allowed(state, PipelineState.FAILED), \
- f"{state} cannot reach FAILED"
- # Can reach COMPLETED via normal flow
- assert state == PipelineState.UPLOADING or \
- any(is_transition_allowed(state, s) for s in PipelineState), \
- f"{state} cannot progress"
|