from datetime import UTC, datetime, timedelta import pytest from dirty_equals import IsPartialDict from starlette.testclient import TestClient from resonance_engine.dsp.enums import DSPClientName, DSPClientStatus, DSPId from resonance_engine.dsp.models import DSPClient from resonance_engine.tasks.enums import TaskStatus from resonance_engine.tasks.models import CollectTask, FanoutTask from tests.unit.helpers import create_model, override_settings def test_dsp_clients_requires_auth(client: TestClient) -> None: client.cookies.clear() with override_settings(auth_enabled=True): response = client.get("/dsp/clients") assert response.status_code == 401 @pytest.mark.db def test_dsp_clients(client: TestClient) -> None: dsp_id = DSPId.spotify client_name = DSPClientName.spotify_songwhip dsp_client = create_model(DSPClient, dsp_id=dsp_id, name=client_name) response = client.get("/dsp/clients") assert response.status_code == 200 assert response.json() == [ { "id": dsp_id, "clients": [ { "id": dsp_client.id, "name": dsp_client.name, "display_name": dsp_client.display_name, "status": dsp_client.status, "configured": True, "stats": { "requests": 0, "retries": 0, "rate_limited": 0, "rps": None, "last_rps": None, }, "nominal_rps": dsp_client.nominal_rps, } ], } ] @pytest.mark.db def test_pause_dsp_sets_status_to_paused(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, status=DSPClientStatus.active) response = client.post(f"/dsp/clients/{client_name}/pause") assert response.status_code == 200 assert response.json() == IsPartialDict(status=DSPClientStatus.paused) @pytest.mark.db def test_pause_dsp_is_idempotent(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, status=DSPClientStatus.paused) response = client.post(f"/dsp/clients/{client_name}/pause") assert response.status_code == 200 assert response.json() == IsPartialDict(status=DSPClientStatus.paused) @pytest.mark.db def test_pause_dsp_returns_404_for_missing_client(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip response = client.post(f"/dsp/clients/{client_name}/pause") assert response.status_code == 404 @pytest.mark.db def test_resume_dsp_sets_status_to_active(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, status=DSPClientStatus.paused) response = client.post(f"/dsp/clients/{client_name}/resume") assert response.status_code == 200 assert response.json() == IsPartialDict(status=DSPClientStatus.active) @pytest.mark.db def test_resume_dsp_is_idempotent(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, status=DSPClientStatus.active) response = client.post(f"/dsp/clients/{client_name}/resume") assert response.status_code == 200 assert response.json() == IsPartialDict(status=DSPClientStatus.active) @pytest.mark.db def test_resume_dsp_returns_404_for_missing_client(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip response = client.post(f"/dsp/clients/{client_name}/resume") assert response.status_code == 404 def test_pause_dsp_rejects_unknown_client_name(client: TestClient) -> None: response = client.post("/dsp/clients/unknown_dsp/pause") assert response.status_code == 422 def test_resume_dsp_rejects_unknown_client_name(client: TestClient) -> None: response = client.post("/dsp/clients/unknown_dsp/resume") assert response.status_code == 422 @pytest.mark.db def test_update_dsp_persists_nominal_rps(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, nominal_rps=11) response = client.put( f"/dsp/clients/{client_name}", json={"nominal_rps": 25}, ) assert response.status_code == 200 assert response.json()["nominal_rps"] == 25 assert DSPClient.query.where(DSPClient.name == client_name).one().nominal_rps == 25 @pytest.mark.db def test_recommended_concurrency_cold_start(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, nominal_rps=20) response = client.get(f"/dsp/clients/{client_name}/recommended-concurrency") assert response.status_code == 200 assert response.json() == { "recommended": 9, "nominal_rps": 20, "observed_rps": None, "latency_s": 0.5, "throttle_rate": 0.0, "basis": "cold", "ran": None, } @pytest.mark.db def test_recommended_concurrency_grow(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, nominal_rps=20) fanout = create_model(FanoutTask, status=TaskStatus.done) started_at = datetime(2026, 1, 1, tzinfo=UTC) create_model( CollectTask, fanout_task_id=fanout.id, dsp_client_name=client_name, status=TaskStatus.done, started_at=started_at, finished_at=started_at + timedelta(seconds=10), fans_total=50, requests=100, requests_rate_limited=0, ) response = client.get(f"/dsp/clients/{client_name}/recommended-concurrency") assert response.status_code == 200 assert response.json() == { "recommended": 2, "nominal_rps": 20, "observed_rps": 10.0, "latency_s": 0.1, "throttle_rate": 0.0, "basis": "grow", "ran": 1.0, } @pytest.mark.db def test_recommended_concurrency_returns_404_for_missing_client( client: TestClient, ) -> None: response = client.get( f"/dsp/clients/{DSPClientName.spotify_songwhip}/recommended-concurrency" ) assert response.status_code == 404 @pytest.mark.db def test_update_dsp_accepts_null_nominal_rps(client: TestClient) -> None: client_name = DSPClientName.spotify_songwhip create_model(DSPClient, name=client_name, nominal_rps=11) response = client.put( f"/dsp/clients/{client_name}", json={"nominal_rps": None}, ) assert response.status_code == 200 assert response.json()["nominal_rps"] is None