Skip to content

Commit

Permalink
handle proper default value in Values.__getattr__
Browse files Browse the repository at this point in the history
  • Loading branch information
m.kindritskiy committed Dec 19, 2024
1 parent e5da79a commit f932dd8
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 25 deletions.
10 changes: 9 additions & 1 deletion featureflags_client/http/values.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ def __getattr__(self, name: str) -> Union[int, str]:
value = self._overrides.get(name)
if value is None:
check = self._manager.get_value(name)
value = check(self._ctx) if check is not None else default
if callable(check):
# evaluated value
value = check(self._ctx)
elif check is not None:
# default value from server
value = check
else:
# default value from client code
value = default

# caching/snapshotting
setattr(self, name, value)
Expand Down
65 changes: 41 additions & 24 deletions featureflags_client/tests/http/managers/test_async.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from unittest.mock import patch

import faker
from featureflags_client.tests.conftest import value
import pytest

from featureflags_client.http.client import FeatureFlagsClient
Expand All @@ -22,7 +23,8 @@ class Defaults:

class ValuesDefaults:
TEST = "test"
TEST_INT = 1
TEST_INT_A = 1
TEST_INT_B = 20


@pytest.mark.asyncio
Expand Down Expand Up @@ -85,7 +87,6 @@ async def test_manager(async_manager_class, flag, variable, check, condition):
)
async def test_values_manager(
async_manager_class,
value,
variable,
check,
value_condition,
Expand All @@ -102,45 +103,61 @@ async def test_values_manager(
)
client = FeatureFlagsClient(manager)

value_test = Value(
name="TEST",
enabled=True,
overridden=True,
value_default="test",
value_override="nottest",
conditions=[value_condition],
)

value_test_int_a = Value(
name="TEST_INT_A",
enabled=True,
overridden=True,
value_default=1,
value_override=2,
conditions=[value_condition_int_value],
)

value_test_int_b = Value(
name="TEST_INT_B",
enabled=False,
overridden=False,
value_default=10,
value_override=10,
conditions=[],
)

mock_preload_response = PreloadFlagsResponse(
version=1,
flags=[],
values=[
Value(
name="TEST",
enabled=True,
overridden=True,
value_default="test",
value_override="nottest",
conditions=[value_condition],
),
Value(
name="TEST_INT",
enabled=True,
overridden=True,
value_default=1,
value_override=2,
conditions=[value_condition_int_value],
),
],
values=[value_test, value_test_int_a, value_test_int_b],
)
with patch.object(manager, "_post") as mock_post:
mock_post.return_value = mock_preload_response.to_dict()

await client.preload_async()
mock_post.assert_called_once()

# check that resulting values based on conditions
with client.values({variable.name: check.value}) as values:
assert values.TEST is value_condition.value_override
assert values.TEST_INT is value_condition_int_value.value_override
assert values.TEST_INT_A is value_condition_int_value.value_override
assert values.TEST_INT_B == value_test_int_b.value_default

# check that resulting values NOT based on conditions
with client.values({variable.name: f.pystr()}) as values:
assert values.TEST == "nottest"
assert values.TEST_INT == 2
assert values.TEST == value_test.value_override
assert values.TEST_INT_A == value_test_int_a.value_override
assert values.TEST_INT_B == value_test_int_b.value_default

# check that each .values call is isolated
with client.values({variable.name: check.value}) as values:
assert values.TEST is value_condition.value_override
assert values.TEST_INT is value_condition_int_value.value_override
assert values.TEST_INT_A is value_condition_int_value.value_override
assert values.TEST_INT_B == value_test_int_b.value_default

# close client connection.
await manager.close()

0 comments on commit f932dd8

Please sign in to comment.