from unittest.mock import Mock, patch import httpx from services.chat_model_config import ( clear_chat_model_config_cache, get_chat_model_config, ) def setup_function(): clear_chat_model_config_cache() def teardown_function(): clear_chat_model_config_cache() def test_admin_runtime_config_takes_priority(monkeypatch): monkeypatch.setenv("CHAT_MODEL_CONFIG_URL", "http://config.test/runtime") monkeypatch.setenv("AVATAR_MODEL_CONFIG_TOKEN", "shared-secret") response = Mock() response.raise_for_status.return_value = None response.json.return_value = { "data": { "api_base_url": "https://model.test/v1/", "api_key": "runtime-key", "model": "avatar-model", "max_tokens": 2048, "timeout_seconds": 42, } } with patch("services.chat_model_config.httpx.get", return_value=response) as request: config = get_chat_model_config() assert config.source == "admin" assert config.api_base_url == "https://model.test/v1" assert config.model == "avatar-model" assert config.max_tokens == 2048 request.assert_called_once_with( "http://config.test/runtime", headers={"X-Avatar-Config-Token": "shared-secret"}, timeout=5.0, ) def test_runtime_failure_falls_back_to_environment(monkeypatch): monkeypatch.setenv("CHAT_MODEL_CONFIG_URL", "http://config.test/runtime") monkeypatch.setenv("AVATAR_MODEL_CONFIG_TOKEN", "shared-secret") monkeypatch.setenv("CHAT_API_URL", "https://fallback.test/v1/") monkeypatch.setenv("CHAT_API_KEY", "fallback-key") monkeypatch.setenv("CHAT_MODEL", "fallback-model") monkeypatch.setenv("CHAT_MAX_OUTPUT_TOKENS", "1536") request = httpx.Request("GET", "http://config.test/runtime") with patch( "services.chat_model_config.httpx.get", side_effect=httpx.ConnectError("offline", request=request), ): config = get_chat_model_config() assert config.source == "environment" assert config.api_base_url == "https://fallback.test/v1" assert config.api_key == "fallback-key" assert config.model == "fallback-model" assert config.max_tokens == 1536 def test_runtime_config_is_cached(monkeypatch): monkeypatch.setenv("CHAT_MODEL_CONFIG_URL", "") monkeypatch.setenv("CHAT_MODEL", "first-model") first = get_chat_model_config() monkeypatch.setenv("CHAT_MODEL", "second-model") second = get_chat_model_config() assert first is second assert second.model == "first-model"