from pathlib import Path import pytest from pydantic import ValidationError from app import config as config_module from app.config import Settings, get_settings PROJECT_ROOT = Path(__file__).resolve().parents[2] TEST_CONFIG_FILE = PROJECT_ROOT / "config.test.yaml" MISSING_REQUIRED_SECTION_CONFIG_FILE = ( PROJECT_ROOT / "tests" / "config" / "fixtures" / "config.missing_adapter.yaml" ) DEFAULT_CONFIG_FILE_FIXTURE = ( PROJECT_ROOT / "tests" / "config" / "fixtures" / "config.default.yaml" ) TEST_OVERRIDE_CONFIG_FILE_FIXTURE = ( PROJECT_ROOT / "tests" / "config" / "fixtures" / "config.test.override.yaml" ) def _use_runtime_config_files( monkeypatch: pytest.MonkeyPatch, *, test_config_file: Path, default_config_file: Path | None = None, ) -> None: monkeypatch.setattr(config_module, "TEST_CONFIG_FILE", str(test_config_file)) if default_config_file is not None: monkeypatch.setattr( config_module, "DEFAULT_CONFIG_FILE", str(default_config_file), ) get_settings.cache_clear() def test_configuration_sections_are_loaded_from_yaml_file( monkeypatch: pytest.MonkeyPatch, ) -> None: _use_runtime_config_files(monkeypatch, test_config_file=TEST_CONFIG_FILE) settings = Settings() assert settings.controller.api_prefix == "/api/v1" assert settings.controller.request_id_header == "X-Request-ID" assert settings.service.provider_timeout_seconds == 10.0 assert settings.service.max_parallel_providers == 8 assert settings.business_logic.weight_round_scale == 2 assert settings.repository.redis_dsn == "redis://localhost:6379/0" assert settings.repository.price_cache_ttl_seconds == 900 assert settings.adapter.cdek_base_url == "https://api.cdek.ru/v2" assert settings.adapter.cdek_client_id == "test-client-id" assert settings.adapter.cdek_client_secret == "test-client-secret" assert settings.adapter.cdek_retry_attempts == 2 assert settings.adapter.cdek_retry_backoff_seconds == 0.2 assert settings.adapter.cdek_timeout_seconds == 10.0 assert settings.adapter.cdek_cache_ttl_seconds == 900 def test_get_settings_fails_when_required_yaml_section_is_missing( monkeypatch: pytest.MonkeyPatch, ) -> None: _use_runtime_config_files( monkeypatch, test_config_file=MISSING_REQUIRED_SECTION_CONFIG_FILE, ) with pytest.raises(ValidationError) as error: get_settings() locations = {tuple(item["loc"]) for item in error.value.errors()} assert ("adapter",) in locations get_settings.cache_clear() def test_get_settings_returns_cached_instance(monkeypatch: pytest.MonkeyPatch) -> None: _use_runtime_config_files(monkeypatch, test_config_file=TEST_CONFIG_FILE) first = get_settings() second = get_settings() assert first is second assert first.service.provider_timeout_seconds == 10.0 get_settings.cache_clear() def test_get_settings_uses_config_test_yaml_in_pytest_environment( monkeypatch: pytest.MonkeyPatch, ) -> None: _use_runtime_config_files( monkeypatch, test_config_file=TEST_OVERRIDE_CONFIG_FILE_FIXTURE, default_config_file=DEFAULT_CONFIG_FILE_FIXTURE, ) settings = get_settings() assert settings.service.provider_timeout_seconds == 17.0 assert settings.controller.api_prefix == "/from-config-test-yaml" assert settings.adapter.cdek_client_id == "test-id" get_settings.cache_clear()