This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/backend/tests/test_recording_api.py
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

295 lines
9.7 KiB
Python

"""
Tests for Recording API
Tests for Jibri webhook handling, recording management, and transcription endpoints.
"""
import pytest
from datetime import datetime, timedelta
from fastapi.testclient import TestClient
# Import the app (adjust import path as needed)
# In actual test environment, this would be the main FastAPI app
# from main import app
# For now, we create a minimal test setup
from fastapi import FastAPI
from recording_api import router as recording_router
app = FastAPI()
app.include_router(recording_router)
client = TestClient(app)
class TestJibriWebhook:
"""Tests for Jibri webhook endpoint."""
def test_webhook_recording_completed_valid(self):
"""Test webhook with valid recording_completed event."""
payload = {
"event": "recording_completed",
"recording_name": "test-room_20260115_120000",
"storage_path": "recordings/test-room_20260115_120000/video.mp4",
"audio_path": "recordings/test-room_20260115_120000/audio.wav",
"file_size_bytes": 52428800,
"timestamp": "2026-01-15T12:00:00Z"
}
response = client.post("/api/recordings/webhook", json=payload)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["status"] == "uploaded"
assert "recording_id" in data
assert data["meeting_id"] == "test-room"
def test_webhook_unknown_event_rejected(self):
"""Test that unknown event types are rejected."""
payload = {
"event": "unknown_event",
"recording_name": "test",
"storage_path": "test/video.mp4",
"file_size_bytes": 1000,
"timestamp": "2026-01-15T12:00:00Z"
}
response = client.post("/api/recordings/webhook", json=payload)
assert response.status_code == 400
assert "Unknown event type" in response.json()["error"]
def test_webhook_missing_required_fields(self):
"""Test that missing required fields cause validation error."""
payload = {
"event": "recording_completed"
# Missing other required fields
}
response = client.post("/api/recordings/webhook", json=payload)
assert response.status_code == 422 # Validation error
class TestRecordingManagement:
"""Tests for recording CRUD operations."""
@pytest.fixture(autouse=True)
def setup(self):
"""Create a test recording before each test."""
# Clear store and create test recording
from recording_api import _recordings_store
_recordings_store.clear()
payload = {
"event": "recording_completed",
"recording_name": "fixture-room_20260115_100000",
"storage_path": "recordings/fixture-room/video.mp4",
"file_size_bytes": 10000000,
"timestamp": "2026-01-15T10:00:00Z"
}
response = client.post("/api/recordings/webhook", json=payload)
self.recording_id = response.json()["recording_id"]
def test_list_recordings_empty(self):
"""Test listing recordings when empty."""
from recording_api import _recordings_store
_recordings_store.clear()
response = client.get("/api/recordings")
assert response.status_code == 200
data = response.json()
assert data["total"] == 0
assert data["recordings"] == []
def test_list_recordings_with_data(self):
"""Test listing recordings returns created recordings."""
response = client.get("/api/recordings")
assert response.status_code == 200
data = response.json()
assert data["total"] == 1
assert len(data["recordings"]) == 1
def test_list_recordings_filter_by_status(self):
"""Test filtering recordings by status."""
response = client.get("/api/recordings?status=uploaded")
assert response.status_code == 200
data = response.json()
assert all(r["status"] == "uploaded" for r in data["recordings"])
def test_list_recordings_pagination(self):
"""Test pagination of recordings list."""
response = client.get("/api/recordings?page=1&page_size=10")
assert response.status_code == 200
data = response.json()
assert data["page"] == 1
assert data["page_size"] == 10
def test_get_recording_by_id(self):
"""Test getting a specific recording by ID."""
response = client.get(f"/api/recordings/{self.recording_id}")
assert response.status_code == 200
data = response.json()
assert data["id"] == self.recording_id
assert data["status"] == "uploaded"
def test_get_recording_not_found(self):
"""Test getting non-existent recording returns 404."""
response = client.get("/api/recordings/nonexistent-id")
assert response.status_code == 404
assert "not found" in response.json()["detail"].lower()
def test_delete_recording(self):
"""Test soft-deleting a recording."""
response = client.delete(
f"/api/recordings/{self.recording_id}?reason=DSGVO%20request"
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["status"] == "deleted"
def test_delete_recording_requires_reason(self):
"""Test that deletion requires a reason."""
response = client.delete(f"/api/recordings/{self.recording_id}")
assert response.status_code == 422 # Missing required query param
class TestTranscriptionEndpoints:
"""Tests for transcription management."""
@pytest.fixture(autouse=True)
def setup(self):
"""Create test recording and clear transcription store."""
from recording_api import _recordings_store, _transcriptions_store
_recordings_store.clear()
_transcriptions_store.clear()
payload = {
"event": "recording_completed",
"recording_name": "trans-test_20260115_110000",
"storage_path": "recordings/trans-test/video.mp4",
"file_size_bytes": 5000000,
"timestamp": "2026-01-15T11:00:00Z"
}
response = client.post("/api/recordings/webhook", json=payload)
self.recording_id = response.json()["recording_id"]
def test_start_transcription(self):
"""Test starting a transcription job."""
response = client.post(
f"/api/recordings/{self.recording_id}/transcribe",
json={"language": "de", "model": "large-v3"}
)
assert response.status_code == 200
data = response.json()
assert data["status"] == "pending"
assert data["language"] == "de"
assert data["model"] == "large-v3"
def test_start_transcription_default_values(self):
"""Test transcription uses default values when not specified."""
response = client.post(
f"/api/recordings/{self.recording_id}/transcribe",
json={}
)
assert response.status_code == 200
data = response.json()
assert data["language"] == "de"
assert data["model"] == "large-v3"
def test_start_transcription_recording_not_found(self):
"""Test starting transcription for non-existent recording."""
response = client.post(
"/api/recordings/nonexistent/transcribe",
json={"language": "de"}
)
assert response.status_code == 404
def test_start_transcription_duplicate_rejected(self):
"""Test that duplicate transcription requests are rejected."""
# First request
client.post(
f"/api/recordings/{self.recording_id}/transcribe",
json={"language": "de"}
)
# Second request should fail
response = client.post(
f"/api/recordings/{self.recording_id}/transcribe",
json={"language": "de"}
)
assert response.status_code == 409
assert "already exists" in response.json()["detail"]
def test_get_transcription_status(self):
"""Test getting transcription status."""
# Start transcription first
client.post(
f"/api/recordings/{self.recording_id}/transcribe",
json={"language": "de"}
)
response = client.get(
f"/api/recordings/{self.recording_id}/transcription"
)
assert response.status_code == 200
data = response.json()
assert data["recording_id"] == self.recording_id
assert data["status"] == "pending"
def test_get_transcription_not_found(self):
"""Test getting transcription for recording without transcription."""
response = client.get(
f"/api/recordings/{self.recording_id}/transcription"
)
assert response.status_code == 404
class TestAuditLog:
"""Tests for audit log endpoints."""
def test_get_audit_log(self):
"""Test retrieving audit log entries."""
response = client.get("/api/recordings/audit/log")
assert response.status_code == 200
data = response.json()
assert "entries" in data
assert "total" in data
def test_get_audit_log_filter_by_action(self):
"""Test filtering audit log by action."""
response = client.get("/api/recordings/audit/log?action=created")
assert response.status_code == 200
class TestHealthCheck:
"""Tests for health check endpoint."""
def test_health_check(self):
"""Test health check returns healthy status."""
response = client.get("/api/recordings/health")
assert response.status_code == 200
data = response.json()
assert data["status"] == "healthy"
assert "recordings_count" in data
assert "minio_endpoint" in data