diff --git a/src/edge_proxy/settings.py b/src/edge_proxy/settings.py index 96be2c7..d4e2b90 100644 --- a/src/edge_proxy/settings.py +++ b/src/edge_proxy/settings.py @@ -8,17 +8,15 @@ import structlog -from pydantic import AliasChoices, BaseModel, HttpUrl, IPvAnyAddress, Field +from pydantic import AliasChoices, BaseModel, HttpUrl, IPvAnyAddress, Field, constr from pydantic_settings import BaseSettings, PydanticBaseSettingsSource - CONFIG_PATH = os.environ.get( "CONFIG_PATH", default="config.json", ) - logger = structlog.get_logger() @@ -65,8 +63,8 @@ def json_config_settings_source() -> dict[str, Any]: class EnvironmentKeyPair(BaseModel): - server_side_key: str - client_side_key: str + server_side_key: constr(pattern=r"ser\.*", strip_whitespace=True) + client_side_key: constr(min_length=1, strip_whitespace=True) class EndpointCacheSettings(BaseModel): @@ -105,14 +103,7 @@ class HealthCheckSettings(BaseModel): class AppSettings(BaseModel): - environment_key_pairs: list[EnvironmentKeyPair] = Field( - default_factory=lambda: [ - EnvironmentKeyPair( - server_side_key="ser.environment_key", - client_side_key="environment_key", - ) - ] - ) + environment_key_pairs: list[EnvironmentKeyPair] api_url: HttpUrl = HttpUrl("https://edge.api.flagsmith.com/api/v1") api_poll_frequency_seconds: int = Field( default=10, diff --git a/tests/conftest.py b/tests/conftest.py index 9a2df0f..1cf2cfd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -51,8 +51,15 @@ def environment_1_feature_states_response_list_response_with_identity_override( @pytest.fixture(autouse=True) -def skip_json_config_settings_source(mocker: MockerFixture) -> None: - mocker.patch("edge_proxy.settings.json_config_settings_source", dict) +def mock_settings(mocker: MockerFixture) -> None: + mock_config = { + "environment_key_pairs": [ + {"server_side_key": "ser.abc123", "client_side_key": "def456"} + ] + } + mocker.patch( + "edge_proxy.settings.json_config_settings_source", return_value=mock_config + ) @pytest.fixture diff --git a/tests/test_server.py b/tests/test_server.py index 3f5d19e..0a19985 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -6,7 +6,7 @@ from fastapi.testclient import TestClient from pytest_mock import MockerFixture -from edge_proxy.settings import AppSettings, HealthCheckSettings +from edge_proxy.settings import HealthCheckSettings from tests.fixtures.response_data import environment_1 if typing.TYPE_CHECKING: @@ -59,10 +59,8 @@ def test_health_check_returns_200_if_cache_is_stale_and_health_check_configured_ client: TestClient, ) -> None: # Given - settings = AppSettings( - health_check=HealthCheckSettings(environment_update_grace_period_seconds=None) - ) - mocker.patch("edge_proxy.server.settings", settings) + health_check = HealthCheckSettings(environment_update_grace_period_seconds=None) + mocker.patch("edge_proxy.server.settings.health_check", health_check) last_updated_at = datetime.now() - timedelta(days=10) mocked_environment_service = mocker.patch("edge_proxy.server.environment_service") diff --git a/tests/test_settings.py b/tests/test_settings.py index d649002..d99f2d0 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,9 +1,32 @@ -import typing +from typing import Any, Optional import pytest from pytest_mock import MockerFixture +from pydantic import ValidationError -from edge_proxy.settings import get_settings +from edge_proxy.settings import get_settings, AppSettings + + +@pytest.mark.parametrize( + "client_side_key,server_side_key,expected_exception", + [ + ("abc123", "ser.456", None), + ("abc123", "456", ValidationError), + ("abc123", "", ValidationError), + ("", "ser.456", ValidationError), + ], +) +def test_client_side_key_validation( + client_side_key: str, server_side_key: str, expected_exception: Optional[Exception] +) -> None: + try: + AppSettings( + environment_key_pairs=[ + {"server_side_key": server_side_key, "client_side_key": client_side_key} + ] + ) + except expected_exception: + pass @pytest.mark.parametrize( @@ -12,7 +35,7 @@ ( { "environment_key_pairs": [ - {"server_side_key": "abc123", "client_side_key": "ser.def456"} + {"server_side_key": "ser.abc123", "client_side_key": "def456"} ], "api_poll_frequency": 10, "api_poll_timeout": 10, @@ -23,7 +46,7 @@ ( { "environment_key_pairs": [ - {"server_side_key": "abc123", "client_side_key": "ser.def456"} + {"server_side_key": "ser.abc123", "client_side_key": "def456"} ], "api_poll_frequency_seconds": 10, "api_poll_timeout_seconds": 10, @@ -35,8 +58,8 @@ ) def test_settings_are_loaded_correctly( mocker: MockerFixture, - config_file_json: dict[str, typing.Any], - expected_config: dict[str, typing.Any], + config_file_json: dict[str, Any], + expected_config: dict[str, Any], ) -> None: """ Parametrized test which accepts a raw json config file, and a dictionary representing the