"""Test suite for the environment settings system.""" import os from pathlib import Path import pytest from local_deep_research.settings.env_registry import ( registry, get_env_setting, is_test_mode, is_ci_environment, ) from local_deep_research.settings.manager import SettingsManager class TestEnvRegistry: """Test the environment registry functionality.""" @pytest.fixture(autouse=True) def clean_env(self): """Clean environment before each test.""" # Store original env vars original_env = { k: v for k, v in os.environ.items() if k.startswith("LDR_") or k in ["CI", "TESTING"] } # Clean env vars for key in list(os.environ.keys()): if key.startswith("LDR_") or key in ["CI", "TESTING"]: os.environ.pop(key, None) yield # Restore original env vars for key in list(os.environ.keys()): if key.startswith("LDR_") or key in ["CI", "TESTING"]: os.environ.pop(key, None) for key, value in original_env.items(): os.environ[key] = value def test_registry_has_settings(self): """Test that registry has settings registered.""" all_settings = registry.list_all_settings() assert len(all_settings) > 0, "Registry should have settings" assert "testing.test_mode" in all_settings assert "bootstrap.encryption_key" in all_settings assert "db_config.cache_size_mb" in all_settings def test_categories(self): """Test that all categories have settings.""" categories = ["testing", "bootstrap", "db_config"] for cat in categories: settings = registry.get_category_settings(cat) assert len(settings) > 0, f"Category '{cat}' should have settings" def test_boolean_setting(self): """Test boolean setting conversion.""" # Test various true values for value in [ "true", "True", "TRUE", "1", "yes", "YES", "on", "enabled", ]: os.environ["LDR_TESTING_TEST_MODE"] = value assert is_test_mode(), f"'{value}' should be True" # Test various false values for value in ["false", "False", "FALSE", "0", "no", "NO", "off", ""]: os.environ["LDR_TESTING_TEST_MODE"] = value assert not is_test_mode(), f"'{value}' should be False" def test_ci_environment(self): """Test CI environment detection.""" assert not is_ci_environment() os.environ["CI"] = "true" assert is_ci_environment() os.environ["CI"] = "false" assert not is_ci_environment() def test_integer_setting(self): """Test integer setting conversion and validation.""" os.environ["LDR_DB_CONFIG_CACHE_SIZE_MB"] = "512" cache_size = get_env_setting("db_config.cache_size_mb") assert cache_size == 512 # Test invalid integer returns setting's registered default os.environ["LDR_DB_CONFIG_CACHE_SIZE_MB"] = "invalid" cache_size = get_env_setting("db_config.cache_size_mb", 100) assert cache_size == 64 # Test when not set uses default from setting definition os.environ.pop("LDR_DB_CONFIG_CACHE_SIZE_MB", None) cache_size = get_env_setting("db_config.cache_size_mb") assert cache_size == 64 # Default from db_config.py def test_enum_setting(self): """Test enum setting with case-insensitive matching.""" # Test lowercase input returns canonical form os.environ["LDR_DB_CONFIG_JOURNAL_MODE"] = "wal" journal_mode = get_env_setting("db_config.journal_mode") assert journal_mode == "WAL" os.environ["LDR_DB_CONFIG_JOURNAL_MODE"] = "TRUNCATE" journal_mode = get_env_setting("db_config.journal_mode") assert journal_mode == "TRUNCATE" # Test default when not set os.environ.pop("LDR_DB_CONFIG_JOURNAL_MODE", None) journal_mode = get_env_setting("db_config.journal_mode") assert journal_mode == "WAL" # Default value def test_path_setting(self): """Test path setting expansion.""" test_path = "/tmp/test_ldr_path" os.environ["LDR_BOOTSTRAP_DATA_DIR"] = test_path data_dir = get_env_setting("bootstrap.data_dir") assert data_dir == test_path # Test home expansion os.environ["LDR_BOOTSTRAP_DATA_DIR"] = "~/test_path" data_dir = get_env_setting("bootstrap.data_dir") assert data_dir.startswith(str(Path.home())) assert "test_path" in data_dir def test_secret_setting(self): """Test secret setting hides values.""" os.environ["LDR_BOOTSTRAP_ENCRYPTION_KEY"] = "secret_key_123" setting_obj = registry.get_setting_object("bootstrap.encryption_key") # Value should be hidden in string representation assert "secret_key_123" not in str(setting_obj) assert "SET" in str(setting_obj) # But value should still be retrievable value = get_env_setting("bootstrap.encryption_key") assert value == "secret_key_123" class TestSettingsManagerIntegration: """Test SettingsManager integration with env settings.""" @pytest.fixture(autouse=True) def clean_env(self): """Clean environment before each test.""" original_env = { k: v for k, v in os.environ.items() if k.startswith("LDR_") } for key in list(os.environ.keys()): if key.startswith("LDR_"): os.environ.pop(key, None) yield for key in list(os.environ.keys()): if key.startswith("LDR_"): os.environ.pop(key, None) for key, value in original_env.items(): os.environ[key] = value def test_get_env_only_setting(self): """Test getting env-only settings through SettingsManager.""" sm = SettingsManager(db_session=None) os.environ["LDR_TESTING_TEST_MODE"] = "true" test_mode = sm.get_setting("testing.test_mode") assert test_mode def test_is_env_only_setting(self): """Test checking if a setting is env-only.""" sm = SettingsManager(db_session=None) # These should be env-only assert sm.is_env_only_setting("testing.test_mode") assert sm.is_env_only_setting("bootstrap.encryption_key") assert sm.is_env_only_setting("db_config.cache_size_mb") # These should NOT be env-only (regular settings) assert not sm.is_env_only_setting("app.debug") assert not sm.is_env_only_setting("llm.provider") assert not sm.is_env_only_setting("search.max_concurrent") def test_get_bootstrap_vars(self): """Test getting bootstrap environment variables.""" sm = SettingsManager(db_session=None) bootstrap_vars = sm.get_bootstrap_env_vars() # Should include bootstrap settings assert "LDR_BOOTSTRAP_ENCRYPTION_KEY" in bootstrap_vars assert "LDR_BOOTSTRAP_DATA_DIR" in bootstrap_vars assert "LDR_BOOTSTRAP_CONFIG_DIR" in bootstrap_vars # Should include db_config settings assert "LDR_DB_CONFIG_CACHE_SIZE_MB" in bootstrap_vars assert "LDR_DB_CONFIG_JOURNAL_MODE" in bootstrap_vars # Should have a reasonable number of vars assert len(bootstrap_vars) >= 10 def test_is_bootstrap_env_var(self): """Test checking if an env var is a bootstrap variable.""" sm = SettingsManager(db_session=None) # Bootstrap vars assert sm.is_bootstrap_env_var("LDR_BOOTSTRAP_ENCRYPTION_KEY") assert sm.is_bootstrap_env_var("LDR_DB_CONFIG_PAGE_SIZE") assert sm.is_bootstrap_env_var("LDR_BOOTSTRAP_DATA_DIR") # Testing vars are in ALL_ENV_ONLY_VARS but not specifically bootstrap # They are allowed by the pre-commit hook but not considered bootstrap vars assert not sm.is_bootstrap_env_var("LDR_TESTING_TEST_MODE") # Non-existent var assert not sm.is_bootstrap_env_var("RANDOM_VAR") assert not sm.is_bootstrap_env_var("SOME_OTHER_VAR") class TestEnvVarMapping: """Test environment variable name mapping.""" def test_get_env_var_for_setting(self): """Test getting env var name for a setting.""" assert ( registry.get_env_var("testing.test_mode") == "LDR_TESTING_TEST_MODE" ) assert ( registry.get_env_var("bootstrap.encryption_key") == "LDR_BOOTSTRAP_ENCRYPTION_KEY" ) assert ( registry.get_env_var("db_config.cache_size_mb") == "LDR_DB_CONFIG_CACHE_SIZE_MB" ) assert registry.get_env_var("nonexistent.setting") is None def test_get_all_env_vars(self): """Test getting all environment variables.""" all_env_vars = registry.get_all_env_vars() # Should have a reasonable number assert len(all_env_vars) >= 15 # Should include key variables assert "LDR_TESTING_TEST_MODE" in all_env_vars assert "LDR_BOOTSTRAP_ENCRYPTION_KEY" in all_env_vars # CI and TESTING are external vars, not in registry anymore def test_category_specific_vars(self): """Test getting category-specific environment variables.""" # Testing vars testing_vars = registry.get_testing_vars() assert len(testing_vars) >= 1 assert "LDR_TESTING_TEST_MODE" in testing_vars # Bootstrap vars (includes db_config) bootstrap_vars = registry.get_bootstrap_vars() assert len(bootstrap_vars) >= 10 assert "LDR_BOOTSTRAP_ENCRYPTION_KEY" in bootstrap_vars assert "LDR_BOOTSTRAP_DATA_DIR" in bootstrap_vars assert "LDR_DB_CONFIG_CACHE_SIZE_MB" in bootstrap_vars assert "LDR_DB_CONFIG_JOURNAL_MODE" in bootstrap_vars def test_is_env_only(self): """Test checking if a setting is env-only.""" # These should be env-only assert registry.is_env_only("testing.test_mode") assert registry.is_env_only("bootstrap.encryption_key") assert registry.is_env_only("db_config.cache_size_mb") # These should not exist in env registry assert not registry.is_env_only("app.debug") assert not registry.is_env_only("nonexistent.setting")