"""Tests for orchestration models.""" from __future__ import annotations from datetime import datetime import pytest from src.orchestration.models import ( ALL_BOOKS, NEW_TESTAMENT_BOOKS, OLD_TESTAMENT_BOOKS, BibleJob, BookJob, BookResult, JobResult, JobStatus, VerseJob, ) class TestJobStatus: """Tests for JobStatus enum.""" def test_status_values(self) -> None: """Test that all expected status values exist.""" assert JobStatus.PENDING == "pending" assert JobStatus.IN_PROGRESS == "in_progress" assert JobStatus.COMPLETED == "completed" assert JobStatus.FAILED == "failed" assert JobStatus.CANCELLED == "cancelled" def test_status_is_string_enum(self) -> None: """Test that status values can be used as strings.""" assert str(JobStatus.PENDING) == "JobStatus.PENDING" assert JobStatus.PENDING.value == "pending" class TestVerseJob: """Tests for VerseJob dataclass.""" def test_default_values(self) -> None: """Test default values for VerseJob.""" job = VerseJob(book="john", chapter=1, verse=1) assert job.book == "john" assert job.chapter == 1 assert job.verse == 1 assert job.status == JobStatus.PENDING assert job.attempts == 0 assert job.last_error is None assert job.worker_pid is None assert job.started_at is None assert job.completed_at is None def test_reference_str(self) -> None: """Test reference_str property.""" job = VerseJob(book="john", chapter=3, verse=16) assert job.reference_str == "john:3:16" def test_with_values(self) -> None: """Test VerseJob with all values set.""" now = datetime.utcnow() job = VerseJob( book="genesis", chapter=1, verse=1, status=JobStatus.IN_PROGRESS, attempts=2, last_error="Rate limit exceeded", worker_pid=12345, started_at=now, ) assert job.status == JobStatus.IN_PROGRESS assert job.attempts == 2 assert job.last_error == "Rate limit exceeded" assert job.worker_pid == 12345 assert job.started_at == now class TestBookJob: """Tests for BookJob dataclass.""" def test_default_values(self) -> None: """Test default values for BookJob.""" job = BookJob(book="john") assert job.book == "john" assert job.status == JobStatus.PENDING assert job.total_verses == 0 assert job.completed_verses == 0 assert job.failed_verses == 0 assert job.worker_pid is None assert job.started_at is None assert job.completed_at is None assert job.error_message is None def test_pending_verses(self) -> None: """Test pending_verses property.""" job = BookJob( book="john", total_verses=100, completed_verses=50, failed_verses=10, ) assert job.pending_verses == 40 def test_progress_percentage(self) -> None: """Test progress_percentage property.""" job = BookJob( book="john", total_verses=100, completed_verses=75, ) assert job.progress_percentage == 75.0 def test_progress_percentage_zero_total(self) -> None: """Test progress_percentage with zero total.""" job = BookJob(book="john", total_verses=0) assert job.progress_percentage == 0.0 class TestBibleJob: """Tests for BibleJob dataclass.""" def test_default_values(self) -> None: """Test default values for BibleJob.""" job = BibleJob() assert job.job_id is not None assert len(job.job_id) == 36 # UUID format assert job.books == [] assert job.status == JobStatus.PENDING assert job.config_snapshot == {} assert job.created_at is not None assert job.started_at is None assert job.completed_at is None assert job.total_verses == 0 assert job.completed_verses == 0 assert job.failed_verses == 0 def test_pending_verses(self) -> None: """Test pending_verses property.""" job = BibleJob( total_verses=1000, completed_verses=500, failed_verses=50, ) assert job.pending_verses == 450 def test_progress_percentage(self) -> None: """Test progress_percentage property.""" job = BibleJob( total_verses=1000, completed_verses=250, ) assert job.progress_percentage == 25.0 def test_progress_percentage_zero_total(self) -> None: """Test progress_percentage with zero total.""" job = BibleJob(total_verses=0) assert job.progress_percentage == 0.0 def test_with_books(self) -> None: """Test BibleJob with books list.""" job = BibleJob( books=["john", "matthew", "luke"], config_snapshot={"model": "test-model"}, ) assert job.books == ["john", "matthew", "luke"] assert job.config_snapshot == {"model": "test-model"} class TestBookResult: """Tests for BookResult dataclass.""" def test_successful_result(self) -> None: """Test successful book result.""" result = BookResult( book="john", success=True, verses_translated=879, verses_failed=0, duration_seconds=3600.5, ) assert result.book == "john" assert result.success is True assert result.verses_translated == 879 assert result.verses_failed == 0 assert result.duration_seconds == 3600.5 assert result.error_message is None def test_failed_result(self) -> None: """Test failed book result.""" result = BookResult( book="genesis", success=False, verses_translated=100, verses_failed=50, duration_seconds=1800.0, error_message="Network error", ) assert result.success is False assert result.error_message == "Network error" class TestJobResult: """Tests for JobResult dataclass.""" def test_successful_result(self) -> None: """Test successful job result.""" book_results = [ BookResult( book="john", success=True, verses_translated=879, verses_failed=0, duration_seconds=3600.0, ), BookResult( book="matthew", success=True, verses_translated=1071, verses_failed=5, duration_seconds=4000.0, ), ] result = JobResult( job_id="test-job-123", success=True, books_completed=2, books_failed=0, total_verses_translated=1950, total_verses_failed=5, duration_seconds=7600.0, book_results=book_results, ) assert result.job_id == "test-job-123" assert result.success is True assert result.books_completed == 2 assert result.books_failed == 0 assert len(result.book_results) == 2 class TestBookConstants: """Tests for book constants.""" def test_old_testament_count(self) -> None: """Test that OT has 39 books.""" assert len(OLD_TESTAMENT_BOOKS) == 39 def test_new_testament_count(self) -> None: """Test that NT has 27 books.""" assert len(NEW_TESTAMENT_BOOKS) == 27 def test_all_books_count(self) -> None: """Test that all books is 66.""" assert len(ALL_BOOKS) == 66 def test_all_books_is_ot_plus_nt(self) -> None: """Test that ALL_BOOKS = OT + NT.""" assert ALL_BOOKS == OLD_TESTAMENT_BOOKS + NEW_TESTAMENT_BOOKS def test_no_duplicate_books(self) -> None: """Test there are no duplicate books.""" assert len(set(ALL_BOOKS)) == len(ALL_BOOKS) def test_common_ot_books_present(self) -> None: """Test that common OT books are present.""" assert "genesis" in OLD_TESTAMENT_BOOKS assert "exodus" in OLD_TESTAMENT_BOOKS assert "psalms" in OLD_TESTAMENT_BOOKS assert "isaiah" in OLD_TESTAMENT_BOOKS def test_common_nt_books_present(self) -> None: """Test that common NT books are present.""" assert "matthew" in NEW_TESTAMENT_BOOKS assert "john" in NEW_TESTAMENT_BOOKS assert "acts" in NEW_TESTAMENT_BOOKS assert "romans" in NEW_TESTAMENT_BOOKS assert "revelation" in NEW_TESTAMENT_BOOKS