zfp-oss #27

Merged
benchinnery merged 15 commits from zfp-oss into main 2026-04-23 11:10:43 -04:00
5 changed files with 29 additions and 29 deletions
Showing only changes of commit 07c72294f5 - Show all commits

View File

@ -3,7 +3,7 @@
from fastapi import Depends, FastAPI from fastapi import Depends, FastAPI
from .auth import require_api_key from .auth import require_api_key
from .routers import inference, orchestrator from .routers import conductor, inference
def create_app(api_key: str = "") -> FastAPI: def create_app(api_key: str = "") -> FastAPI:
@ -28,9 +28,9 @@ def create_app(api_key: str = "") -> FastAPI:
app.state.api_key = api_key app.state.api_key = api_key
app.include_router( app.include_router(
orchestrator.router, conductor.router,
prefix="/orchestrator", prefix="/conductor",
tags=["Orchestrator"], tags=["Conductor"],
dependencies=[Depends(require_api_key)], dependencies=[Depends(require_api_key)],
) )
app.include_router( app.include_router(

View File

@ -7,7 +7,7 @@ from pathlib import Path
from pydantic import BaseModel, field_validator from pydantic import BaseModel, field_validator
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Orchestrator # Conductor
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------

View File

@ -1,4 +1,4 @@
"""Orchestrator routes: campaign deployment, status, and cancellation.""" """Conductor routes: campaign deployment, status, and cancellation."""
from __future__ import annotations from __future__ import annotations

View File

@ -23,9 +23,9 @@ def serve(host: str, port: int, api_key: str, log_level: str):
\b \b
Endpoints: Endpoints:
POST /orchestrator/deploy POST /conductor/deploy
GET /orchestrator/status/{campaign_id} GET /conductor/status/{campaign_id}
POST /orchestrator/cancel/{campaign_id} POST /conductor/cancel/{campaign_id}
POST /inference/load POST /inference/load
POST /inference/start POST /inference/start
POST /inference/stop POST /inference/stop

View File

@ -1,6 +1,6 @@
"""Tests for the RT-OSS HTTP server. """Tests for the RT-OSS HTTP server.
Covers: auth, inference lifecycle (without SDR/ONNX hardware), orchestrator Covers: auth, inference lifecycle (without SDR/ONNX hardware), conductor
lifecycle (with mocked executor), and state helpers. lifecycle (with mocked executor), and state helpers.
``start_inference`` and ``_inference_loop`` require real SDR hardware and an ``start_inference`` and ``_inference_loop`` require real SDR hardware and an
@ -286,17 +286,17 @@ class TestInferenceStop:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# POST /orchestrator/deploy # POST /conductor/deploy
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class TestOrchestratorDeploy: class TestConductorDeploy:
def test_deploy_422_on_invalid_config(self, client): def test_deploy_422_on_invalid_config(self, client):
with patch( with patch(
"ria_toolkit_oss.server.routers.orchestrator.CampaignConfig.from_dict", "ria_toolkit_oss.server.routers.conductor.CampaignConfig.from_dict",
side_effect=ValueError("missing required field 'name'"), side_effect=ValueError("missing required field 'name'"),
): ):
resp = client.post("/orchestrator/deploy", json={"config": {}}) resp = client.post("/conductor/deploy", json={"config": {}})
assert resp.status_code == 422 assert resp.status_code == 422
def test_deploy_returns_campaign_id(self, client): def test_deploy_returns_campaign_id(self, client):
@ -307,10 +307,10 @@ class TestOrchestratorDeploy:
mock_executor.return_value.run.return_value = MagicMock(to_dict=lambda: {}) mock_executor.return_value.run.return_value = MagicMock(to_dict=lambda: {})
with ( with (
patch("ria_toolkit_oss.server.routers.orchestrator.CampaignConfig.from_dict", return_value=mock_cfg), patch("ria_toolkit_oss.server.routers.conductor.CampaignConfig.from_dict", return_value=mock_cfg),
patch("ria_toolkit_oss.server.routers.orchestrator.CampaignExecutor", mock_executor), patch("ria_toolkit_oss.server.routers.conductor.CampaignExecutor", mock_executor),
): ):
resp = client.post("/orchestrator/deploy", json={"config": {"name": "test_campaign"}}) resp = client.post("/conductor/deploy", json={"config": {"name": "test_campaign"}})
assert resp.status_code == 200 assert resp.status_code == 200
body = resp.json() body = resp.json()
@ -325,23 +325,23 @@ class TestOrchestratorDeploy:
mock_executor.return_value.run.return_value = MagicMock(to_dict=lambda: {}) mock_executor.return_value.run.return_value = MagicMock(to_dict=lambda: {})
with ( with (
patch("ria_toolkit_oss.server.routers.orchestrator.CampaignConfig.from_dict", return_value=mock_cfg), patch("ria_toolkit_oss.server.routers.conductor.CampaignConfig.from_dict", return_value=mock_cfg),
patch("ria_toolkit_oss.server.routers.orchestrator.CampaignExecutor", mock_executor), patch("ria_toolkit_oss.server.routers.conductor.CampaignExecutor", mock_executor),
): ):
resp = client.post("/orchestrator/deploy", json={"config": {}}) resp = client.post("/conductor/deploy", json={"config": {}})
campaign_id = resp.json()["campaign_id"] campaign_id = resp.json()["campaign_id"]
assert state_module._campaigns.get(campaign_id) is not None assert state_module._campaigns.get(campaign_id) is not None
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# GET /orchestrator/status/{campaign_id} # GET /conductor/status/{campaign_id}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class TestOrchestratorStatus: class TestConductorStatus:
def test_status_404_for_unknown_id(self, client): def test_status_404_for_unknown_id(self, client):
resp = client.get("/orchestrator/status/nonexistent-id") resp = client.get("/conductor/status/nonexistent-id")
assert resp.status_code == 404 assert resp.status_code == 404
def test_status_returns_campaign_state(self, client): def test_status_returns_campaign_state(self, client):
@ -357,7 +357,7 @@ class TestOrchestratorStatus:
) )
state_module._campaigns["abc-123"] = state state_module._campaigns["abc-123"] = state
resp = client.get("/orchestrator/status/abc-123") resp = client.get("/conductor/status/abc-123")
assert resp.status_code == 200 assert resp.status_code == 200
body = resp.json() body = resp.json()
assert body["campaign_id"] == "abc-123" assert body["campaign_id"] == "abc-123"
@ -367,13 +367,13 @@ class TestOrchestratorStatus:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# POST /orchestrator/cancel/{campaign_id} # POST /conductor/cancel/{campaign_id}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
class TestOrchestratorCancel: class TestConductorCancel:
def test_cancel_404_for_unknown_id(self, client): def test_cancel_404_for_unknown_id(self, client):
resp = client.post("/orchestrator/cancel/no-such-id") resp = client.post("/conductor/cancel/no-such-id")
assert resp.status_code == 404 assert resp.status_code == 404
def test_cancel_sets_cancel_event(self, client): def test_cancel_sets_cancel_event(self, client):
@ -387,7 +387,7 @@ class TestOrchestratorCancel:
) )
state_module._campaigns["camp-to-cancel"] = state state_module._campaigns["camp-to-cancel"] = state
resp = client.post("/orchestrator/cancel/camp-to-cancel") resp = client.post("/conductor/cancel/camp-to-cancel")
assert resp.status_code == 200 assert resp.status_code == 200
assert resp.json()["cancelled"] is True assert resp.json()["cancelled"] is True
assert cancel_event.is_set() assert cancel_event.is_set()
@ -403,7 +403,7 @@ class TestOrchestratorCancel:
) )
state_module._campaigns["done"] = state state_module._campaigns["done"] = state
resp = client.post("/orchestrator/cancel/done") resp = client.post("/conductor/cancel/done")
assert resp.status_code == 200 assert resp.status_code == 200
assert resp.json()["cancelled"] is False assert resp.json()["cancelled"] is False
assert not cancel_event.is_set() assert not cancel_event.is_set()