Files
manual_slop/tests/test_orchestration_logic.py
2026-03-05 13:57:03 -05:00

97 lines
3.6 KiB
Python

import pytest
from unittest.mock import patch
import json
from typing import Any
from src import orchestrator_pm
from src import multi_agent_conductor
from src import conductor_tech_lead
from src.models import Ticket, Track, WorkerContext
def test_generate_tracks() -> None:
mock_response = """
[
{"id": "track_1", "title": "Setup", "goal": "init project", "type": "setup"},
{"id": "track_2", "title": "Refactor", "goal": "decouple modules", "type": "refactor"}
]
"""
with patch("src.ai_client.send", return_value=mock_response):
tracks = orchestrator_pm.generate_tracks("Develop feature X", {}, [])
assert len(tracks) == 2
assert tracks[0]["id"] == "track_1"
assert tracks[1]["type"] == "refactor"
def test_generate_tickets() -> None:
mock_response = """
[
{"id": "T1", "description": "task 1", "depends_on": []},
{"id": "T2", "description": "task 2", "depends_on": ["T1"]}
]
"""
with patch("src.ai_client.send", return_value=mock_response):
tickets = conductor_tech_lead.generate_tickets("Track goal", "code skeletons")
assert len(tickets) == 2
assert tickets[0]["id"] == "T1"
assert tickets[1]["depends_on"] == ["T1"]
def test_topological_sort() -> None:
tickets = [
{"id": "T2", "depends_on": ["T1"]},
{"id": "T1", "depends_on": []}
]
sorted_tickets = conductor_tech_lead.topological_sort(tickets)
assert sorted_tickets[0]["id"] == "T1"
assert sorted_tickets[1]["id"] == "T2"
def test_topological_sort_circular() -> None:
tickets = [
{"id": "T1", "depends_on": ["T2"]},
{"id": "T2", "depends_on": ["T1"]}
]
with pytest.raises(ValueError, match="DAG Validation Error"):
conductor_tech_lead.topological_sort(tickets)
def test_track_executable_tickets() -> None:
t1 = Ticket(id="T1", description="d1", status="completed")
t2 = Ticket(id="T2", description="d2", status="todo", depends_on=["T1"])
t3 = Ticket(id="T3", description="d3", status="todo", depends_on=["T2"])
track = Track(id="TR1", description="track", tickets=[t1, t2, t3])
# T2 should be executable because T1 is completed
executable = track.get_executable_tickets()
assert len(executable) == 1
assert executable[0].id == "T2"
def test_conductor_engine_run() -> None:
t1 = Ticket(id="T1", description="d1", status="todo")
track = Track(id="TR1", description="track", tickets=[t1])
engine = multi_agent_conductor.ConductorEngine(track, auto_queue=True)
with patch("src.multi_agent_conductor.run_worker_lifecycle") as mock_run:
def side_effect(ticket, context, *args, **kwargs):
ticket.mark_complete()
return "Success"
mock_run.side_effect = side_effect
engine.run()
assert t1.status == "completed"
assert mock_run.called
def test_conductor_engine_parse_json_tickets() -> None:
track = Track(id="TR1", description="track", tickets=[])
engine = multi_agent_conductor.ConductorEngine(track)
json_data = '[{"id": "T1", "description": "desc", "depends_on": []}]'
engine.parse_json_tickets(json_data)
assert len(track.tickets) == 1
assert track.tickets[0].id == "T1"
def test_run_worker_lifecycle_blocked() -> None:
ticket = Ticket(id="T1", description="desc", status="todo")
context = WorkerContext(ticket_id="T1", model_name="model", messages=[])
with patch("src.ai_client.send") as mock_ai_client, \
patch("src.ai_client.reset_session"), \
patch("src.ai_client.set_provider"), \
patch("src.multi_agent_conductor.confirm_spawn", return_value=(True, "p", "c")):
mock_ai_client.return_value = "BLOCKED because of missing info"
multi_agent_conductor.run_worker_lifecycle(ticket, context)
assert ticket.status == "blocked"
assert ticket.blocked_reason == "BLOCKED because of missing info"