mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-12 19:56:53 +00:00
✨(summary) add multi-tenant support and v2 tasks / API
Add multitenancy support to Summary sub-app. The V1 routes / tasks behave like before, with the default tenant being "meet". V2 routes / tasks support being called frm any tenant, and don't have meet related logic. V2 tasks are created in separate queues to avoid mix / match,i
This commit is contained in:
@@ -5,7 +5,7 @@ class TestHeartbeat:
|
||||
"""Tests for the /__heartbeat__ endpoint."""
|
||||
|
||||
def test_returns_200(self, client):
|
||||
"""The heartbeat endpoint responds with 200 OK without a token."""
|
||||
"""The heartbeat endpoint responds with 200 OK without an api_key."""
|
||||
response = client.get("/__heartbeat__")
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -15,7 +15,7 @@ class TestLBHeartbeat:
|
||||
"""Tests for the /__lbheartbeat__ endpoint."""
|
||||
|
||||
def test_returns_200(self, client):
|
||||
"""The load-balancer heartbeat endpoint responds with 200 OK without a token."""
|
||||
"""The LB heartbeat endpoint responds with 200 OK without an api_key."""
|
||||
response = client.get("/__lbheartbeat__")
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
class TestTasks:
|
||||
"""Tests for the /tasks endpoint."""
|
||||
"""Tests for the /v1/tasks endpoint."""
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks.process_audio_transcribe_summarize_v2.apply_async",
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
"""Integration tests for the V2 task API endpoints."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
class TestTasksV2:
|
||||
"""Tests for the /v2/async-jobs-jobs endpoints."""
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks_v2.process_audio_transcribe_v2_task.apply_async",
|
||||
return_value=MagicMock(id="transcribe-task-id-abc"),
|
||||
)
|
||||
def test_create_transcribe_task_v2_returns_task_id(self, mock_apply_async, client):
|
||||
"""POST /async-jobs/transcribe creates a task and injects tenant_id."""
|
||||
response = client.post(
|
||||
"/api/v2/async-jobs/transcribe",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
json={
|
||||
"user_sub": "remote-001",
|
||||
"cloud_storage_url": "https://example.com/audio.mp3",
|
||||
"language": "en",
|
||||
"context_language": "fr",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"job_id": "transcribe-task-id-abc",
|
||||
"message": "Transcribe job created",
|
||||
}
|
||||
|
||||
args = mock_apply_async.call_args.kwargs["args"]
|
||||
assert args == [
|
||||
{
|
||||
"user_sub": "remote-001",
|
||||
"cloud_storage_url": "https://example.com/audio.mp3",
|
||||
"language": "en",
|
||||
"context_language": "fr",
|
||||
"tenant_id": "test-tenant",
|
||||
}
|
||||
]
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks_v2.summarize_v2_task.apply_async",
|
||||
return_value=MagicMock(id="summarize-task-id-abc"),
|
||||
)
|
||||
def test_create_summarize_task_v2_returns_task_id(self, mock_apply_async, client):
|
||||
"""POST /async-jobs/summarize creates a task and injects tenant_id."""
|
||||
response = client.post(
|
||||
"/api/v2/async-jobs/summarize",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
json={
|
||||
"user_sub": "remote-002",
|
||||
"content": "This is a long meeting transcript to summarize.",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"job_id": "summarize-task-id-abc",
|
||||
"message": "Summarize job created",
|
||||
}
|
||||
|
||||
args = mock_apply_async.call_args.kwargs["args"]
|
||||
assert args == [
|
||||
{
|
||||
"user_sub": "remote-002",
|
||||
"content": "This is a long meeting transcript to summarize.",
|
||||
"tenant_id": "test-tenant",
|
||||
}
|
||||
]
|
||||
|
||||
@patch("summary.api.route.tasks_v2.AsyncResult")
|
||||
def test_get_transcribe_task_status_returns_status_for_same_tenant(
|
||||
self, mock_async_result, client
|
||||
):
|
||||
"""GET /async-jobs/transcribe/{id} returns status when tenant matches."""
|
||||
mock_async_result.return_value = MagicMock(
|
||||
status="PENDING",
|
||||
args=[{"tenant_id": "test-tenant"}],
|
||||
)
|
||||
|
||||
response = client.get(
|
||||
"/api/v2/async-jobs/transcribe/task-id-abc",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"job_id": "task-id-abc", "status": "PENDING"}
|
||||
|
||||
mock_async_result.assert_called_once_with("task-id-abc")
|
||||
|
||||
@patch("summary.api.route.tasks_v2.AsyncResult")
|
||||
def test_get_summarize_task_status_returns_status_for_same_tenant(
|
||||
self, mock_async_result, client
|
||||
):
|
||||
"""GET /async-jobs/summarize/{id} returns status when tenant matches."""
|
||||
mock_async_result.return_value = MagicMock(
|
||||
status="SUCCESS",
|
||||
args=[{"tenant_id": "test-tenant"}],
|
||||
)
|
||||
|
||||
response = client.get(
|
||||
"/api/v2/async-jobs/summarize/task-id-abc",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"job_id": "task-id-abc", "status": "SUCCESS"}
|
||||
|
||||
mock_async_result.assert_called_once_with("task-id-abc")
|
||||
|
||||
@patch("summary.api.route.tasks_v2.AsyncResult")
|
||||
def test_get_task_status_returns_404_when_args_are_missing(
|
||||
self, mock_async_result, client
|
||||
):
|
||||
"""GET /async-jobs/.../{id} returns 404 when task args are invalid."""
|
||||
mock_async_result.return_value = MagicMock(status="SUCCESS", args=None)
|
||||
|
||||
response = client.get(
|
||||
"/api/v2/async-jobs/transcribe/task-id-abc",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 404
|
||||
assert response.json() == {"detail": "Not found"}
|
||||
@@ -4,14 +4,22 @@ import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import SecretStr
|
||||
|
||||
from summary.core.config import Settings, get_settings
|
||||
from summary.core.config import AuthorizedTenant, Settings, get_settings
|
||||
from summary.main import app
|
||||
|
||||
|
||||
def get_settings_override():
|
||||
"""Return settings for tests."""
|
||||
return Settings(
|
||||
app_api_token=SecretStr("test-api-token"),
|
||||
v1_tenant_id="test-tenant",
|
||||
authorized_tenants=(
|
||||
AuthorizedTenant(
|
||||
webhook_url="https://example.com/webhook",
|
||||
id="test-tenant",
|
||||
api_key=SecretStr("test-api-token"),
|
||||
webhook_api_key=SecretStr("test-webhook-api-key"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user