Skip to content

Commit c105be6

Browse files
fix: Deleted identity overrides not synchronised (#170)
Co-authored-by: Matthew Elwell <[email protected]>
1 parent fbd27ea commit c105be6

File tree

2 files changed

+96
-16
lines changed

2 files changed

+96
-16
lines changed

src/edge_proxy/cache.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
from abc import ABC
12
from collections import defaultdict
23
from typing import Any
3-
from abc import ABC
44

55

66
class BaseEnvironmentsCache(ABC):
@@ -57,11 +57,12 @@ def _put_environment(
5757
environment_document: dict[str, Any],
5858
) -> None:
5959
self._environment_cache[environment_api_key] = environment_document
60-
for identity_document in environment_document.get("identity_overrides") or []:
61-
if identifier := identity_document.get("identifier"):
62-
self._identity_override_cache[environment_api_key][identifier] = (
63-
identity_document
64-
)
60+
new_overrides = environment_document.get("identity_overrides") or []
61+
self._identity_override_cache[environment_api_key] = {
62+
identifier: identity_document
63+
for identity_document in new_overrides
64+
if (identifier := identity_document.get("identifier"))
65+
}
6566

6667
def get_environment(
6768
self,

tests/test_environments.py

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
)
1616
from edge_proxy.models import IdentityWithTraits
1717
from edge_proxy.settings import (
18+
AppSettings,
1819
EndpointCacheSettings,
1920
EndpointCachesSettings,
20-
AppSettings,
2121
)
2222
from tests.fixtures.response_data import environment_1, environment_1_api_key
2323

24+
pytestmark = pytest.mark.asyncio
25+
2426
client_key_2 = "test_env_key_2"
2527

2628
settings = AppSettings(
@@ -33,7 +35,6 @@
3335
now = datetime.now()
3436

3537

36-
@pytest.mark.asyncio
3738
async def test_refresh_makes_correct_http_call(mocker: MockerFixture):
3839
# Given
3940
mock_client = mocker.AsyncMock()
@@ -72,7 +73,6 @@ async def test_refresh_makes_correct_http_call(mocker: MockerFixture):
7273
assert environment_service.last_updated_at == now
7374

7475

75-
@pytest.mark.asyncio
7676
async def test_refresh_does_not_update_last_updated_at_if_any_request_fails(
7777
mocker: MockerFixture,
7878
):
@@ -91,7 +91,6 @@ async def test_refresh_does_not_update_last_updated_at_if_any_request_fails(
9191
assert environment_service.last_updated_at is None
9292

9393

94-
@pytest.mark.asyncio
9594
async def test_get_environment_works_correctly(mocker: MockerFixture):
9695
# Given
9796
mock_client = mocker.AsyncMock()
@@ -139,7 +138,6 @@ def test_get_environment_raises_for_unknown_keys():
139138
environment_service.get_environment(environment_key="test_env_key_unknown")
140139

141140

142-
@pytest.mark.asyncio
143141
async def test_refresh_environment_caches_clears_endpoint_caches_if_environment_changes(
144142
mocker: MockerFixture,
145143
) -> None:
@@ -196,7 +194,6 @@ async def test_refresh_environment_caches_clears_endpoint_caches_if_environment_
196194
assert environment_service.get_flags_response_data.cache_info().currsize == 0
197195

198196

199-
@pytest.mark.asyncio
200197
async def test_refresh_environment_caches_sets_last_modified_if_environment_was_cached(
201198
mocker: MockerFixture,
202199
):
@@ -231,7 +228,92 @@ def save_if_modified_since(**kwargs):
231228
assert if_modified_since == "Sun, 20 Jul 1969 20:17:40 GMT"
232229

233230

234-
@pytest.mark.asyncio
231+
async def test_refresh_environment_caches__deleted_identity_override__cached_expected(
232+
mocker: MockerFixture,
233+
) -> None:
234+
# Given
235+
modified_document = copy.deepcopy(environment_1)
236+
modified_document["identity_overrides"] = []
237+
238+
mocked_client = mocker.AsyncMock()
239+
mocked_client.get.side_effect = [
240+
mocker.MagicMock(
241+
text=orjson.dumps(environment_1), raise_for_status=lambda: None
242+
),
243+
mocker.MagicMock(
244+
text=orjson.dumps(modified_document), raise_for_status=lambda: None
245+
),
246+
]
247+
248+
environment_service = EnvironmentService(
249+
settings=AppSettings(
250+
api_url="http://127.0.0.1:8000/api/v1",
251+
environment_key_pairs=[
252+
{
253+
"server_side_key": "ser.key1",
254+
"client_side_key": environment_1_api_key,
255+
},
256+
],
257+
),
258+
client=mocked_client,
259+
)
260+
261+
# When
262+
await environment_service.refresh_environment_caches()
263+
264+
# Then
265+
assert environment_service.get_identity_response_data(
266+
IdentityWithTraits(identifier="overridden-id"),
267+
environment_1_api_key,
268+
) == {
269+
"flags": [
270+
{
271+
"enabled": True,
272+
"feature": {
273+
"id": 1,
274+
"name": "feature_1",
275+
"type": "STANDARD",
276+
},
277+
"feature_state_value": "identity_override",
278+
},
279+
{
280+
"enabled": True,
281+
"feature": {
282+
"id": 2,
283+
"name": "feature_2",
284+
"type": "STANDARD",
285+
},
286+
"feature_state_value": "2.3",
287+
},
288+
],
289+
"traits": [],
290+
}
291+
292+
# When
293+
# We refresh the environment caches again
294+
# and receive a document with the identity override removed
295+
await environment_service.refresh_environment_caches()
296+
297+
# Then
298+
assert environment_service.get_identity_response_data(
299+
IdentityWithTraits(identifier="overridden-id"), environment_1_api_key
300+
) == {
301+
"flags": [
302+
{
303+
"enabled": False,
304+
"feature": {"id": 1, "name": "feature_1", "type": "STANDARD"},
305+
"feature_state_value": "feature_1_value",
306+
},
307+
{
308+
"enabled": True,
309+
"feature": {"id": 2, "name": "feature_2", "type": "STANDARD"},
310+
"feature_state_value": "2.3",
311+
},
312+
],
313+
"traits": [],
314+
}
315+
316+
235317
async def test_get_identity_flags_response_skips_cache_for_different_identity(
236318
mocker: MockerFixture,
237319
) -> None:
@@ -270,7 +352,6 @@ async def test_get_identity_flags_response_skips_cache_for_different_identity(
270352
assert environment_service.get_identity_response_data.cache_info().hits == 0
271353

272354

273-
@pytest.mark.asyncio
274355
async def test_get_flags_response_data_skips_filter_for_server_key(
275356
mocker: MockerFixture,
276357
) -> None:
@@ -301,7 +382,6 @@ async def test_get_flags_response_data_skips_filter_for_server_key(
301382
assert specific_flag.get("feature").get("name") == "feature_3"
302383

303384

304-
@pytest.mark.asyncio
305385
async def test_get_flags_response_data_filters_server_side_features_for_client_key(
306386
mocker: MockerFixture,
307387
) -> None:
@@ -332,7 +412,6 @@ async def test_get_flags_response_data_filters_server_side_features_for_client_k
332412
assert len(flags) == 2
333413

334414

335-
@pytest.mark.asyncio
336415
async def test_get_identity_flags_response_skips_filter_for_server_key(
337416
mocker: MockerFixture,
338417
) -> None:

0 commit comments

Comments
 (0)