Spaces:
Build error
Build error
File size: 8,107 Bytes
2d76892 193eb98 2d76892 193eb98 2d76892 11f019c 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 193eb98 2d76892 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | """
Tests des endpoints GET /api/v1/providers et GET /api/v1/providers/{type}/models.
Stratégie :
- get_available_providers() et list_models_for_provider() mockés via monkeypatch
sur models_api_module (nom local après import from … import …)
- BDD SQLite en mémoire (fixture async_client)
Vérifie :
- GET /api/v1/providers → liste de providers avec available + model_count
- GET /api/v1/providers/{provider_type}/models → 200 ou 404/503
- Comportement avec 0, 1 ou plusieurs providers disponibles
"""
# 1. stdlib
from datetime import datetime, timezone
# 2. third-party
import pytest
# 3. local
import app.api.v1.models_api as models_api_module
from app.schemas.model_config import ModelInfo, ProviderType
from tests.conftest_api import async_client, db_session # noqa: F401
_NOW = datetime.now(timezone.utc)
_PROVIDERS_ALL_UNAVAILABLE = [
{"provider_type": "google_ai_studio", "display_name": "Google AI Studio", "available": False, "model_count": 0},
{"provider_type": "vertex_service_account", "display_name": "Vertex AI (compte de service)", "available": False, "model_count": 0},
{"provider_type": "mistral", "display_name": "Mistral AI", "available": False, "model_count": 0},
]
_PROVIDERS_GOOGLE_ONLY = [
{"provider_type": "google_ai_studio", "display_name": "Google AI Studio", "available": True, "model_count": 2},
{"provider_type": "vertex_service_account", "display_name": "Vertex AI (compte de service)", "available": False, "model_count": 0},
{"provider_type": "mistral", "display_name": "Mistral AI", "available": False, "model_count": 0},
]
_PROVIDERS_GOOGLE_AND_MISTRAL = [
{"provider_type": "google_ai_studio", "display_name": "Google AI Studio", "available": True, "model_count": 3},
{"provider_type": "vertex_service_account", "display_name": "Vertex AI (compte de service)", "available": False, "model_count": 0},
{"provider_type": "mistral", "display_name": "Mistral AI", "available": True, "model_count": 2},
]
_MOCK_GOOGLE_MODELS = [
ModelInfo(
model_id="gemini-2.0-flash",
display_name="Gemini 2.0 Flash",
provider=ProviderType.GOOGLE_AI_STUDIO,
supports_vision=True,
input_token_limit=1_000_000,
output_token_limit=8192,
),
ModelInfo(
model_id="gemini-1.5-pro",
display_name="Gemini 1.5 Pro",
provider=ProviderType.GOOGLE_AI_STUDIO,
supports_vision=True,
input_token_limit=2_000_000,
output_token_limit=8192,
),
]
_MOCK_MISTRAL_MODELS = [
ModelInfo(
model_id="pixtral-large-latest",
display_name="Pixtral Large",
provider=ProviderType.MISTRAL,
supports_vision=True,
input_token_limit=128_000,
output_token_limit=None,
),
ModelInfo(
model_id="pixtral-12b-2409",
display_name="Pixtral 12B",
provider=ProviderType.MISTRAL,
supports_vision=True,
input_token_limit=128_000,
output_token_limit=None,
),
]
# ---------------------------------------------------------------------------
# GET /api/v1/providers
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_list_providers_returns_list(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_ALL_UNAVAILABLE)
resp = await async_client.get("/api/v1/providers")
assert resp.status_code == 200
assert isinstance(resp.json(), list)
@pytest.mark.asyncio
async def test_list_providers_count(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_ALL_UNAVAILABLE)
data = (await async_client.get("/api/v1/providers")).json()
assert len(data) == 3 # 3 providers connus
@pytest.mark.asyncio
async def test_list_providers_fields(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_ALL_UNAVAILABLE)
data = (await async_client.get("/api/v1/providers")).json()
p = data[0]
assert "provider_type" in p
assert "display_name" in p
assert "available" in p
assert "model_count" in p
@pytest.mark.asyncio
async def test_list_providers_all_unavailable(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_ALL_UNAVAILABLE)
data = (await async_client.get("/api/v1/providers")).json()
assert all(not p["available"] for p in data)
assert all(p["model_count"] == 0 for p in data)
@pytest.mark.asyncio
async def test_list_providers_google_available(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_GOOGLE_ONLY)
data = (await async_client.get("/api/v1/providers")).json()
google = next(p for p in data if p["provider_type"] == "google_ai_studio")
assert google["available"] is True
assert google["model_count"] == 2
@pytest.mark.asyncio
async def test_list_providers_mistral_available(async_client, monkeypatch):
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_GOOGLE_AND_MISTRAL)
data = (await async_client.get("/api/v1/providers")).json()
mistral = next(p for p in data if p["provider_type"] == "mistral")
assert mistral["available"] is True
assert mistral["model_count"] == 2
@pytest.mark.asyncio
async def test_list_providers_includes_mistral_type(async_client, monkeypatch):
"""Mistral est toujours dans la liste même si indisponible."""
monkeypatch.setattr("app.services.ai.model_registry.get_available_providers", lambda: _PROVIDERS_ALL_UNAVAILABLE)
data = (await async_client.get("/api/v1/providers")).json()
types_ = [p["provider_type"] for p in data]
assert "mistral" in types_
# ---------------------------------------------------------------------------
# GET /api/v1/providers/{provider_type}/models
# ---------------------------------------------------------------------------
@pytest.mark.asyncio
async def test_get_provider_models_google(async_client, monkeypatch):
monkeypatch.setattr(
"app.services.ai.model_registry.list_models_for_provider", lambda ptype: _MOCK_GOOGLE_MODELS
)
resp = await async_client.get("/api/v1/providers/google_ai_studio/models")
assert resp.status_code == 200
assert len(resp.json()) == 2
@pytest.mark.asyncio
async def test_get_provider_models_mistral(async_client, monkeypatch):
monkeypatch.setattr(
"app.services.ai.model_registry.list_models_for_provider", lambda ptype: _MOCK_MISTRAL_MODELS
)
resp = await async_client.get("/api/v1/providers/mistral/models")
assert resp.status_code == 200
data = resp.json()
assert len(data) == 2
ids = [m["model_id"] for m in data]
assert "pixtral-large-latest" in ids
assert "pixtral-12b-2409" in ids
@pytest.mark.asyncio
async def test_get_provider_models_unknown_provider(async_client):
resp = await async_client.get("/api/v1/providers/openai/models")
assert resp.status_code == 404
@pytest.mark.asyncio
async def test_get_provider_models_not_configured(async_client, monkeypatch):
"""Provider connu mais clé absente → 503."""
def _raise(ptype):
raise RuntimeError("Variable d'environnement manquante : MISTRAL_API_KEY")
monkeypatch.setattr("app.services.ai.model_registry.list_models_for_provider", _raise)
resp = await async_client.get("/api/v1/providers/mistral/models")
assert resp.status_code == 503
@pytest.mark.asyncio
async def test_get_provider_models_fields(async_client, monkeypatch):
monkeypatch.setattr(
"app.services.ai.model_registry.list_models_for_provider", lambda ptype: _MOCK_MISTRAL_MODELS
)
data = (await async_client.get("/api/v1/providers/mistral/models")).json()
m = data[0]
assert "model_id" in m
assert "display_name" in m
assert "provider" in m
assert "supports_vision" in m
|