Phase 14a: Integration-Tests (FastAPI TestClient, ohne DB)
tests/test_api_smoke.py:
- 43 parametrisierte Auth-Coverage-Tests: jeder geschuetzte Endpoint
muss ohne Authorization-Header 401 oder 403 liefern (nicht 200, nicht 500).
Verhindert, dass jemand versehentlich einen Endpoint ohne
get_current_admin schreibt.
- 2 Tests fuer oeffentliche Auth-Endpoints (/magic-link, /verify):
pruefen nur, dass NICHT 401/403 zurueckkommt.
- 2 Static-Route-Tests (/, /dashboard) muessen 200 liefern.
- TestClient(raise_server_exceptions=False) damit DB-Probleme nicht zu
Test-Aborts werden.
tests/test_api_meta.py:
- Integration-Tests fuer /api/sources/meta mit dependency_overrides
(Mock get_current_admin). DB-frei, deshalb echte Endpoint-Logik
vollstaendig durchgetestet.
- 5 Tests: Schema vorhanden, Pflichtfelder, spezielle Lagen-Themen,
alle 5 source-types.
Insgesamt: 80 Tests, 0.63s. Aufruf:
PYTHONPATH=src ./venv/bin/python -m pytest tests/ -v
Phase 14b (echtes DB-Schema-Setup mit aiosqlite-In-Memory) folgt separat,
braucht Schema-Bootstrap - viel groesserer Aufwand fuer CRUD-Tests.
Dieser Commit ist enthalten in:
65
tests/test_api_meta.py
Normale Datei
65
tests/test_api_meta.py
Normale Datei
@@ -0,0 +1,65 @@
|
||||
"""Integration-Tests fuer DB-freie Endpoints mit Mock-Auth.
|
||||
|
||||
GET /api/sources/meta liefert die Single-Source-of-Truth Kategorien/Typen
|
||||
und braucht keine DB. Mit override des get_current_admin Dependency
|
||||
testen wir den Endpoint richtig durch (echtes JSON, echtes Schema).
|
||||
"""
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def authed_client():
|
||||
from main import app
|
||||
from auth import get_current_admin
|
||||
|
||||
def fake_admin():
|
||||
return {"id": 1, "email": "test@aegis-sight.de", "username": "test"}
|
||||
|
||||
app.dependency_overrides[get_current_admin] = fake_admin
|
||||
yield TestClient(app)
|
||||
app.dependency_overrides = {}
|
||||
|
||||
|
||||
def test_meta_returns_schema(authed_client):
|
||||
r = authed_client.get("/api/sources/meta")
|
||||
assert r.status_code == 200
|
||||
data = r.json()
|
||||
assert "categories" in data
|
||||
assert "types" in data
|
||||
assert isinstance(data["categories"], list)
|
||||
assert isinstance(data["types"], list)
|
||||
|
||||
|
||||
def test_meta_categories_have_required_fields(authed_client):
|
||||
r = authed_client.get("/api/sources/meta")
|
||||
data = r.json()
|
||||
for cat in data["categories"]:
|
||||
assert "key" in cat
|
||||
assert "label" in cat
|
||||
assert isinstance(cat["key"], str) and cat["key"]
|
||||
assert isinstance(cat["label"], str) and cat["label"]
|
||||
|
||||
|
||||
def test_meta_types_have_required_fields(authed_client):
|
||||
r = authed_client.get("/api/sources/meta")
|
||||
data = r.json()
|
||||
for t in data["types"]:
|
||||
assert "key" in t
|
||||
assert "label" in t
|
||||
|
||||
|
||||
def test_meta_includes_specialized_categories(authed_client):
|
||||
"""Phase 3b - die spezielleren Lagen-Themen muessen als Kategorien existieren."""
|
||||
r = authed_client.get("/api/sources/meta")
|
||||
keys = {c["key"] for c in r.json()["categories"]}
|
||||
assert "cybercrime" in keys
|
||||
assert "ukraine-russland-krieg" in keys
|
||||
assert "russische-staatspropaganda" in keys
|
||||
|
||||
|
||||
def test_meta_includes_all_source_types(authed_client):
|
||||
"""Alle 5 Source-Types muessen rauskommen."""
|
||||
r = authed_client.get("/api/sources/meta")
|
||||
keys = {t["key"] for t in r.json()["types"]}
|
||||
assert keys == {"rss_feed", "web_source", "telegram_channel", "podcast_feed", "excluded"}
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren