Skip to main content
Glama
test_config_extended.py12.4 kB
"""Essential tests for configuration functionality.""" import os import tempfile from unittest.mock import patch, Mock, MagicMock import pytest import json from promptheus.config import Config, find_and_load_dotenv, _is_project_root from pathlib import Path @pytest.fixture def temp_env_file(): """Create a temporary .env file for testing.""" with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.env') as f: f.write("GEMINI_API_KEY=AIza-test-key-from-env\n") f.write("OPENAI_API_KEY=sk-test-openai-key\n") temp_path = f.name yield Path(temp_path) # Cleanup os.unlink(temp_path) @pytest.fixture def config(): """Create a fresh config instance for each test.""" config = Config() # Reset to clear any cached values from other tests config.reset() return config def test_config_initialization(config): """Test config initialization.""" # Config auto-detects provider on first access to .provider property # so let's check after reset that provider is reset config.reset() assert config.model is None # Model should be None initially assert config._status_messages == [] # After reset, messages should be cleared assert config._error_messages == [] # Provider will be auto-detected when accessed, but after reset it's None until accessed assert config._provider is None def test_load_model_config(config): """Test loading model configuration from JSON file.""" config_data = config.load_provider_config() assert isinstance(config_data, dict) assert "providers" in config_data assert "provider_aliases" in config_data def test_reset_config(config): """Test config reset functionality.""" config._provider = "test" config.model = "test-model" config._status_messages = ["test message"] config._error_messages = ["test error"] config.reset() assert config._provider is None assert config.model is None assert config._status_messages == [] assert config._error_messages == [] def test_message_consumption(config): """Test message consumption functionality.""" config._record_status("status message") config._record_error("error message") status_messages = config.consume_status_messages() error_messages = config.consume_error_messages() assert status_messages == ["status message"] assert error_messages == ["error message"] # Messages should be cleared after consumption assert config.consume_status_messages() == [] assert config.consume_error_messages() == [] PROVIDER_ENV_VARS = [ "PROMPTHEUS_PROVIDER", "GEMINI_API_KEY", "GOOGLE_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GROQ_API_KEY", "DASHSCOPE_API_KEY", "ZHIPUAI_API_KEY", ] def clear_provider_envs(monkeypatch): for key in PROVIDER_ENV_VARS: monkeypatch.delenv(key, raising=False) def test_provider_property_auto_detection(monkeypatch, config): """Test provider auto-detection based on environment variables.""" clear_provider_envs(monkeypatch) monkeypatch.setenv("GEMINI_API_KEY", "AIza-test-key") # Reset config to trigger auto-detection config.reset() provider = config.provider assert provider == "google" def test_provider_property_multiple_env_vars(monkeypatch, config): """Test provider auto-detection with multiple API keys.""" clear_provider_envs(monkeypatch) monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-test-key") monkeypatch.setenv("GEMINI_API_KEY", "AIza-test-key") # Reset config to trigger auto-detection config.reset() provider = config.provider # Anthropic should be detected first based on priority order assert provider in ["anthropic", "google"] def test_set_provider_valid(config): """Test setting a valid provider.""" config.set_provider("google") assert config._provider == "google" def test_set_provider_invalid(config): """Test setting an invalid provider.""" with pytest.raises(ValueError, match="Unknown provider: invalid_provider"): config.set_provider("invalid_provider") def test_set_provider_unsupported(monkeypatch, config): """Test setting an unsupported provider.""" # Mock model config to include our provider but mark as unsupported original_load = config.load_provider_config def mock_load_config(): config_data = original_load() config_data["providers"]["unsupported"] = { "default_model": "test-model", "models": ["test-model"], "api_key_env": "UNSUPPORTED_API_KEY" } return config_data monkeypatch.setattr(config, 'load_provider_config', mock_load_config) with pytest.raises(ValueError, match="not supported yet"): config.set_provider("unsupported") def test_set_model(config): """Test setting a model.""" config.set_model("test-model") assert config.model == "test-model" def test_get_model_default(config, monkeypatch): """Test getting model with default fallback.""" # Ensure no environment variable is set monkeypatch.delenv("PROMPTHEUS_MODEL", raising=False) model = config.get_model() # Should return default model for default provider (Google) assert isinstance(model, str) assert len(model) > 0 def test_get_model_from_env(monkeypatch, config): """Test getting model from environment variable.""" monkeypatch.setenv("PROMPTHEUS_PROVIDER", "google") monkeypatch.delenv("GOOGLE_MODEL", raising=False) monkeypatch.setenv("PROMPTHEUS_MODEL", "env-model") model = config.get_model() assert model == "env-model" def test_manual_provider_ignores_global_model(monkeypatch, config): """Manual provider changes should use provider defaults unless overridden explicitly.""" monkeypatch.setenv("PROMPTHEUS_MODEL", "env-model") config.set_provider("anthropic") provider_default = config._ensure_provider_config()["providers"]["anthropic"]["default_model"] assert config.get_model() == provider_default def test_get_provider_config_google(monkeypatch, config): """Test getting provider configuration for Google.""" monkeypatch.setenv("GEMINI_API_KEY", "AIza-test-key") config.set_provider("google") provider_config = config.get_provider_config() assert provider_config["api_key"] == "AIza-test-key" assert isinstance(provider_config, dict) def test_get_provider_config_openai(monkeypatch, config): """Test getting provider configuration for OpenAI.""" monkeypatch.setenv("OPENAI_API_KEY", "sk-test-key") config.set_provider("openai") provider_config = config.get_provider_config() assert provider_config["api_key"] == "sk-test-key" assert isinstance(provider_config, dict) def test_get_configured_providers(monkeypatch, config): """Test getting list of configured providers.""" monkeypatch.setenv("GEMINI_API_KEY", "AIza-test-key") monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-test-key") configured = config.get_configured_providers() assert "google" in configured assert "anthropic" in configured def test_validate_no_api_key(): """Validation should fail loudly when the API key is missing.""" # Save original os.getenv original_getenv = os.getenv # Define a custom getenv that returns None for API keys def mock_getenv(key, default=None): api_keys = ["GEMINI_API_KEY", "GOOGLE_API_KEY", "ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GROQ_API_KEY", "DASHSCOPE_API_KEY", "ZHIPUAI_API_KEY"] if key in api_keys: return None return original_getenv(key, default) # Patch os.getenv in the config module where it's actually used with patch('promptheus.config.os.getenv', side_effect=mock_getenv): # Create a fresh config instance with mocked getenv config = Config() config.set_provider("google") # Set a provider to validate is_valid = config.validate() assert not is_valid error_messages = config.consume_error_messages() assert any("No API key" in msg or "To use Gemini" in msg for msg in error_messages) def test_validate_with_api_key(monkeypatch, config): """Test validation with valid API key.""" monkeypatch.setenv("GEMINI_API_KEY", "AIza-valid-key") config.set_provider("google") is_valid = config.validate() assert is_valid def test_validate_invalid_api_key_format(monkeypatch, config): """Test validation with invalid API key format.""" monkeypatch.setenv("GEMINI_API_KEY", "invalid-key-format") config.set_provider("google") is_valid = config.validate() assert not is_valid error_messages = config.consume_error_messages() assert any("doesn't look quite right" in msg for msg in error_messages) def test_validate_valid_anthropic_key_format(monkeypatch, config): """Test validation with valid Anthropic API key format.""" monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-ant-test-key") config.set_provider("anthropic") is_valid = config.validate() assert is_valid def test_validate_custom_endpoint_skips_format_check(monkeypatch, config): """Test that custom endpoints skip format validation.""" monkeypatch.setenv("ANTHROPIC_API_KEY", "invalid-format-key") monkeypatch.setenv("ANTHROPIC_BASE_URL", "https://custom.example.com") config.set_provider("anthropic") is_valid = config.validate() # Should be valid despite invalid format because of custom endpoint assert is_valid def test_prometheus_provider_env_var(monkeypatch, config): """Test provider detection from PROMPTHEUS_PROVIDER environment variable.""" monkeypatch.setenv("PROMPTHEUS_PROVIDER", "openai") monkeypatch.setenv("OPENAI_API_KEY", "sk-test-key") # Reset config to trigger detection config.reset() provider = config.provider assert provider == "openai" def test_prometheus_provider_env_var_unknown(monkeypatch): """Test unknown provider in PROMPTHEUS_PROVIDER environment variable.""" monkeypatch.delenv("PROMPTHEUS_PROVIDER", raising=False) monkeypatch.setenv("PROMPTHEUS_PROVIDER", "unknown_provider") config = Config() config.reset() # Force re-evaluation of environment variables # Access the provider property to trigger validation _ = config.provider # Get the error messages - they should contain the unknown provider message error_messages = config.consume_error_messages() assert any("Unknown provider" in msg and "unknown_provider" in msg for msg in error_messages) def test_load_dotenv_functionality(temp_env_file, monkeypatch): """Test the find_and_load_dotenv function.""" # Temporarily change to the directory containing the temp file original_cwd = os.getcwd() temp_dir = temp_env_file.parent try: os.chdir(temp_dir) # Remove any existing env vars that might interfere for key in ["GEMINI_API_KEY", "OPENAI_API_KEY"]: monkeypatch.delenv(key, raising=False) # Call the function result = find_and_load_dotenv(temp_env_file.name) # Verify it loaded the file assert result is not None assert result.name == temp_env_file.name # Verify environment variables were loaded assert os.getenv("GEMINI_API_KEY") == "AIza-test-key-from-env" assert os.getenv("OPENAI_API_KEY") == "sk-test-openai-key" finally: os.chdir(original_cwd) def test_is_project_root_with_git_marker(tmp_path): """Test _is_project_root with .git marker.""" git_dir = tmp_path / ".git" git_dir.mkdir() assert _is_project_root(tmp_path) def test_is_project_root_with_pyproject_marker(tmp_path): """Test _is_project_root with pyproject.toml marker.""" (tmp_path / "pyproject.toml").touch() assert _is_project_root(tmp_path) def test_is_project_root_with_setup_marker(tmp_path): """Test _is_project_root with setup.py marker.""" (tmp_path / "setup.py").touch() assert _is_project_root(tmp_path) def test_is_project_root_not_project(tmp_path): """Test _is_project_root with no markers.""" assert not _is_project_root(tmp_path)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/abhichandra21/Promptheus'

If you have feedback or need assistance with the MCP directory API, please join our Discord server