Spaces:
Build error
Build error
Claude
refactor: Sprint 3b — remove dead code, non-functional provider, unused fields
11f019c unverified | """ | |
| 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 | |
| # --------------------------------------------------------------------------- | |
| 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) | |
| 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 | |
| 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 | |
| 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) | |
| 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 | |
| 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 | |
| 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 | |
| # --------------------------------------------------------------------------- | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |