diff --git a/src/main/java/dev/openfeature/sdk/ImmutableContext.java b/src/main/java/dev/openfeature/sdk/ImmutableContext.java index 632448aa..67e35629 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableContext.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableContext.java @@ -62,7 +62,8 @@ public final class ImmutableContext implements EvaluationContext { */ @Override public String getTargetingKey() { - return this.getValue(TARGETING_KEY).asString(); + Value value = this.getValue(TARGETING_KEY); + return value == null ? null : value.asString(); } /** diff --git a/src/main/java/dev/openfeature/sdk/MutableContext.java b/src/main/java/dev/openfeature/sdk/MutableContext.java index 69c22b84..42b9ccb7 100644 --- a/src/main/java/dev/openfeature/sdk/MutableContext.java +++ b/src/main/java/dev/openfeature/sdk/MutableContext.java @@ -99,7 +99,8 @@ public class MutableContext implements EvaluationContext { */ @Override public String getTargetingKey() { - return this.getValue(TARGETING_KEY).asString(); + Value value = this.getValue(TARGETING_KEY); + return value == null ? null : value.asString(); } /** diff --git a/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java b/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java index 7cfedec9..c3847b93 100644 --- a/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java +++ b/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java @@ -47,6 +47,12 @@ class ImmutableContextTest { EvaluationContext merge = ctx.merge(overriding); assertEquals("targeting_key", merge.getTargetingKey()); } + @DisplayName("missing targeting key should return null") + @Test + void missingTargetingKeyShould() { + EvaluationContext ctx = new ImmutableContext(); + assertEquals(null, ctx.getTargetingKey()); + } @DisplayName("Merge should retain all the attributes from the existing context when overriding context is null") @Test diff --git a/src/test/java/dev/openfeature/sdk/MutableContextTest.java b/src/test/java/dev/openfeature/sdk/MutableContextTest.java new file mode 100644 index 00000000..655cc85d --- /dev/null +++ b/src/test/java/dev/openfeature/sdk/MutableContextTest.java @@ -0,0 +1,105 @@ +package dev.openfeature.sdk; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; + +import static dev.openfeature.sdk.EvaluationContext.TARGETING_KEY; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MutableContextTest { + + @DisplayName("targeting key should be changed from the overriding context") + @Test + void shouldChangeTargetingKeyFromOverridingContext() { + HashMap attributes = new HashMap<>(); + attributes.put("key1", new Value("val1")); + attributes.put("key2", new Value("val2")); + EvaluationContext ctx = new MutableContext("targeting key", attributes); + EvaluationContext overriding = new MutableContext("overriding_key"); + EvaluationContext merge = ctx.merge(overriding); + assertEquals("overriding_key", merge.getTargetingKey()); + } + + @DisplayName("targeting key should not changed from the overriding context if missing") + @Test + void shouldRetainTargetingKeyWhenOverridingContextTargetingKeyValueIsEmpty() { + HashMap attributes = new HashMap<>(); + attributes.put("key1", new Value("val1")); + attributes.put("key2", new Value("val2")); + EvaluationContext ctx = new MutableContext("targeting_key", attributes); + EvaluationContext overriding = new MutableContext(""); + EvaluationContext merge = ctx.merge(overriding); + assertEquals("targeting_key", merge.getTargetingKey()); + } + @DisplayName("missing targeting key should return null") + @Test + void missingTargetingKeyShould() { + EvaluationContext ctx = new MutableContext(); + assertEquals(null, ctx.getTargetingKey()); + } + + @DisplayName("Merge should retain all the attributes from the existing context when overriding context is null") + @Test + void mergeShouldReturnAllTheValuesFromTheContextWhenOverridingContextIsNull() { + HashMap attributes = new HashMap<>(); + attributes.put("key1", new Value("val1")); + attributes.put("key2", new Value("val2")); + EvaluationContext ctx = new MutableContext("targeting_key", attributes); + EvaluationContext merge = ctx.merge(null); + assertEquals("targeting_key", merge.getTargetingKey()); + assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + } + + @DisplayName("Merge should retain subkeys from the existing context when the overriding context has the same targeting key") + @Test + void mergeShouldRetainItsSubkeysWhenOverridingContextHasTheSameKey() { + HashMap attributes = new HashMap<>(); + HashMap overridingAttributes = new HashMap<>(); + HashMap key1Attributes = new HashMap<>(); + HashMap ovKey1Attributes = new HashMap<>(); + + key1Attributes.put("key1_1", new Value("val1_1")); + attributes.put("key1", new Value(new ImmutableStructure(key1Attributes))); + attributes.put("key2", new Value("val2")); + ovKey1Attributes.put("overriding_key1_1", new Value("overriding_val_1_1")); + overridingAttributes.put("key1", new Value(new ImmutableStructure(ovKey1Attributes))); + + EvaluationContext ctx = new MutableContext("targeting_key", attributes); + EvaluationContext overriding = new MutableContext("targeting_key", overridingAttributes); + EvaluationContext merge = ctx.merge(overriding); + assertEquals("targeting_key", merge.getTargetingKey()); + assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + + Value key1 = merge.getValue("key1"); + assertTrue(key1.isStructure()); + + Structure value = key1.asStructure(); + assertArrayEquals(new Object[]{"key1_1","overriding_key1_1"}, value.keySet().toArray()); + } + + @DisplayName("Merge should retain subkeys from the existing context when the overriding context doesn't have targeting key") + @Test + void mergeShouldRetainItsSubkeysWhenOverridingContextHasNoTargetingKey() { + HashMap attributes = new HashMap<>(); + HashMap key1Attributes = new HashMap<>(); + + key1Attributes.put("key1_1", new Value("val1_1")); + attributes.put("key1", new Value(new ImmutableStructure(key1Attributes))); + attributes.put("key2", new Value("val2")); + + EvaluationContext ctx = new MutableContext(attributes); + EvaluationContext overriding = new MutableContext(); + EvaluationContext merge = ctx.merge(overriding); + assertArrayEquals(new Object[]{"key1", "key2"}, merge.keySet().toArray()); + + Value key1 = merge.getValue("key1"); + assertTrue(key1.isStructure()); + + Structure value = key1.asStructure(); + assertArrayEquals(new Object[]{"key1_1"}, value.keySet().toArray()); + } +}