Skip to content

Commit 67e4368

Browse files
committed
feat: add tests for context merging
Signed-off-by: Lukas Reining <[email protected]>
1 parent 2a21b9d commit 67e4368

File tree

4 files changed

+63
-13
lines changed

4 files changed

+63
-13
lines changed

openfeature/api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
]
3737

3838
_evaluation_context = EvaluationContext()
39-
_evaluation_transaction_context_propagator = NoOpTransactionContextPropagator()
39+
_evaluation_transaction_context_propagator: TransactionContextPropagator = (
40+
NoOpTransactionContextPropagator()
41+
)
4042

4143
_hooks: typing.List[Hook] = []
4244

openfeature/transaction_context/context_var_transaction_context_propagator.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
TransactionContextPropagator,
66
)
77

8-
_transaction_context_var: ContextVar[EvaluationContext] = ContextVar(
9-
"transaction_context", default=EvaluationContext()
10-
)
11-
128

139
class ContextVarsTransactionContextPropagator(TransactionContextPropagator):
10+
_transaction_context_var: ContextVar[EvaluationContext] = ContextVar(
11+
"transaction_context", default=EvaluationContext()
12+
)
13+
1414
def get_transaction_context(self) -> EvaluationContext:
15-
return _transaction_context_var.get()
15+
return self._transaction_context_var.get()
1616

1717
def set_transaction_context(self, transaction_context: EvaluationContext) -> None:
18-
_transaction_context_var.set(transaction_context)
18+
self._transaction_context_var.set(transaction_context)

tests/test_client.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import time
22
import uuid
33
from concurrent.futures import ThreadPoolExecutor
4-
from unittest.mock import MagicMock
4+
from unittest.mock import MagicMock, Mock
55

66
import pytest
77

8+
from openfeature import api
89
from openfeature.api import add_hooks, clear_hooks, get_client, set_provider
910
from openfeature.client import OpenFeatureClient
11+
from openfeature.evaluation_context import EvaluationContext
1012
from openfeature.event import EventDetails, ProviderEvent, ProviderEventDetails
1113
from openfeature.exception import ErrorCode, OpenFeatureError
1214
from openfeature.flag_evaluation import FlagResolutionDetails, Reason
1315
from openfeature.hook import Hook
1416
from openfeature.provider import FeatureProvider, ProviderStatus
1517
from openfeature.provider.in_memory_provider import InMemoryFlag, InMemoryProvider
1618
from openfeature.provider.no_op_provider import NoOpProvider
19+
from openfeature.transaction_context import ContextVarsTransactionContextPropagator
1720

1821

1922
@pytest.mark.parametrize(
@@ -384,3 +387,47 @@ def emit_events_task():
384387
f2 = executor.submit(emit_events_task)
385388
f1.result()
386389
f2.result()
390+
391+
392+
def test_client_should_merge_contexts():
393+
api.clear_hooks()
394+
api.set_transaction_context_propagator(ContextVarsTransactionContextPropagator())
395+
396+
provider = NoOpProvider()
397+
provider.resolve_boolean_details = MagicMock(wraps=provider.resolve_boolean_details)
398+
api.set_provider(provider)
399+
400+
# Global evaluation context
401+
global_context = EvaluationContext(
402+
targeting_key="global", attributes={"global_attr": "global_value"}
403+
)
404+
api.set_evaluation_context(global_context)
405+
406+
# Transaction context
407+
transaction_context = EvaluationContext(
408+
targeting_key="transaction",
409+
attributes={"transaction_attr": "transaction_value"},
410+
)
411+
api.set_transaction_context(transaction_context)
412+
413+
# Client-specific context
414+
client_context = EvaluationContext(
415+
targeting_key="client", attributes={"client_attr": "client_value"}
416+
)
417+
client = OpenFeatureClient(domain=None, version=None, context=client_context)
418+
419+
# Invocation-specific context
420+
invocation_context = EvaluationContext(
421+
targeting_key="invocation", attributes={"invocation_attr": "invocation_value"}
422+
)
423+
client.get_boolean_details("flag", False, invocation_context)
424+
425+
# Retrieve the call arguments
426+
args, kwargs = provider.resolve_boolean_details.call_args
427+
flag_key, default_value, context = args
428+
429+
assert context.targeting_key == "invocation" # Last one in the merge chain
430+
assert context.attributes["global_attr"] == "global_value"
431+
assert context.attributes["transaction_attr"] == "transaction_value"
432+
assert context.attributes["client_attr"] == "client_value"
433+
assert context.attributes["invocation_attr"] == "invocation_value"

tests/test_transaction_context.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
NoOpTransactionContextPropagator,
1616
TransactionContextPropagator,
1717
)
18-
from openfeature.transaction_context.context_var_transaction_context_propagator import (
19-
_transaction_context_var,
20-
)
2118

2219

2320
# Test cases
@@ -97,8 +94,12 @@ def test_should_propagate_event_when_context_set():
9794
set_transaction_context(evaluation_context)
9895

9996
# Then
100-
assert _transaction_context_var.get().targeting_key == "custom_key"
101-
assert _transaction_context_var.get().attributes == {"attr1": "val1"}
97+
assert (
98+
custom_propagator._transaction_context_var.get().targeting_key == "custom_key"
99+
)
100+
assert custom_propagator._transaction_context_var.get().attributes == {
101+
"attr1": "val1"
102+
}
102103

103104

104105
def test_context_vars_transaction_context_propagator_multiple_threads():

0 commit comments

Comments
 (0)