"""Integrationstests Projekt-/Media-/Plugin-API (PLAN.md §23.1, §13.3).""" from __future__ import annotations import io import pytest from fastapi.testclient import TestClient from hms_control_server import create_app @pytest.fixture() def client() -> TestClient: return TestClient(create_app()) # ---------- Projekte (§23.1, §24.2) ---------- def test_project_crud_roundtrip(client: TestClient) -> None: """Projekt anlegen → laden → aktualisieren → löschen (§23.1).""" created = client.post("/api/v1/projects", json={"name": "Test Show"}) assert created.status_code == 200 project = created.json()["project"] assert project["name"] == "Test Show" assert project["schema_version"] == 1 listed = client.get("/api/v1/projects") assert listed.status_code == 200 assert any(p["name"] == "Test Show" for p in listed.json()["projects"]) fetched = client.get(f"/api/v1/projects/{project['id']}") assert fetched.status_code == 200 assert fetched.json()["name"] == "Test Show" updated = client.put(f"/api/v1/projects/{project['id']}", json={"name": "Umbenannt"}) assert updated.status_code == 200 refetched = client.get(f"/api/v1/projects/{project['id']}") assert refetched.json()["name"] == "Umbenannt" deleted = client.delete(f"/api/v1/projects/{project['id']}") assert deleted.status_code == 200 assert client.get(f"/api/v1/projects/{project['id']}").status_code == 404 def test_project_404_on_unknown(client: TestClient) -> None: assert client.get("/api/v1/projects/00000000-0000-0000-0000-000000000000").status_code == 404 assert client.put( "/api/v1/projects/00000000-0000-0000-0000-000000000000", json={} ).status_code == 404 def test_project_activate(client: TestClient) -> None: """Aktivieren setzt State-Revision im Store (§6.4).""" created = client.post("/api/v1/projects", json={"name": "Show A"}) project_id = created.json()["project"]["id"] activated = client.post(f"/api/v1/projects/{project_id}/activate") assert activated.status_code == 200 assert activated.json()["state_revision"] >= 1 # Projekt aktivieren mit unbekannter ID → 404 unknown = "00000000-0000-0000-0000-000000000000" assert client.post(f"/api/v1/projects/{unknown}/activate").status_code == 404 # ---------- Medien (§13.3) ---------- def test_media_import_and_list(client: TestClient) -> None: """Upload mit Duplikaterkennung: erst importiert, dann duplicate (§13.3).""" content = b"fake-video-bytes-for-testing-only" # 1. Import r1 = client.post( "/api/v1/media/import", files={"file": ("test.mp4", io.BytesIO(content), "video/mp4")}, ) assert r1.status_code == 200 body1 = r1.json() assert body1["status"] == "imported" assert body1["asset"]["rel_path"] == "test.mp4" assert body1["asset"]["content_hash"] # 2. Duplikat (gleicher Inhalt) r2 = client.post( "/api/v1/media/import", files={"file": ("kopie.mp4", io.BytesIO(content), "video/mp4")}, ) assert r2.status_code == 200 body2 = r2.json() assert body2["status"] == "duplicate" assert body2["duplicate_of"] == body1["asset"]["id"] # 3. Liste zeigt beide, markiert nichts fehlend listed = client.get("/api/v1/media") assert listed.status_code == 200 assert len(listed.json()["media"]) >= 1 assert listed.json()["missing_count"] == 0 def test_media_list_empty(client: TestClient) -> None: listed = client.get("/api/v1/media") assert listed.status_code == 200 assert "media" in listed.json() # ---------- Plugins (§14.5) ---------- def test_plugins_listed_by_state(client: TestClient) -> None: """Plugins erscheinen nach Lifecycle-Status gruppiert (§14.5).""" listed = client.get("/api/v1/plugins") assert listed.status_code == 200 body = listed.json() assert body["total"] >= 24 # alle Builtin-Plugins gefunden assert "validated" in body["plugins_by_state"] generators = [ p for p in body["plugins_by_state"].get("validated", []) if p["kind"] == "generator" ] filters = [ p for p in body["plugins_by_state"].get("validated", []) if p["kind"] == "filter" ] assert len(generators) == 10 # §15.1 assert len(filters) == 14 # §15.2 def test_plugin_enable_unknown_returns_404(client: TestClient) -> None: """Unbekanntes Plugin → 404, kein Absturz (§14.5).""" r = client.post("/api/v1/plugins/com.gibts.nicht/enable") assert r.status_code == 404 # ---------- Diagnostics ---------- def test_diagnostics_reports_revisions(client: TestClient) -> None: """Diagnostics zeigt State- und Projekt-Revisionen (§28.2).""" r = client.get("/api/v1/diagnostics") assert r.status_code == 200 body = r.json() assert "state_revision" in body assert "project_revision" in body