import pytest from domain.tasks.subtasks import SubTaskStatus from domain.tasks.tasks import Source, Task, TaskStatus def test_create_task_starts_waiting() -> None: # arrange / act t = Task.create( task_source="manual:test", source=Source.PORTFOLIO, source_id="abc-123" ) # assert assert t.status is TaskStatus.WAITING assert t.source is Source.PORTFOLIO assert t.source_id == "abc-123" assert t.job_started is not None assert t.job_completed is None def test_create_task_rejects_blank_task_source() -> None: # act / assert with pytest.raises(ValueError, match="task_source"): Task.create(task_source=" ") def test_start_transitions_to_in_progress() -> None: # arrange t = Task.create(task_source="manual:test") # act t.start() # assert assert t.status is TaskStatus.IN_PROGRESS def test_complete_marks_job_completed() -> None: # arrange t = Task.create(task_source="manual:test") t.start() # act t.complete() # assert assert t.status is TaskStatus.COMPLETE assert t.job_completed is not None def test_fail_marks_job_completed() -> None: # arrange t = Task.create(task_source="manual:test") # act t.fail() # assert assert t.status is TaskStatus.FAILED assert t.job_completed is not None def test_start_rejects_from_terminal_status() -> None: # arrange t = Task.create(task_source="manual:test") t.complete() # act / assert with pytest.raises(ValueError): t.start() def test_recalculate_with_empty_statuses_is_noop() -> None: # arrange t = Task.create(task_source="manual:test") original_status = t.status original_completed = t.job_completed # act t.recalculate_from_subtasks([]) # assert assert t.status is original_status assert t.job_completed is original_completed def test_recalculate_all_waiting_keeps_waiting() -> None: # arrange t = Task.create(task_source="manual:test") t.start() # task moved to IN_PROGRESS earlier t.complete() # then COMPLETE, with job_completed set # act t.recalculate_from_subtasks([SubTaskStatus.WAITING, SubTaskStatus.WAITING]) # assert assert t.status is TaskStatus.WAITING assert t.job_completed is None def test_recalculate_any_in_progress_marks_in_progress() -> None: # arrange t = Task.create(task_source="manual:test") # act t.recalculate_from_subtasks( [SubTaskStatus.WAITING, SubTaskStatus.IN_PROGRESS, SubTaskStatus.COMPLETE] ) # assert assert t.status is TaskStatus.IN_PROGRESS assert t.job_completed is None def test_recalculate_all_complete_marks_complete() -> None: # arrange t = Task.create(task_source="manual:test") # act t.recalculate_from_subtasks([SubTaskStatus.COMPLETE, SubTaskStatus.COMPLETE]) # assert assert t.status is TaskStatus.COMPLETE assert t.job_completed is not None def test_recalculate_any_failed_marks_failed_even_with_others() -> None: # arrange t = Task.create(task_source="manual:test") # act t.recalculate_from_subtasks( [SubTaskStatus.IN_PROGRESS, SubTaskStatus.COMPLETE, SubTaskStatus.FAILED] ) # assert assert t.status is TaskStatus.FAILED assert t.job_completed is not None