from fastapi.testclient import TestClient import backend.models as models from backend import config from backend.main import app _PAYLOAD = { "data": [ { "id": "openai/gpt-4o", "name": "GPT-4o", "pricing": {"prompt": "0.0000025", "completion": "0.00001"}, "context_length": 128000, "architecture": {"input_modalities": ["text", "image"], "output_modalities": ["text"]}, }, { "id": "google/gemini-2.5-pro", "name": "Gemini 2.5 Pro", "pricing": {"prompt": "0.00000125", "completion": "0.00001"}, "context_length": 1000000, "architecture": {"modality": "text+image->text"}, }, { "id": "meta-llama/llama-3.1-70b-instruct", "name": "Llama 3.1 70B Instruct", "pricing": {"prompt": "0.0000005", "completion": "0.0000008"}, "context_length": 131072, "architecture": {"input_modalities": ["text"], "output_modalities": ["text"]}, }, ] } def _reset_cache(): models._cache["models"] = None models._cache["at"] = 0.0 def test_models_endpoint_normalizes_pricing(monkeypatch): _reset_cache() monkeypatch.setattr(models, "_fetch_openrouter_models", lambda: _PAYLOAD["data"]) client = TestClient(app) response = client.get("/models") assert response.status_code == 200 body = response.json() assert body["defaults"] == {"vision": config.MODEL, "text": config.TEXT_MODEL} by_id = {m["id"]: m for m in body["text"]} assert by_id["openai/gpt-4o"]["prompt_usd_per_mtok"] == 2.5 assert by_id["openai/gpt-4o"]["completion_usd_per_mtok"] == 10.0 assert by_id["openai/gpt-4o"]["context_length"] == 128000 def test_models_endpoint_splits_vision_and_text(monkeypatch): _reset_cache() monkeypatch.setattr(models, "_fetch_openrouter_models", lambda: _PAYLOAD["data"]) client = TestClient(app) body = client.get("/models").json() vision_ids = {m["id"] for m in body["vision"]} text_ids = {m["id"] for m in body["text"]} # Both modality shapes (structured and legacy string) are recognized. assert vision_ids == {"openai/gpt-4o", "google/gemini-2.5-pro"} # Text list is the full catalog; vision models appear in both. assert text_ids == {"openai/gpt-4o", "google/gemini-2.5-pro", "meta-llama/llama-3.1-70b-instruct"} def test_models_endpoint_caches(monkeypatch): _reset_cache() calls = [] def fake_fetch(): calls.append(1) return _PAYLOAD["data"] monkeypatch.setattr(models, "_fetch_openrouter_models", fake_fetch) client = TestClient(app) assert client.get("/models").status_code == 200 assert client.get("/models").status_code == 200 assert len(calls) == 1 def test_models_endpoint_502_on_fetch_failure(monkeypatch): _reset_cache() monkeypatch.setattr(models, "_fetch_openrouter_models", lambda: None) client = TestClient(app) assert client.get("/models").status_code == 502