Skip to content

Commit 30af01f

Browse files
authored
Merge pull request #148 from Flagsmith/feat/logging
feat: Immediately exit if configuration is missing or invalid
2 parents 436252d + 02c4134 commit 30af01f

File tree

4 files changed

+45
-26
lines changed

4 files changed

+45
-26
lines changed

src/edge_proxy/settings.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@
88

99
import structlog
1010

11-
from pydantic import AliasChoices, BaseModel, HttpUrl, IPvAnyAddress, Field
11+
from pydantic import AliasChoices, BaseModel, HttpUrl, IPvAnyAddress, Field, constr
1212

1313
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource
1414

15-
1615
CONFIG_PATH = os.environ.get(
1716
"CONFIG_PATH",
1817
default="config.json",
1918
)
2019

21-
2220
logger = structlog.get_logger()
2321

2422

@@ -65,8 +63,8 @@ def json_config_settings_source() -> dict[str, Any]:
6563

6664

6765
class EnvironmentKeyPair(BaseModel):
68-
server_side_key: str
69-
client_side_key: str
66+
server_side_key: constr(pattern=r"ser\.*", strip_whitespace=True)
67+
client_side_key: constr(min_length=1, strip_whitespace=True)
7068

7169

7270
class EndpointCacheSettings(BaseModel):
@@ -105,14 +103,7 @@ class HealthCheckSettings(BaseModel):
105103

106104

107105
class AppSettings(BaseModel):
108-
environment_key_pairs: list[EnvironmentKeyPair] = Field(
109-
default_factory=lambda: [
110-
EnvironmentKeyPair(
111-
server_side_key="ser.environment_key",
112-
client_side_key="environment_key",
113-
)
114-
]
115-
)
106+
environment_key_pairs: list[EnvironmentKeyPair]
116107
api_url: HttpUrl = HttpUrl("https://edge.api.flagsmith.com/api/v1")
117108
api_poll_frequency_seconds: int = Field(
118109
default=10,

tests/conftest.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,15 @@ def environment_1_feature_states_response_list_response_with_identity_override(
5151

5252

5353
@pytest.fixture(autouse=True)
54-
def skip_json_config_settings_source(mocker: MockerFixture) -> None:
55-
mocker.patch("edge_proxy.settings.json_config_settings_source", dict)
54+
def mock_settings(mocker: MockerFixture) -> None:
55+
mock_config = {
56+
"environment_key_pairs": [
57+
{"server_side_key": "ser.abc123", "client_side_key": "def456"}
58+
]
59+
}
60+
mocker.patch(
61+
"edge_proxy.settings.json_config_settings_source", return_value=mock_config
62+
)
5663

5764

5865
@pytest.fixture

tests/test_server.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from fastapi.testclient import TestClient
77
from pytest_mock import MockerFixture
88

9-
from edge_proxy.settings import AppSettings, HealthCheckSettings
9+
from edge_proxy.settings import HealthCheckSettings
1010
from tests.fixtures.response_data import environment_1
1111

1212
if typing.TYPE_CHECKING:
@@ -59,10 +59,8 @@ def test_health_check_returns_200_if_cache_is_stale_and_health_check_configured_
5959
client: TestClient,
6060
) -> None:
6161
# Given
62-
settings = AppSettings(
63-
health_check=HealthCheckSettings(environment_update_grace_period_seconds=None)
64-
)
65-
mocker.patch("edge_proxy.server.settings", settings)
62+
health_check = HealthCheckSettings(environment_update_grace_period_seconds=None)
63+
mocker.patch("edge_proxy.server.settings.health_check", health_check)
6664

6765
last_updated_at = datetime.now() - timedelta(days=10)
6866
mocked_environment_service = mocker.patch("edge_proxy.server.environment_service")

tests/test_settings.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
1-
import typing
1+
from typing import Any, Optional
22

33
import pytest
44
from pytest_mock import MockerFixture
5+
from pydantic import ValidationError
56

6-
from edge_proxy.settings import get_settings
7+
from edge_proxy.settings import get_settings, AppSettings
8+
9+
10+
@pytest.mark.parametrize(
11+
"client_side_key,server_side_key,expected_exception",
12+
[
13+
("abc123", "ser.456", None),
14+
("abc123", "456", ValidationError),
15+
("abc123", "", ValidationError),
16+
("", "ser.456", ValidationError),
17+
],
18+
)
19+
def test_client_side_key_validation(
20+
client_side_key: str, server_side_key: str, expected_exception: Optional[Exception]
21+
) -> None:
22+
try:
23+
AppSettings(
24+
environment_key_pairs=[
25+
{"server_side_key": server_side_key, "client_side_key": client_side_key}
26+
]
27+
)
28+
except expected_exception:
29+
pass
730

831

932
@pytest.mark.parametrize(
@@ -12,7 +35,7 @@
1235
(
1336
{
1437
"environment_key_pairs": [
15-
{"server_side_key": "abc123", "client_side_key": "ser.def456"}
38+
{"server_side_key": "ser.abc123", "client_side_key": "def456"}
1639
],
1740
"api_poll_frequency": 10,
1841
"api_poll_timeout": 10,
@@ -23,7 +46,7 @@
2346
(
2447
{
2548
"environment_key_pairs": [
26-
{"server_side_key": "abc123", "client_side_key": "ser.def456"}
49+
{"server_side_key": "ser.abc123", "client_side_key": "def456"}
2750
],
2851
"api_poll_frequency_seconds": 10,
2952
"api_poll_timeout_seconds": 10,
@@ -35,8 +58,8 @@
3558
)
3659
def test_settings_are_loaded_correctly(
3760
mocker: MockerFixture,
38-
config_file_json: dict[str, typing.Any],
39-
expected_config: dict[str, typing.Any],
61+
config_file_json: dict[str, Any],
62+
expected_config: dict[str, Any],
4063
) -> None:
4164
"""
4265
Parametrized test which accepts a raw json config file, and a dictionary representing the

0 commit comments

Comments
 (0)