"""Tests for backend/config.py.""" import os from unittest.mock import patch import pytest from pydantic_settings import BaseSettings from config import Settings class TestSettings: """Test the Settings configuration class.""" def _make_settings(self, **env_vars: str) -> Settings: """Create a Settings instance with specific env vars, ignoring .env file.""" with patch.dict(os.environ, env_vars, clear=False): return Settings(_env_file=None) def test_defaults(self) -> None: s = self._make_settings() assert s.database_url is None assert s.redis_url is None assert s.host == "0.0.0.0" assert s.port == 8400 assert s.api_key is None assert s.default_endpoint_url is None assert s.default_endpoint_key is None assert s.max_concurrent_runs == 4 assert s.max_tokens_per_sweep == 0 assert s.data_dir == "/data" assert s.mcp_enabled is True assert s.mcp_port == 8401 def test_jwt_secret_auto_generated(self) -> None: s = self._make_settings() assert len(s.jwt_secret) > 0 def test_jwt_secret_auto_generated_unique(self) -> None: s1 = self._make_settings() s2 = self._make_settings() assert s1.jwt_secret != s2.jwt_secret def test_jwt_secret_from_env(self) -> None: s = self._make_settings(JWT_SECRET="my-secret-key") assert s.jwt_secret == "my-secret-key" def test_sqlite_fallback_when_no_database_url(self) -> None: s = self._make_settings(DATA_DIR="/tmp/test") url = s.effective_database_url assert url.startswith("sqlite:///") assert url.endswith("promptlooper.db") assert "tmp" in url and "test" in url assert s.is_sqlite is True def test_postgres_when_database_url_set(self) -> None: url = "postgresql://user:pass@localhost:5432/promptlooper" s = self._make_settings(DATABASE_URL=url) assert s.effective_database_url == url assert s.is_sqlite is False def test_in_process_queue_when_no_redis(self) -> None: s = self._make_settings() assert s.use_in_process_queue is True def test_celery_queue_when_redis_set(self) -> None: s = self._make_settings(REDIS_URL="redis://localhost:6379/0") assert s.use_in_process_queue is False assert s.redis_url == "redis://localhost:6379/0" def test_empty_api_key_becomes_none(self) -> None: s = self._make_settings(API_KEY="") assert s.api_key is None def test_whitespace_api_key_becomes_none(self) -> None: s = self._make_settings(API_KEY=" ") assert s.api_key is None def test_valid_api_key_preserved(self) -> None: s = self._make_settings(API_KEY="sk-test-123") assert s.api_key == "sk-test-123" def test_env_overrides(self) -> None: s = self._make_settings( HOST="127.0.0.1", PORT="9000", MAX_CONCURRENT_RUNS="8", MAX_TOKENS_PER_SWEEP="100000", MCP_ENABLED="false", MCP_PORT="9001", ) assert s.host == "127.0.0.1" assert s.port == 9000 assert s.max_concurrent_runs == 8 assert s.max_tokens_per_sweep == 100000 assert s.mcp_enabled is False assert s.mcp_port == 9001 def test_default_endpoint_config(self) -> None: s = self._make_settings( DEFAULT_ENDPOINT_URL="http://localhost:11434/v1", DEFAULT_ENDPOINT_KEY="sk-key", ) assert s.default_endpoint_url == "http://localhost:11434/v1" assert s.default_endpoint_key == "sk-key"