mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 12:19:06 +00:00
255 lines
8.7 KiB
Python
255 lines
8.7 KiB
Python
import json
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.orm import Session
|
|
|
|
from reflector.api.jibri_webhook import router
|
|
from reflector.models import Transcript
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
from fastapi import FastAPI
|
|
|
|
app = FastAPI()
|
|
app.include_router(router)
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_db():
|
|
db = Mock(spec=Session)
|
|
db.add = Mock()
|
|
db.commit = Mock()
|
|
db.refresh = Mock()
|
|
return db
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_settings():
|
|
with patch("reflector.api.jibri_webhook.settings") as mock:
|
|
mock.JIBRI_RECORDINGS_PATH = "/recordings"
|
|
yield mock
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_pipeline():
|
|
with patch("reflector.api.jibri_webhook.TranscriptMainPipeline") as mock:
|
|
pipeline_instance = Mock()
|
|
pipeline_instance.create = Mock()
|
|
mock.return_value = pipeline_instance
|
|
yield mock
|
|
|
|
|
|
class TestJibriWebhook:
|
|
def test_recording_ready_success_with_events(
|
|
self, client, mock_db, mock_settings, mock_pipeline
|
|
):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
# Create recording directory and files
|
|
session_id = "test-session-123"
|
|
recording_dir = Path(tmpdir) / session_id
|
|
recording_dir.mkdir()
|
|
|
|
recording_file = recording_dir / "recording.mp4"
|
|
recording_file.write_text("fake video content")
|
|
|
|
events_file = recording_dir / "events.jsonl"
|
|
events = [
|
|
{
|
|
"type": "room_created",
|
|
"timestamp": 1234567890,
|
|
"room_name": "TestRoom",
|
|
"room_jid": "testroom@conference.meet.jitsi",
|
|
"meeting_url": "https://meet.jitsi/TestRoom",
|
|
},
|
|
{
|
|
"type": "participant_joined",
|
|
"timestamp": 1234567892,
|
|
"room_name": "TestRoom",
|
|
"participant": {
|
|
"jid": "user1@meet.jitsi/resource",
|
|
"nick": "John Doe",
|
|
"id": "user1@meet.jitsi",
|
|
"is_moderator": False,
|
|
},
|
|
},
|
|
]
|
|
|
|
with open(events_file, "w") as f:
|
|
for event in events:
|
|
f.write(json.dumps(event) + "\n")
|
|
|
|
# Mock database dependency
|
|
with patch("reflector.api.jibri_webhook.get_db") as mock_get_db:
|
|
mock_get_db.return_value = mock_db
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": session_id,
|
|
"path": session_id,
|
|
"meeting_url": "https://meet.jitsi/TestRoom",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
|
|
assert data["status"] == "accepted"
|
|
assert data["session_id"] == session_id
|
|
assert data["events_found"] is True
|
|
assert data["participant_count"] == 1
|
|
|
|
# Verify transcript was created
|
|
mock_db.add.assert_called_once()
|
|
transcript_arg = mock_db.add.call_args[0][0]
|
|
assert isinstance(transcript_arg, Transcript)
|
|
assert "TestRoom" in transcript_arg.title
|
|
assert transcript_arg.metadata["jitsi"]["room"]["name"] == "TestRoom"
|
|
|
|
# Verify pipeline was triggered
|
|
mock_pipeline.return_value.create.assert_called_once()
|
|
|
|
def test_recording_ready_success_without_events(
|
|
self, client, mock_db, mock_settings, mock_pipeline
|
|
):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
session_id = "test-session-456"
|
|
recording_dir = Path(tmpdir) / session_id
|
|
recording_dir.mkdir()
|
|
|
|
recording_file = recording_dir / "recording.mp4"
|
|
recording_file.write_text("fake video content")
|
|
|
|
with patch("reflector.api.jibri_webhook.get_db") as mock_get_db:
|
|
mock_get_db.return_value = mock_db
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": session_id,
|
|
"path": session_id,
|
|
"meeting_url": "https://meet.jitsi/NoEventsRoom",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
|
|
assert data["status"] == "accepted"
|
|
assert data["events_found"] is False
|
|
assert data["participant_count"] == 0
|
|
|
|
# Verify transcript was created with minimal metadata
|
|
mock_db.add.assert_called_once()
|
|
transcript_arg = mock_db.add.call_args[0][0]
|
|
assert transcript_arg.metadata["jitsi"]["participants"] == []
|
|
|
|
def test_recording_ready_path_not_found(self, client, mock_settings):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": "nonexistent",
|
|
"path": "nonexistent",
|
|
"meeting_url": "https://meet.jitsi/Test",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 404
|
|
assert "Recording path not found" in response.json()["detail"]
|
|
|
|
def test_recording_ready_recording_file_not_found(self, client, mock_settings):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
session_id = "test-no-recording"
|
|
recording_dir = Path(tmpdir) / session_id
|
|
recording_dir.mkdir()
|
|
|
|
# No recording.mp4 file created
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": session_id,
|
|
"path": session_id,
|
|
"meeting_url": "https://meet.jitsi/Test",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 404
|
|
assert "Recording file not found" in response.json()["detail"]
|
|
|
|
def test_recording_ready_with_relative_path(
|
|
self, client, mock_db, mock_settings, mock_pipeline
|
|
):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
# Create nested directory structure
|
|
session_id = "2024/01/15/test-session"
|
|
recording_dir = Path(tmpdir) / session_id
|
|
recording_dir.mkdir(parents=True)
|
|
|
|
recording_file = recording_dir / "recording.mp4"
|
|
recording_file.write_text("fake video content")
|
|
|
|
with patch("reflector.api.jibri_webhook.get_db") as mock_get_db:
|
|
mock_get_db.return_value = mock_db
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": "test-session",
|
|
"path": session_id, # Relative path with subdirectories
|
|
"meeting_url": "https://meet.jitsi/Test",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "accepted"
|
|
|
|
def test_recording_ready_empty_meeting_url(
|
|
self, client, mock_db, mock_settings, mock_pipeline
|
|
):
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
mock_settings.JIBRI_RECORDINGS_PATH = tmpdir
|
|
|
|
session_id = "test-session"
|
|
recording_dir = Path(tmpdir) / session_id
|
|
recording_dir.mkdir()
|
|
|
|
recording_file = recording_dir / "recording.mp4"
|
|
recording_file.write_text("fake video content")
|
|
|
|
with patch("reflector.api.jibri_webhook.get_db") as mock_get_db:
|
|
mock_get_db.return_value = mock_db
|
|
|
|
response = client.post(
|
|
"/api/v1/jibri/recording-ready",
|
|
json={
|
|
"session_id": session_id,
|
|
"path": session_id,
|
|
"meeting_url": "",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
|
|
# Verify fallback URL was used
|
|
transcript_arg = mock_db.add.call_args[0][0]
|
|
assert transcript_arg.source_url == f"jitsi://{session_id}"
|