992495e2e4
Tests that imported wled_controller.main at module level caused the real production database (data/ledgrab.db) to be opened before test fixtures could patch the config. This led to silent data loss. Patch the global config singleton at conftest module level (before any test imports main.py) to redirect all DB access to a temp directory.
151 lines
5.0 KiB
Python
151 lines
5.0 KiB
Python
"""API tests for audio processing template endpoints."""
|
|
|
|
import pytest
|
|
|
|
from wled_controller.config import get_config
|
|
|
|
# Ensure audio filters registered
|
|
import wled_controller.core.audio.filters # noqa: F401
|
|
|
|
_config = get_config()
|
|
_api_key = next(iter(_config.auth.api_keys.values()), "")
|
|
AUTH = {"Authorization": f"Bearer {_api_key}"} if _api_key else {}
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def client():
|
|
"""Provide a TestClient with lifespan (startup/shutdown) properly triggered."""
|
|
from fastapi.testclient import TestClient
|
|
from wled_controller.main import app
|
|
|
|
with TestClient(app) as c:
|
|
yield c
|
|
|
|
|
|
# Track created template IDs for cleanup
|
|
_created_ids: list[str] = []
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def cleanup_after_test(client):
|
|
"""Clean up created templates after each test."""
|
|
yield
|
|
for tid in list(_created_ids):
|
|
client.delete(f"/api/v1/audio-processing-templates/{tid}", headers=AUTH)
|
|
_created_ids.clear()
|
|
|
|
|
|
def _create(client, name: str, filters: list | None = None, **kwargs) -> dict:
|
|
"""Helper: create a template and track for cleanup."""
|
|
body = {"name": name, "filters": filters or [], **kwargs}
|
|
resp = client.post("/api/v1/audio-processing-templates", json=body, headers=AUTH)
|
|
if resp.status_code == 201:
|
|
_created_ids.append(resp.json()["id"])
|
|
return resp
|
|
|
|
|
|
class TestAudioProcessingTemplateAPI:
|
|
"""Test /api/v1/audio-processing-templates endpoints."""
|
|
|
|
def test_list(self, client):
|
|
resp = client.get("/api/v1/audio-processing-templates", headers=AUTH)
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "templates" in data
|
|
assert "count" in data
|
|
|
|
def test_create(self, client):
|
|
resp = _create(
|
|
client,
|
|
"API Test Template",
|
|
filters=[{"filter_id": "gain", "options": {"factor": 2.0}}],
|
|
description="A test template",
|
|
tags=["test"],
|
|
)
|
|
assert resp.status_code == 201
|
|
data = resp.json()
|
|
assert data["name"] == "API Test Template"
|
|
assert data["id"].startswith("apt_")
|
|
assert len(data["filters"]) == 1
|
|
assert data["filters"][0]["filter_id"] == "gain"
|
|
assert data["description"] == "A test template"
|
|
assert data["tags"] == ["test"]
|
|
|
|
def test_create_invalid_filter_returns_400(self, client):
|
|
resp = client.post(
|
|
"/api/v1/audio-processing-templates",
|
|
json={
|
|
"name": "Bad Template",
|
|
"filters": [{"filter_id": "nonexistent", "options": {}}],
|
|
},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 400
|
|
|
|
def test_get_by_id(self, client):
|
|
create_resp = _create(client, "Fetchable Template")
|
|
tid = create_resp.json()["id"]
|
|
|
|
resp = client.get(f"/api/v1/audio-processing-templates/{tid}", headers=AUTH)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["name"] == "Fetchable Template"
|
|
|
|
def test_get_nonexistent_returns_404(self, client):
|
|
resp = client.get("/api/v1/audio-processing-templates/apt_nonexistent", headers=AUTH)
|
|
assert resp.status_code == 404
|
|
|
|
def test_update(self, client):
|
|
create_resp = _create(client, "Original API Template")
|
|
tid = create_resp.json()["id"]
|
|
|
|
resp = client.put(
|
|
f"/api/v1/audio-processing-templates/{tid}",
|
|
json={
|
|
"name": "Updated API Template",
|
|
"filters": [{"filter_id": "inverter", "options": {}}],
|
|
},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert data["name"] == "Updated API Template"
|
|
assert len(data["filters"]) == 1
|
|
|
|
def test_update_nonexistent_returns_404(self, client):
|
|
resp = client.put(
|
|
"/api/v1/audio-processing-templates/apt_nonexistent",
|
|
json={"name": "X"},
|
|
headers=AUTH,
|
|
)
|
|
assert resp.status_code == 404
|
|
|
|
def test_delete(self, client):
|
|
create_resp = _create(client, "To Delete API")
|
|
tid = create_resp.json()["id"]
|
|
_created_ids.remove(tid)
|
|
|
|
resp = client.delete(f"/api/v1/audio-processing-templates/{tid}", headers=AUTH)
|
|
assert resp.status_code == 204
|
|
|
|
resp2 = client.get(f"/api/v1/audio-processing-templates/{tid}", headers=AUTH)
|
|
assert resp2.status_code == 404
|
|
|
|
def test_delete_nonexistent_returns_404(self, client):
|
|
resp = client.delete("/api/v1/audio-processing-templates/apt_nonexistent", headers=AUTH)
|
|
assert resp.status_code == 404
|
|
|
|
|
|
class TestFilterRegistryAPI:
|
|
"""Test /api/v1/audio-filters endpoint."""
|
|
|
|
def test_list_filters(self, client):
|
|
resp = client.get("/api/v1/audio-filters", headers=AUTH)
|
|
if resp.status_code == 404:
|
|
pytest.skip("Audio filters registry endpoint not implemented")
|
|
assert resp.status_code == 200
|
|
data = resp.json()
|
|
assert "filters" in data
|
|
ids = {f["filter_id"] for f in data["filters"]}
|
|
assert "gain" in ids
|
|
assert "inverter" in ids
|