| """Tests for configuration management module. |
| |
| Requirements: 10.1, 10.2, 10.3, 10.4, 10.5 |
| """ |
|
|
| import os |
| import pytest |
| from pathlib import Path |
| from unittest.mock import patch |
|
|
| from app.config import Config, load_config, validate_config, init_config |
|
|
|
|
| class TestConfig: |
| """Test configuration loading and validation.""" |
| |
| def test_config_with_all_fields(self): |
| """Test creating config with all fields specified.""" |
| config = Config( |
| zhipu_api_key="test_api_key_1234567890", |
| data_dir=Path("test_data"), |
| max_audio_size=5 * 1024 * 1024, |
| log_level="DEBUG", |
| log_file=Path("test_logs/test.log"), |
| host="127.0.0.1", |
| port=9000 |
| ) |
| |
| assert config.zhipu_api_key == "test_api_key_1234567890" |
| assert config.data_dir == Path("test_data") |
| assert config.max_audio_size == 5 * 1024 * 1024 |
| assert config.log_level == "DEBUG" |
| assert config.log_file == Path("test_logs/test.log") |
| assert config.host == "127.0.0.1" |
| assert config.port == 9000 |
| |
| def test_config_with_defaults(self): |
| """Test creating config with default values.""" |
| config = Config(zhipu_api_key="test_api_key_1234567890") |
| |
| assert config.zhipu_api_key == "test_api_key_1234567890" |
| assert config.data_dir == Path("data") |
| assert config.max_audio_size == 10 * 1024 * 1024 |
| assert config.log_level == "INFO" |
| assert config.log_file == Path("logs/app.log") |
| assert config.host == "0.0.0.0" |
| assert config.port == 8000 |
| |
| def test_config_missing_api_key(self): |
| """Test that missing API key raises validation error.""" |
| with pytest.raises(Exception): |
| Config() |
| |
| def test_config_invalid_log_level(self): |
| """Test that invalid log level raises validation error.""" |
| with pytest.raises(ValueError, match="log_level must be one of"): |
| Config( |
| zhipu_api_key="test_api_key_1234567890", |
| log_level="INVALID" |
| ) |
| |
| def test_config_invalid_max_audio_size(self): |
| """Test that invalid max audio size raises validation error.""" |
| with pytest.raises(ValueError, match="max_audio_size must be positive"): |
| Config( |
| zhipu_api_key="test_api_key_1234567890", |
| max_audio_size=-1 |
| ) |
| |
| def test_config_log_level_case_insensitive(self): |
| """Test that log level is case insensitive.""" |
| config = Config( |
| zhipu_api_key="test_api_key_1234567890", |
| log_level="debug" |
| ) |
| assert config.log_level == "DEBUG" |
| |
| def test_config_immutable(self): |
| """Test that config is immutable (frozen).""" |
| config = Config(zhipu_api_key="test_api_key_1234567890") |
| |
| with pytest.raises(Exception): |
| config.zhipu_api_key = "new_key" |
|
|
|
|
| class TestLoadConfig: |
| """Test loading configuration from environment variables.""" |
| |
| @patch.dict(os.environ, { |
| "ZHIPU_API_KEY": "test_key_1234567890", |
| "DATA_DIR": "custom_data", |
| "MAX_AUDIO_SIZE": "5242880", |
| "LOG_LEVEL": "DEBUG", |
| "LOG_FILE": "custom_logs/app.log", |
| "HOST": "127.0.0.1", |
| "PORT": "9000" |
| }) |
| def test_load_config_from_env(self, tmp_path): |
| """Test loading config from environment variables.""" |
| |
| data_dir = tmp_path / "custom_data" |
| data_dir.mkdir() |
| log_dir = tmp_path / "custom_logs" |
| log_dir.mkdir() |
| |
| with patch.dict(os.environ, { |
| "DATA_DIR": str(data_dir), |
| "LOG_FILE": str(log_dir / "app.log") |
| }, clear=False): |
| config = load_config() |
| |
| assert config.zhipu_api_key == "test_key_1234567890" |
| assert config.data_dir == data_dir |
| assert config.max_audio_size == 5242880 |
| assert config.log_level == "DEBUG" |
| assert config.log_file == log_dir / "app.log" |
| assert config.host == "127.0.0.1" |
| assert config.port == 9000 |
| |
| @patch.dict(os.environ, {"ZHIPU_API_KEY": "test_key_1234567890"}, clear=True) |
| def test_load_config_with_defaults(self, tmp_path): |
| """Test loading config with default values.""" |
| |
| with patch.dict(os.environ, {"DATA_DIR": str(tmp_path / "data")}, clear=False): |
| config = load_config() |
| |
| assert config.zhipu_api_key == "test_key_1234567890" |
| assert config.log_level == "INFO" |
| assert config.host == "0.0.0.0" |
| assert config.port == 8000 |
| |
| @patch.dict(os.environ, {}, clear=True) |
| def test_load_config_missing_api_key(self): |
| """Test that missing API key raises ValueError. |
| |
| Requirement 10.4: Missing required config should cause startup failure. |
| """ |
| with pytest.raises(ValueError, match="ZHIPU_API_KEY environment variable is required"): |
| load_config() |
| |
| @patch.dict(os.environ, { |
| "ZHIPU_API_KEY": "test_key_1234567890", |
| "MAX_AUDIO_SIZE": "invalid" |
| }, clear=True) |
| def test_load_config_invalid_integer(self): |
| """Test that invalid integer value raises ValueError.""" |
| with pytest.raises(ValueError): |
| load_config() |
|
|
|
|
| class TestValidateConfig: |
| """Test configuration validation at startup.""" |
| |
| def test_validate_config_success(self, tmp_path): |
| """Test successful config validation.""" |
| data_dir = tmp_path / "data" |
| data_dir.mkdir() |
| log_dir = tmp_path / "logs" |
| log_dir.mkdir() |
| |
| config = Config( |
| zhipu_api_key="test_key_1234567890", |
| data_dir=data_dir, |
| log_file=log_dir / "app.log" |
| ) |
| |
| |
| validate_config(config) |
| |
| def test_validate_config_data_dir_not_writable(self, tmp_path): |
| """Test validation fails if data directory is not writable. |
| |
| Note: This test is skipped on Windows as chmod doesn't work the same way. |
| """ |
| import platform |
| if platform.system() == "Windows": |
| pytest.skip("chmod doesn't work reliably on Windows") |
| |
| data_dir = tmp_path / "data" |
| data_dir.mkdir() |
| |
| |
| data_dir.chmod(0o444) |
| |
| config = Config( |
| zhipu_api_key="test_key_1234567890", |
| data_dir=data_dir |
| ) |
| |
| try: |
| with pytest.raises(ValueError, match="not writable"): |
| validate_config(config) |
| finally: |
| |
| data_dir.chmod(0o755) |
| |
| def test_validate_config_short_api_key(self, tmp_path): |
| """Test validation fails if API key is too short.""" |
| data_dir = tmp_path / "data" |
| data_dir.mkdir() |
| |
| config = Config( |
| zhipu_api_key="short", |
| data_dir=data_dir |
| ) |
| |
| with pytest.raises(ValueError, match="ZHIPU_API_KEY appears to be invalid"): |
| validate_config(config) |
|
|
|
|
| class TestInitConfig: |
| """Test global config initialization.""" |
| |
| @patch.dict(os.environ, {"ZHIPU_API_KEY": "test_key_1234567890"}, clear=True) |
| def test_init_config(self, tmp_path): |
| """Test initializing global config.""" |
| from app.config import _config, get_config |
| |
| |
| import app.config |
| app.config._config = None |
| |
| with patch.dict(os.environ, {"DATA_DIR": str(tmp_path / "data")}, clear=False): |
| config = init_config() |
| |
| assert config is not None |
| assert config.zhipu_api_key == "test_key_1234567890" |
| |
| |
| assert get_config() == config |
|
|