IIIF-Studio / backend /tests /test_api_profiles.py
Claude
fix(paths): analyse systémique et correction exhaustive des chemins en production
4d7e198 unverified
"""
Tests HTTP de l'endpoint GET /api/v1/profiles (Sprint 1 — régression Docker).
Pourquoi ces tests existent :
GET /api/v1/profiles retournait [] en production (HuggingFace) alors qu'il
fonctionnait en local. Cause : chemin relatif vers profiles/ non résolu dans
le container Docker. Ces tests vérifient l'endpoint HTTP complet (pas seulement
le schéma Pydantic) pour détecter toute régression de chemin en CI.
Stratégie :
- Utilise le dossier profiles/ réel du dépôt via settings.profiles_dir
(déjà résolu correctement en local par config.py via Path(__file__).resolve())
- Teste le cas de régression : retourne [] si profiles_dir est manquant
"""
# 1. stdlib
from pathlib import Path
# 2. third-party
import pytest
# 3. local
import app.config as config_mod
from tests.conftest_api import async_client, db_session # noqa: F401
# ── Tests "happy path" — utilise le vrai dossier profiles/ ────────────────────
@pytest.mark.asyncio
async def test_list_profiles_returns_nonempty_list(async_client):
"""L'endpoint retourne une liste non vide — régression Docker principale."""
resp = await async_client.get("/api/v1/profiles")
assert resp.status_code == 200
data = resp.json()
assert isinstance(data, list)
assert len(data) > 0, (
f"profiles_dir={config_mod.settings.profiles_dir} "
f"(exists={config_mod.settings.profiles_dir.is_dir()}) — "
"l'endpoint retourne [] alors qu'il devrait retourner les 4 profils"
)
@pytest.mark.asyncio
async def test_list_profiles_returns_all_four_profiles(async_client):
"""Les 4 profils du dépôt sont tous retournés."""
resp = await async_client.get("/api/v1/profiles")
assert resp.status_code == 200
ids = {p["profile_id"] for p in resp.json()}
expected = {
"medieval-illuminated",
"medieval-textual",
"early-modern-print",
"modern-handwritten",
}
assert ids == expected
@pytest.mark.asyncio
async def test_list_profiles_each_has_required_fields(async_client):
"""Chaque profil expose les champs obligatoires de CorpusProfile."""
resp = await async_client.get("/api/v1/profiles")
assert resp.status_code == 200
for profile in resp.json():
assert "profile_id" in profile
assert "label" in profile
assert "active_layers" in profile
assert "prompt_templates" in profile
assert "script_type" in profile
assert "language_hints" in profile
@pytest.mark.asyncio
async def test_get_profile_by_id(async_client):
"""GET /api/v1/profiles/{id} retourne le profil correspondant."""
resp = await async_client.get("/api/v1/profiles/medieval-illuminated")
assert resp.status_code == 200
data = resp.json()
assert data["profile_id"] == "medieval-illuminated"
assert data["script_type"] == "caroline"
@pytest.mark.asyncio
async def test_get_profile_by_id_not_found(async_client):
"""GET /api/v1/profiles/{id} retourne 404 pour un identifiant inconnu."""
resp = await async_client.get("/api/v1/profiles/nonexistent-xyz")
assert resp.status_code == 404
# ── Test de régression Docker — simule un profiles_dir manquant ───────────────
@pytest.mark.asyncio
async def test_list_profiles_empty_when_dir_missing(async_client):
"""Retourne [] si profiles_dir n'existe pas (régression Docker).
Ce test reproduit exactement la condition du bug de production :
settings.profiles_dir pointe vers un répertoire qui n'existe pas dans
le container (mauvais chemin résolu). L'endpoint doit retourner [] sans
erreur 500, mais le test vérifie aussi que le cas ne se produit pas en
conditions normales (voir test_list_profiles_returns_nonempty_list).
"""
original = config_mod.settings.profiles_dir
config_mod.settings.profiles_dir = Path("/nonexistent/path/profiles")
try:
resp = await async_client.get("/api/v1/profiles")
finally:
config_mod.settings.profiles_dir = original
assert resp.status_code == 200
assert resp.json() == []