Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df576aa556 | |||
| 3172fd1015 | |||
| bc18d2478e | |||
| e024b0648b |
@@ -297,6 +297,46 @@ jobs:
|
||||
- name: Run tests
|
||||
run: uv run pytest -n 2
|
||||
|
||||
test-summary:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
working-directory: src/summary
|
||||
|
||||
env:
|
||||
APP_API_TOKEN: "test-api-token"
|
||||
AWS_STORAGE_BUCKET_NAME: "http://meet-media-storage"
|
||||
AWS_S3_ENDPOINT_URL: "minio:9000"
|
||||
AWS_S3_ACCESS_KEY_ID: "meet"
|
||||
AWS_S3_SECRET_ACCESS_KEY: "password"
|
||||
WHISPERX_BASE_URL: "https://configure-your-url.com"
|
||||
WHISPERX_ASR_MODEL: "large-v2"
|
||||
WHISPERX_API_KEY: "test-whisperx-secret"
|
||||
WHISPERX_DEFAULT_LANGUAGE: "fr"
|
||||
LLM_BASE_URL: "https://configure-your-url.com"
|
||||
LLM_API_KEY: "test-llm-secret"
|
||||
LLM_MODEL: "test-llm-model"
|
||||
WEBHOOK_API_TOKEN: "test-webhook-secret"
|
||||
WEBHOOK_URL: "https://configure-your-url.com"
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.13"
|
||||
cache: "pip"
|
||||
|
||||
- name: Install development dependencies
|
||||
run: pip install --user .[dev]
|
||||
|
||||
- name: Run summary tests
|
||||
run: ~/.local/bin/pytest
|
||||
|
||||
lint-front:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
|
||||
@@ -30,7 +30,6 @@ and this project adheres to
|
||||
- ⚡️(helm) reduce initialDelaySeconds and add periods seconds #1139
|
||||
- 🔒️(backend) avoid information exposure through exception messages #1144
|
||||
- ⬆️(dependencies) update PyJWT to v2.12.0 [SECURITY] #1151
|
||||
- 📌(agents) unpin OpenSSL and related dependencies #1167
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -191,6 +191,7 @@ lint-pylint: ## lint back-end python sources with pylint only on changed files f
|
||||
|
||||
test: ## run project tests
|
||||
@$(MAKE) test-back-parallel
|
||||
@$(MAKE) test-summary
|
||||
.PHONY: test
|
||||
|
||||
test-back: ## run back-end tests
|
||||
@@ -203,6 +204,11 @@ test-back-parallel: ## run all back-end tests in parallel
|
||||
bin/pytest -n auto $${args:-${1}}
|
||||
.PHONY: test-back-parallel
|
||||
|
||||
test-summary: ## run summary tests
|
||||
@args="$(filter-out $@,$(MAKECMDGOALS))" && \
|
||||
bin/pytest-summary $${args:-${1}}
|
||||
.PHONY: test-summary
|
||||
|
||||
makemigrations: ## run django makemigrations for the Meet project.
|
||||
@echo "$(BOLD)Running makemigrations$(RESET)"
|
||||
@$(COMPOSE) up -d postgresql
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/_config.sh"
|
||||
|
||||
_dc_run \
|
||||
app-summary-dev \
|
||||
python -m pytest "$@"
|
||||
@@ -4,6 +4,8 @@ FROM python:3.13-slim AS base
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libglib2.0-0 \
|
||||
libgobject-2.0-0 \
|
||||
"openssl=3.5.4-1~deb13u2" \
|
||||
"libssl3t64=3.5.4-1~deb13u2" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
FROM base AS builder
|
||||
|
||||
@@ -21,8 +21,16 @@ dependencies = [
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"ruff==0.14.4",
|
||||
"pytest==9.0.2",
|
||||
"responses>=0.25.8",
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
markers = [
|
||||
"api: Test the API",
|
||||
]
|
||||
testpaths = ["tests"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=61.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
@@ -49,6 +57,7 @@ select = [
|
||||
"T20", # flake8-print
|
||||
"W", # pycodestyle warning
|
||||
]
|
||||
ignore= ["PLR2004"]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*" = [
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"""Tests for the summary service."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Tests for the API summary service."""
|
||||
@@ -0,0 +1,21 @@
|
||||
"""Integration tests for the health check endpoints."""
|
||||
|
||||
|
||||
class TestHeartbeat:
|
||||
"""Tests for the /__heartbeat__ endpoint."""
|
||||
|
||||
def test_returns_200(self, client):
|
||||
"""The heartbeat endpoint responds with 200 OK without a token."""
|
||||
response = client.get("/__heartbeat__")
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
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."""
|
||||
response = client.get("/__lbheartbeat__")
|
||||
|
||||
assert response.status_code == 200
|
||||
@@ -0,0 +1,88 @@
|
||||
"""Integration tests for the API tasks endpoints."""
|
||||
|
||||
# tests/unit/test_api_tasks.py
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
class TestTasks:
|
||||
"""Tests for the /tasks endpoint."""
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks.process_audio_transcribe_summarize_v2.apply_async",
|
||||
return_value=MagicMock(id="task-id-abc"),
|
||||
)
|
||||
@patch("summary.api.route.tasks.time.time", return_value=1735725600.0)
|
||||
def test_create_task_returns_task_id(self, mock_time, mock_apply_async, client):
|
||||
"""POST /tasks/ with valid payload returns id and dispatches Celery task."""
|
||||
response = client.post(
|
||||
"api/v1/tasks/",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
json={
|
||||
"owner_id": "owner-123",
|
||||
"filename": "recording.mp4",
|
||||
"email": "user@example.com",
|
||||
"sub": "sub-123",
|
||||
"room": "room-abc",
|
||||
"recording_date": "2026-01-01",
|
||||
"recording_time": "10:00:00",
|
||||
"language": None,
|
||||
"download_link": "http://example.com/file.mp4",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"id": "task-id-abc", "message": "Task created"}
|
||||
|
||||
args = mock_apply_async.call_args.kwargs["args"]
|
||||
assert args == [
|
||||
"owner-123", # owner_id
|
||||
"recording.mp4", # filename
|
||||
"user@example.com", # email
|
||||
"sub-123", # sub
|
||||
1735725600.0, # frozen time
|
||||
"room-abc", # room
|
||||
"2026-01-01", # recording_date
|
||||
"10:00:00", # recording_time
|
||||
None, # language
|
||||
"http://example.com/file.mp4", # download_link
|
||||
None, # context_language
|
||||
]
|
||||
|
||||
def test_create_task_invalid_language(self, client):
|
||||
"""POST /tasks/ with an unsupported language returns 422."""
|
||||
payload = {"language": "klingon"}
|
||||
response = client.post(
|
||||
"/api/v1/tasks/",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
json=payload,
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks.AsyncResult",
|
||||
return_value=MagicMock(status="PENDING"),
|
||||
)
|
||||
def test_get_task_status_pending(self, mock_result, client):
|
||||
"""GET /tasks/{id} returns PENDING status when the task has not started yet."""
|
||||
response = client.get(
|
||||
"/api/v1/tasks/task-id-abc",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"id": "task-id-abc", "status": "PENDING"}
|
||||
|
||||
@patch(
|
||||
"summary.api.route.tasks.AsyncResult",
|
||||
return_value=MagicMock(status="SUCCESS"),
|
||||
)
|
||||
def test_get_task_status_success(self, mock_result, client):
|
||||
"""GET /tasks/{id} returns SUCCESS status when the task has completed."""
|
||||
response = client.get(
|
||||
"/api/v1/tasks/task-id-abc",
|
||||
headers={"Authorization": "Bearer test-api-token"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "SUCCESS"
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Integration test configuration. Provides shared fixtures."""
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import SecretStr
|
||||
|
||||
from summary.core.config import 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"),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def client():
|
||||
"""Provide a FastAPI TestClient for tests."""
|
||||
client = TestClient(app)
|
||||
app.dependency_overrides[get_settings] = get_settings_override
|
||||
|
||||
return client
|
||||
Reference in New Issue
Block a user