import pytest from models import Ticket, Track, WorkerContext def test_ticket_instantiation() -> None: """ Verifies that a Ticket can be instantiated with its required fields: id, description, status, assigned_to. """ ticket_id = "T1" description = "Implement surgical code changes" status = "todo" assigned_to = "tier3-worker" ticket = Ticket( id=ticket_id, description=description, status=status, assigned_to=assigned_to ) assert ticket.id == ticket_id assert ticket.description == description assert ticket.status == status assert ticket.assigned_to == assigned_to assert ticket.depends_on == [] def test_ticket_with_dependencies() -> None: """ Verifies that a Ticket can store dependencies. """ ticket = Ticket( id="T2", description="Write code", status="todo", assigned_to="worker-1", depends_on=["T1"] ) assert ticket.depends_on == ["T1"] def test_track_instantiation() -> None: """ Verifies that a Track can be instantiated with its required fields: id, description, and a list of Tickets. """ ticket1 = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a") ticket2 = Ticket(id="T2", description="Task 2", status="todo", assigned_to="b") track_id = "TRACK-1" track_desc = "Implement MMA Models" tickets = [ticket1, ticket2] track = Track( id=track_id, description=track_desc, tickets=tickets ) assert track.id == track_id assert track.description == track_desc assert len(track.tickets) == 2 assert track.tickets[0].id == "T1" assert track.tickets[1].id == "T2" def test_track_can_handle_empty_tickets() -> None: """ Verifies that a Track can be instantiated with an empty list of tickets. """ track = Track(id="TRACK-2", description="Empty Track", tickets=[]) assert track.tickets == [] def test_worker_context_instantiation() -> None: """ Verifies that a WorkerContext can be instantiated with ticket_id, model_name, and messages. """ ticket_id = "T1" model_name = "gemini-2.0-flash-lite" messages = [ {"role": "user", "content": "Hello"}, {"role": "assistant", "content": "Hi there!"} ] context = WorkerContext( ticket_id=ticket_id, model_name=model_name, messages=messages ) assert context.ticket_id == ticket_id assert context.model_name == model_name assert context.messages == messages def test_ticket_mark_blocked() -> None: """ Verifies that ticket.mark_blocked(reason) sets the status to 'blocked'. Note: The reason field might need to be added to the Ticket class. """ ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a") ticket.mark_blocked("Waiting for API key") assert ticket.status == "blocked" def test_ticket_mark_complete() -> None: """ Verifies that ticket.mark_complete() sets the status to 'completed'. """ ticket = Ticket(id="T1", description="Task 1", status="todo", assigned_to="a") ticket.mark_complete() assert ticket.status == "completed" def test_track_get_executable_tickets() -> None: """ Verifies that track.get_executable_tickets() returns only 'todo' tickets whose dependencies are all 'completed'. """ # T1: todo, no deps -> executable t1 = Ticket(id="T1", description="T1", status="todo", assigned_to="a") # T2: todo, deps [T1] -> not executable (T1 is todo) t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="a", depends_on=["T1"]) # T3: todo, deps [T4] -> not executable (T4 is blocked) t3 = Ticket(id="T3", description="T3", status="todo", assigned_to="a", depends_on=["T4"]) # T4: blocked, no deps -> not executable (not 'todo') t4 = Ticket(id="T4", description="T4", status="blocked", assigned_to="a") # T5: completed, no deps -> not executable (not 'todo') t5 = Ticket(id="T5", description="T5", status="completed", assigned_to="a") # T6: todo, deps [T5] -> executable (T5 is completed) t6 = Ticket(id="T6", description="T6", status="todo", assigned_to="a", depends_on=["T5"]) track = Track(id="TR1", description="Track 1", tickets=[t1, t2, t3, t4, t5, t6]) executable = track.get_executable_tickets() executable_ids = [t.id for t in executable] assert "T1" in executable_ids assert "T6" in executable_ids assert len(executable_ids) == 2 def test_track_get_executable_tickets_complex() -> None: """ Verifies executable tickets with complex dependency chains. Chain: T1 (comp) -> T2 (todo) -> T3 (todo) T4 (comp) -> T3 T5 (todo) -> T3 """ t1 = Ticket(id="T1", description="T1", status="completed", assigned_to="a") t2 = Ticket(id="T2", description="T2", status="todo", assigned_to="a", depends_on=["T1"]) t3 = Ticket(id="T3", description="T3", status="todo", assigned_to="a", depends_on=["T2", "T4", "T5"]) t4 = Ticket(id="T4", description="T4", status="completed", assigned_to="a") t5 = Ticket(id="T5", description="T5", status="todo", assigned_to="a") track = Track(id="TR1", description="Track 1", tickets=[t1, t2, t3, t4, t5]) # At this point: # T1 is completed # T4 is completed # T2 is todo, depends on T1 (completed) -> Executable # T5 is todo, no deps -> Executable # T3 is todo, depends on T2 (todo), T4 (completed), T5 (todo) -> Not executable executable = track.get_executable_tickets() executable_ids = sorted([t.id for t in executable]) assert executable_ids == ["T2", "T5"] # Mark T2 complete t2.mark_complete() # T3 still depends on T5 executable = track.get_executable_tickets() executable_ids = sorted([t.id for t in executable]) assert executable_ids == ["T5"] # Mark T5 complete t5.mark_complete() # Now T3 should be executable executable = track.get_executable_tickets() executable_ids = sorted([t.id for t in executable]) assert executable_ids == ["T3"]