Spaces:
Paused
Paused
| """ | |
| Tests for gui/env_manager.py - Environment file management | |
| """ | |
| import os | |
| import tempfile | |
| from pathlib import Path | |
| import pytest | |
| from gui.env_manager import EnvManager, get_env_manager, reset_env_manager | |
| def temp_env_file(): | |
| """Create a temporary .env file for testing.""" | |
| with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f: | |
| f.write("""# Test configuration | |
| PORT=2048 | |
| STREAM_PORT=3120 | |
| DEBUG_LOGS_ENABLED=true | |
| DEFAULT_TEMPERATURE=1.0 | |
| SERVER_LOG_LEVEL=INFO | |
| FUNCTION_CALLING_MODE=auto | |
| """) | |
| f.flush() | |
| yield Path(f.name) | |
| os.unlink(f.name) | |
| def temp_example_file(): | |
| """Create a temporary .env.example file for testing.""" | |
| with tempfile.NamedTemporaryFile( | |
| mode="w", suffix=".env.example", delete=False | |
| ) as f: | |
| f.write("""# Example configuration | |
| PORT=2048 | |
| STREAM_PORT=3120 | |
| """) | |
| f.flush() | |
| yield Path(f.name) | |
| os.unlink(f.name) | |
| def env_manager(temp_env_file, temp_example_file): | |
| """Create an EnvManager instance for testing.""" | |
| reset_env_manager() | |
| return EnvManager(temp_env_file, temp_example_file) | |
| class TestEnvManagerInit: | |
| """Tests for EnvManager initialization.""" | |
| def test_loads_existing_file(self, env_manager): | |
| """Test that EnvManager loads existing .env file.""" | |
| assert env_manager.get("PORT") == 2048 | |
| def test_creates_from_example_if_missing(self, temp_example_file): | |
| """Test creating .env from .env.example if missing.""" | |
| reset_env_manager() | |
| missing_path = Path(tempfile.gettempdir()) / "nonexistent_test.env" | |
| if missing_path.exists(): | |
| missing_path.unlink() | |
| manager = EnvManager(missing_path, temp_example_file) | |
| assert missing_path.exists() | |
| assert manager.get("PORT") == 2048 | |
| missing_path.unlink() | |
| class TestEnvManagerGet: | |
| """Tests for EnvManager.get() method.""" | |
| def test_get_int_value(self, env_manager): | |
| """Test getting integer values.""" | |
| assert env_manager.get("PORT") == 2048 | |
| assert isinstance(env_manager.get("PORT"), int) | |
| def test_get_bool_value(self, env_manager): | |
| """Test getting boolean values.""" | |
| assert env_manager.get("DEBUG_LOGS_ENABLED") is True | |
| assert isinstance(env_manager.get("DEBUG_LOGS_ENABLED"), bool) | |
| def test_get_float_value(self, env_manager): | |
| """Test getting float values.""" | |
| assert env_manager.get("DEFAULT_TEMPERATURE") == 1.0 | |
| assert isinstance(env_manager.get("DEFAULT_TEMPERATURE"), float) | |
| def test_get_string_value(self, env_manager): | |
| """Test getting string values.""" | |
| assert env_manager.get("SERVER_LOG_LEVEL") == "INFO" | |
| assert isinstance(env_manager.get("SERVER_LOG_LEVEL"), str) | |
| def test_get_choice_value(self, env_manager): | |
| """Test getting choice values.""" | |
| assert env_manager.get("FUNCTION_CALLING_MODE") == "auto" | |
| def test_get_missing_returns_default(self, env_manager): | |
| """Test that missing keys return schema default.""" | |
| # QUOTA_SOFT_LIMIT is in schema but not in our test file | |
| assert env_manager.get("QUOTA_SOFT_LIMIT") == 850000 | |
| def test_get_raw_value(self, env_manager): | |
| """Test getting raw string value.""" | |
| raw = env_manager.get_raw("DEBUG_LOGS_ENABLED") | |
| assert raw == "true" | |
| assert isinstance(raw, str) | |
| class TestEnvManagerSet: | |
| """Tests for EnvManager.set() method.""" | |
| def test_set_int_value(self, env_manager): | |
| """Test setting integer values.""" | |
| env_manager.set("PORT", 3000) | |
| assert env_manager.get("PORT") == 3000 | |
| def test_set_bool_value(self, env_manager): | |
| """Test setting boolean values.""" | |
| env_manager.set("DEBUG_LOGS_ENABLED", False) | |
| assert env_manager.get("DEBUG_LOGS_ENABLED") is False | |
| def test_set_float_value(self, env_manager): | |
| """Test setting float values.""" | |
| env_manager.set("DEFAULT_TEMPERATURE", 0.7) | |
| assert env_manager.get("DEFAULT_TEMPERATURE") == 0.7 | |
| class TestEnvManagerDirtyState: | |
| """Tests for dirty state tracking.""" | |
| def test_initially_not_dirty(self, env_manager): | |
| """Test that newly loaded manager is not dirty.""" | |
| assert env_manager.is_dirty() is False | |
| def test_dirty_after_set(self, env_manager): | |
| """Test that manager becomes dirty after setting a value.""" | |
| env_manager.set("PORT", 9999) | |
| assert env_manager.is_dirty() is True | |
| def test_get_modified_keys(self, env_manager): | |
| """Test getting list of modified keys.""" | |
| env_manager.set("PORT", 9999) | |
| env_manager.set("STREAM_PORT", 8888) | |
| modified = env_manager.get_modified_keys() | |
| assert "PORT" in modified | |
| assert "STREAM_PORT" in modified | |
| class TestEnvManagerSave: | |
| """Tests for saving .env file.""" | |
| def test_save_writes_file(self, env_manager, temp_env_file): | |
| """Test that save writes to file.""" | |
| env_manager.set("PORT", 5000) | |
| assert env_manager.save() is True | |
| # Re-read the file | |
| with open(temp_env_file) as f: | |
| content = f.read() | |
| assert "PORT=5000" in content | |
| def test_save_clears_dirty_state(self, env_manager): | |
| """Test that save clears dirty state.""" | |
| env_manager.set("PORT", 5000) | |
| assert env_manager.is_dirty() is True | |
| env_manager.save() | |
| assert env_manager.is_dirty() is False | |
| class TestEnvManagerCategories: | |
| """Tests for category handling.""" | |
| def test_get_category_keys(self, env_manager): | |
| """Test getting keys by category.""" | |
| server_keys = env_manager.get_category_keys("server") | |
| assert "PORT" in server_keys | |
| assert "STREAM_PORT" in server_keys | |
| def test_get_schema_info(self, env_manager): | |
| """Test getting schema info for a key.""" | |
| info = env_manager.get_schema_info("PORT") | |
| assert info is not None | |
| default, type_hint, description, category = info | |
| assert default == 2048 | |
| assert type_hint == "int" | |
| assert category == "server" | |
| def test_categories_dict_exists(self, env_manager): | |
| """Test that CATEGORIES dict is defined.""" | |
| assert len(EnvManager.CATEGORIES) > 0 | |
| assert "server" in EnvManager.CATEGORIES | |
| assert "logging" in EnvManager.CATEGORIES | |
| class TestEnvManagerHotReload: | |
| """Tests for hot reload functionality.""" | |
| def test_register_callback(self, env_manager): | |
| """Test registering hot reload callback.""" | |
| callback_called = [] | |
| def callback(modified): | |
| callback_called.append(modified) | |
| env_manager.register_hot_reload_callback(callback) | |
| env_manager.set("PORT", 9999) | |
| env_manager.trigger_hot_reload() | |
| assert len(callback_called) == 1 | |
| assert "PORT" in callback_called[0] | |
| def test_unregister_callback(self, env_manager): | |
| """Test unregistering hot reload callback.""" | |
| callback_called = [] | |
| def callback(modified): | |
| callback_called.append(modified) | |
| env_manager.register_hot_reload_callback(callback) | |
| env_manager.unregister_hot_reload_callback(callback) | |
| env_manager.set("PORT", 9999) | |
| env_manager.trigger_hot_reload() | |
| assert len(callback_called) == 0 | |
| def test_apply_to_environment(self, env_manager): | |
| """Test applying settings to os.environ.""" | |
| env_manager.set("PORT", 7777) | |
| env_manager.apply_to_environment() | |
| assert os.environ.get("PORT") == "7777" | |
| class TestEnvManagerReset: | |
| """Tests for reset functionality.""" | |
| def test_reset_to_defaults(self, env_manager): | |
| """Test resetting all values to defaults.""" | |
| env_manager.set("PORT", 9999) | |
| env_manager.reset_to_defaults() | |
| assert env_manager.get("PORT") == 2048 | |
| def test_discard_changes(self, env_manager): | |
| """Test discarding unsaved changes.""" | |
| original = env_manager.get("PORT") | |
| env_manager.set("PORT", 9999) | |
| env_manager.discard_changes() | |
| assert env_manager.get("PORT") == original | |
| class TestGetEnvManagerSingleton: | |
| """Tests for singleton pattern.""" | |
| def test_singleton_returns_same_instance(self, temp_env_file, temp_example_file): | |
| """Test that get_env_manager returns singleton.""" | |
| reset_env_manager() | |
| manager1 = get_env_manager(temp_env_file, temp_example_file) | |
| manager2 = get_env_manager() | |
| assert manager1 is manager2 | |
| def test_reset_clears_singleton(self, temp_env_file, temp_example_file): | |
| """Test that reset_env_manager clears singleton.""" | |
| reset_env_manager() | |
| manager1 = get_env_manager(temp_env_file, temp_example_file) | |
| reset_env_manager() | |
| manager2 = get_env_manager(temp_env_file, temp_example_file) | |
| assert manager1 is not manager2 | |