diff --git a/flag_engine/segments/evaluator.py b/flag_engine/segments/evaluator.py index e9edc98a..2ecbbe0f 100644 --- a/flag_engine/segments/evaluator.py +++ b/flag_engine/segments/evaluator.py @@ -109,7 +109,7 @@ def get_evaluation_result(context: EvaluationContext) -> EvaluationResult: segment_feature_contexts[feature_key] = override_feature_context identity_key = get_context_value(context, "$.identity.key") - flags: typing.List[FlagResult] = [ + flags: list[FlagResult] = [ ( { "enabled": segment_feature_context["enabled"], @@ -140,7 +140,7 @@ def get_evaluation_result(context: EvaluationContext) -> EvaluationResult: def get_flag_result_from_feature_context( feature_context: FeatureContext, - key: SupportsStr, + key: typing.Optional[SupportsStr], ) -> FlagResult: """ Get a feature value from the feature context @@ -150,7 +150,7 @@ def get_flag_result_from_feature_context( :param key: the key to get the value for :return: the value for the key in the feature context """ - if variants := feature_context.get("variants"): + if key is not None and (variants := feature_context.get("variants")): percentage_value = get_hashed_percentage_for_object_ids( [feature_context["key"], key] ) diff --git a/tests/unit/segments/test_segments_evaluator.py b/tests/unit/segments/test_segments_evaluator.py index 9cb7bfb5..648a19ed 100644 --- a/tests/unit/segments/test_segments_evaluator.py +++ b/tests/unit/segments/test_segments_evaluator.py @@ -984,7 +984,7 @@ def test_get_evaluation_result__identity_override__returns_expected( ), ), ) -def test_get_flag_result_from_feature_context__call_return_expected( +def test_get_flag_result_from_feature_context__calls_returns_expected( percentage_value: int, expected_result: FlagResult, mocker: MockerFixture, @@ -1031,6 +1031,50 @@ def test_get_flag_result_from_feature_context__call_return_expected( ) +def test_get_flag_result_from_feature_context__null_key__calls_returns_expected( + mocker: MockerFixture, +) -> None: + # Given + expected_feature_context_key = "2" + # a None key is provided (no identity context present) + expected_key = None + + get_hashed_percentage_for_object_ids_mock = mocker.patch( + "flag_engine.segments.evaluator.get_hashed_percentage_for_object_ids", + ) + + feature_context: FeatureContext = { + "key": expected_feature_context_key, + "feature_key": "1", + "enabled": False, + "name": "my_feature", + "value": "control", + "variants": [ + {"value": "foo", "weight": 30}, + {"value": "bar", "weight": 30}, + ], + } + + # When + result = get_flag_result_from_feature_context( + feature_context=feature_context, + key=expected_key, + ) + + # Then + # the value of the feature state is the default one + assert result == { + "enabled": False, + "feature_key": "1", + "name": "my_feature", + "reason": "DEFAULT", + "value": "control", + } + + # the function is not called as there is no key to hash against + get_hashed_percentage_for_object_ids_mock.assert_not_called() + + @pytest.mark.parametrize( "property", [