""" 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