| from dataclasses import dataclass, field |
|
|
| from arena.codebase_archive import LocalCodebaseArchiveStore |
| from arena.event_bus import EventBus |
| from arena.run_models import CodebaseArchive, Run, RunEvent, RunRequest, RunTask |
| from arena.run_store import InMemoryRunStore |
| from arena.service import ArenaService |
| from arena.swarm_runtime import SwarmRunResult |
| from arena.validation_models import ValidationReport |
|
|
|
|
| @dataclass |
| class FakeSwarmRuntime: |
| started_runs: list[Run] = field(default_factory=list) |
| executed_runs: list[str] = field(default_factory=list) |
| publish_called: bool = False |
|
|
| def start_run(self, run: Run): |
| self.started_runs.append(run) |
| return object() |
|
|
| def execute_run(self, run_id: str, **kwargs) -> SwarmRunResult: |
| self.executed_runs.append(run_id) |
| return SwarmRunResult( |
| summary="Created the app.", |
| tasks=[RunTask(id="task-1", title="Build codebase", status="completed")], |
| events=[RunEvent(id="event-1", message="Created the app.")], |
| codebase_archive=CodebaseArchive( |
| pointer="local-snapshot://run-1", |
| file_count=1, |
| size_bytes=10, |
| ), |
| ) |
|
|
| def close_run(self, run_id: str) -> None: |
| pass |
|
|
|
|
| class FakeValidatorGraph: |
| def validate(self, **kwargs) -> ValidationReport: |
| return ValidationReport(run_id=kwargs["run_id"], passed=True, summary="ok") |
|
|
|
|
| def test_event_bus_publish_and_close() -> None: |
| bus = EventBus() |
| q = bus.subscribe("run-1") |
|
|
| bus.publish("run-1", {"kind": "event", "message": "started"}) |
| bus.publish("run-1", {"kind": "event", "message": "working"}) |
| bus.close("run-1") |
|
|
| events = [] |
| while True: |
| event = q.get(timeout=1) |
| if event is None: |
| break |
| events.append(event) |
|
|
| assert len(events) == 2 |
| assert events[0]["message"] == "started" |
| assert events[1]["message"] == "working" |
|
|
|
|
| def test_event_bus_publish_to_nonexistent_queue_is_noop() -> None: |
| bus = EventBus() |
| bus.publish("no-such-run", {"kind": "event"}) |
|
|
|
|
| def test_event_bus_close_removes_queue() -> None: |
| bus = EventBus() |
| q = bus.subscribe("run-1") |
| bus.close("run-1") |
| assert "run-1" not in bus._queues |
| assert q.get(timeout=1) is None |
|
|
|
|
| def test_start_run_is_nonblocking_and_publishes_events() -> None: |
| runtime = FakeSwarmRuntime() |
| service = ArenaService( |
| run_store=InMemoryRunStore(), |
| swarm_runtime=runtime, |
| validator_graph=FakeValidatorGraph(), |
| archive_store=LocalCodebaseArchiveStore(), |
| ) |
|
|
| access = service.start_run(RunRequest(prompt="Build a CLI", user_tests=["pytest"])) |
|
|
| assert access.token |
| assert access.run.prompt == "Build a CLI" |
| assert runtime.started_runs[0].id == access.run.id |
|
|
|
|
| def test_start_run_async_completes_and_validates() -> None: |
| import time |
| service = ArenaService( |
| run_store=InMemoryRunStore(), |
| swarm_runtime=FakeSwarmRuntime(), |
| validator_graph=FakeValidatorGraph(), |
| archive_store=LocalCodebaseArchiveStore(), |
| ) |
|
|
| access = service.start_run(RunRequest(prompt="Build a CLI", user_tests=["pytest"])) |
|
|
| time.sleep(0.1) |
|
|
| view = service.get_run(access.run.id) |
| assert view.status in ("working", "validating", "completed") |
| assert len(view.tasks) == 1 |
| assert view.tasks[0].title == "Build codebase" |
| assert view.codebase_archive is not None |
| if view.status == "completed": |
| assert view.validation_report is not None |
|
|
|
|
| def test_service_subscribe_events_returns_a_queue() -> None: |
| service = ArenaService( |
| run_store=InMemoryRunStore(), |
| swarm_runtime=FakeSwarmRuntime(), |
| validator_graph=FakeValidatorGraph(), |
| archive_store=LocalCodebaseArchiveStore(), |
| ) |
|
|
| queue = service.subscribe_events("run-1") |
|
|
| assert queue is not None |
|
|