| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- """
- Unit tests for the state machine module.
- Tests cover all state transitions, persistence, and recovery scenarios.
- """
- import pytest
- from datetime import datetime
- from src.pipeline.state_machine import PipelineStateMachine, PipelineState
- class TestPipelineStateMachine:
- """Test cases for PipelineStateMachine."""
- def test_initial_state_is_idle(self):
- """Test that the machine starts in IDLE state."""
- machine = PipelineStateMachine()
- assert machine.state == PipelineState.IDLE
- def test_valid_transition_idle_to_preparing(self):
- """Test valid transition from IDLE to PREPARING."""
- machine = PipelineStateMachine()
- assert machine.transition_to(PipelineState.PREPARING)
- assert machine.state == PipelineState.PREPARING
- def test_valid_transition_preparing_to_cleaning(self):
- """Test valid transition from PREPARING to CLEANING."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- assert machine.transition_to(PipelineState.CLEANING)
- assert machine.state == PipelineState.CLEANING
- def test_valid_transition_cleaning_to_translating(self):
- """Test valid transition from CLEANING to TRANSLATING."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(PipelineState.CLEANING)
- assert machine.transition_to(PipelineState.TRANSLATING)
- assert machine.state == PipelineState.TRANSLATING
- def test_valid_transition_translating_to_uploading(self):
- """Test valid transition from TRANSLATING to UPLOADING."""
- machine = PipelineStateMachine()
- for state in [
- PipelineState.PREPARING,
- PipelineState.CLEANING,
- PipelineState.TRANSLATING,
- ]:
- machine.transition_to(state)
- assert machine.transition_to(PipelineState.UPLOADING)
- assert machine.state == PipelineState.UPLOADING
- def test_valid_transition_uploading_to_completed(self):
- """Test valid transition from UPLOADING to COMPLETED."""
- machine = PipelineStateMachine()
- for state in [
- PipelineState.PREPARING,
- PipelineState.CLEANING,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- ]:
- machine.transition_to(state)
- assert machine.transition_to(PipelineState.COMPLETED)
- assert machine.state == PipelineState.COMPLETED
- def test_invalid_transition_rejected(self):
- """Test that invalid transitions are rejected."""
- machine = PipelineStateMachine()
- # Can't skip from IDLE to TRANSLATING
- assert not machine.transition_to(PipelineState.TRANSLATING)
- assert machine.state == PipelineState.IDLE
- def test_pause_from_any_active_state(self):
- """Test pausing from any active state."""
- active_states = [
- PipelineState.PREPARING,
- PipelineState.CLEANING,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- ]
- for state in active_states:
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(state)
- assert machine.transition_to(PipelineState.PAUSED)
- assert machine.state == PipelineState.PAUSED
- def test_resume_from_pause(self):
- """Test resuming from PAUSED back to active state."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(PipelineState.TRANSLATING)
- machine.transition_to(PipelineState.PAUSED)
- # Can resume to TRANSLATING
- assert machine.transition_to(PipelineState.TRANSLATING)
- assert machine.state == PipelineState.TRANSLATING
- def test_failed_state_only_goes_to_idle(self):
- """Test that FAILED state can only transition to IDLE."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(PipelineState.FAILED)
- # Can go to IDLE
- assert machine.transition_to(PipelineState.IDLE)
- assert machine.state == PipelineState.IDLE
- # Can't go directly to another state
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(PipelineState.FAILED)
- assert not machine.transition_to(PipelineState.TRANSLATING)
- def test_completed_goes_to_idle(self):
- """Test that COMPLETED transitions to IDLE."""
- machine = PipelineStateMachine()
- for state in [
- PipelineState.PREPARING,
- PipelineState.CLEANING,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- PipelineState.COMPLETED,
- ]:
- machine.transition_to(state)
- assert machine.transition_to(PipelineState.IDLE)
- assert machine.state == PipelineState.IDLE
- def test_state_history_tracking(self):
- """Test that state history is tracked."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING, reason="Starting task")
- machine.transition_to(PipelineState.CLEANING)
- history = machine.get_state_history()
- assert len(history) == 3 # IDLE + PREPARING + CLEANING
- assert history[0]["state"] == "idle"
- assert history[1]["state"] == "preparing"
- assert history[1]["reason"] == "Starting task"
- assert history[2]["state"] == "cleaning"
- def test_can_transition_to_check(self):
- """Test the can_transition_to method."""
- machine = PipelineStateMachine()
- assert machine.can_transition_to(PipelineState.PREPARING)
- assert not machine.can_transition_to(PipelineState.TRANSLATING)
- machine.transition_to(PipelineState.PREPARING)
- assert machine.can_transition_to(PipelineState.CLEANING)
- assert not machine.can_transition_to(PipelineState.IDLE)
- def test_reset(self):
- """Test resetting the state machine."""
- machine = PipelineStateMachine()
- machine.transition_to(PipelineState.PREPARING)
- machine.transition_to(PipelineState.CLEANING)
- machine.reset()
- assert machine.state == PipelineState.IDLE
- assert len(machine.get_state_history()) == 1
- def test_full_workflow(self):
- """Test a complete workflow from start to finish."""
- machine = PipelineStateMachine()
- workflow = [
- PipelineState.PREPARING,
- PipelineState.CLEANING,
- PipelineState.TRANSLATING,
- PipelineState.UPLOADING,
- PipelineState.COMPLETED,
- ]
- for state in workflow:
- assert machine.transition_to(state), f"Failed to transition to {state}"
- assert machine.state == state
- # Should be able to start a new task
- assert machine.transition_to(PipelineState.IDLE)
- assert machine.transition_to(PipelineState.PREPARING)
|