From c09679e2af618d037f6869d4aa963d7b39d04218 Mon Sep 17 00:00:00 2001 From: DBlanchard88 Date: Fri, 6 Oct 2023 14:18:28 -0400 Subject: [PATCH 1/4] FIX: float to int conversion and testing Signed-off-by: DBlanchard88 --- .../resolver/process/InProcessResolver.java | 23 ++++-- .../flagd/e2e/steps/StepDefinitions.java | 11 ++- .../process/InProcessResolverTest.java | 77 ++++++++++++++----- 3 files changed, 78 insertions(+), 33 deletions(-) diff --git a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java index 409b85ddd..c02449d9f 100644 --- a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java +++ b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java @@ -26,7 +26,8 @@ import static dev.openfeature.contrib.providers.flagd.resolver.process.model.FeatureFlag.EMPTY_TARGETING_STRING; /** - * flagd in-process resolver. Resolves feature flags in-process. Flags are retrieved from {@link Storage}, where the + * flagd in-process resolver. Resolves feature flags in-process. Flags are + * retrieved from {@link Storage}, where the * {@link Storage} maintain flag configurations obtained from known source. */ @Slf4j @@ -97,7 +98,7 @@ public void shutdown() throws InterruptedException { * Resolve a boolean flag. */ public ProviderEvaluation booleanEvaluation(String key, Boolean defaultValue, - EvaluationContext ctx) { + EvaluationContext ctx) { return resolve(Boolean.class, key, ctx); } @@ -105,7 +106,7 @@ public ProviderEvaluation booleanEvaluation(String key, Boolean default * Resolve a string flag. */ public ProviderEvaluation stringEvaluation(String key, String defaultValue, - EvaluationContext ctx) { + EvaluationContext ctx) { return resolve(String.class, key, ctx); } @@ -113,7 +114,7 @@ public ProviderEvaluation stringEvaluation(String key, String defaultVal * Resolve a double flag. */ public ProviderEvaluation doubleEvaluation(String key, Double defaultValue, - EvaluationContext ctx) { + EvaluationContext ctx) { return resolve(Double.class, key, ctx); } @@ -121,7 +122,7 @@ public ProviderEvaluation doubleEvaluation(String key, Double defaultVal * Resolve an integer flag. */ public ProviderEvaluation integerEvaluation(String key, Integer defaultValue, - EvaluationContext ctx) { + EvaluationContext ctx) { return resolve(Integer.class, key, ctx); } @@ -142,7 +143,7 @@ public ProviderEvaluation objectEvaluation(String key, Value defaultValue } private ProviderEvaluation resolve(Class type, String key, - EvaluationContext ctx) { + EvaluationContext ctx) { final FeatureFlag flag = flagStore.getFlag(key); // missing flag @@ -155,7 +156,6 @@ private ProviderEvaluation resolve(Class type, String key, throw new FlagNotFoundError("flag: " + key + " is disabled"); } - final Object resolvedVariant; final String reason; @@ -186,7 +186,14 @@ private ProviderEvaluation resolve(Class type, String key, log.debug(message); throw new TypeMismatchError(message); } - + // if this is an integer and we are trying to resolve a double, convert + if (value instanceof Integer && type == Double.class) { + value = ((Integer) value).doubleValue(); + } + // if this is a doulbe and we are trying to resolve an integer, convert + else if (value instanceof Double && type == Integer.class) { + value = ((Double) value).intValue(); + } if (!type.isAssignableFrom(value.getClass()) || !(resolvedVariant instanceof String)) { String message = "returning default variant for flagKey: %s, type not valid"; log.debug(String.format(message, key)); diff --git a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/StepDefinitions.java b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/StepDefinitions.java index ae426db1a..ad11540a4 100644 --- a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/StepDefinitions.java +++ b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/StepDefinitions.java @@ -460,16 +460,15 @@ public void the_resolved_boolean_zero_value_should_be(String expected) { // float/double value @When("a zero-value float flag with key {string} is evaluated with default value {double}") public void a_zero_value_float_flag_with_key_is_evaluated_with_default_value(String flagKey, Double defaultValue) { - // TODO: There is a bug here with 0 value floats - // this.doubleFlagKey = flagKey; - // this.doubleFlagDefaultValue = defaultValue; + this.doubleFlagKey = flagKey; + this.doubleFlagDefaultValue = defaultValue; } @Then("the resolved float zero-value should be {double}") public void the_resolved_float_zero_value_should_be(Double expected) { - // FlagEvaluationDetails details = - // client.getDoubleDetails("float-zero-flag", this.doubleFlagDefaultValue); - // assertEquals(expected, details.getValue()); + FlagEvaluationDetails details = + client.getDoubleDetails("float-zero-flag", this.doubleFlagDefaultValue); + assertEquals(expected, details.getValue()); } // integer value diff --git a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java index fc668b1a5..59aea23e3 100644 --- a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java +++ b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java @@ -47,8 +47,8 @@ public void eventHandling() throws Throwable { final BlockingQueue sender = new LinkedBlockingQueue<>(5); final BlockingQueue receiver = new LinkedBlockingQueue<>(5); - InProcessResolver inProcessResolver = - getInProcessResolverWth(new MockStorage(new HashMap<>(), sender), providerState -> { + InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(new HashMap<>(), sender), + providerState -> { receiver.offer(providerState); }); @@ -56,7 +56,8 @@ public void eventHandling() throws Throwable { Thread initThread = new Thread(() -> { try { inProcessResolver.init(); - } catch (Exception e) {} + } catch (Exception e) { + } }); initThread.start(); if (!sender.offer(StorageState.OK, 100, TimeUnit.MILLISECONDS)) { @@ -86,8 +87,8 @@ public void simpleBooleanResolving() throws Exception { }); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.booleanEvaluation("booleanFlag", false, new ImmutableContext()); + ProviderEvaluation providerEvaluation = inProcessResolver.booleanEvaluation("booleanFlag", false, + new ImmutableContext()); // then assertEquals(true, providerEvaluation.getValue()); @@ -105,8 +106,8 @@ public void simpleDoubleResolving() throws Exception { }); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.doubleEvaluation("doubleFlag", 0d, new ImmutableContext()); + ProviderEvaluation providerEvaluation = inProcessResolver.doubleEvaluation("doubleFlag", 0d, + new ImmutableContext()); // then assertEquals(3.141d, providerEvaluation.getValue()); @@ -114,6 +115,46 @@ public void simpleDoubleResolving() throws Exception { assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason()); } + @Test + public void fetchIntegerAsDouble() throws Exception { + // given + + final Map flagMap = new HashMap<>(); + flagMap.put("doubleFlag", DOUBLE_FLAG); + + InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(flagMap), providerState -> { + }); + + // when + ProviderEvaluation providerEvaluation = inProcessResolver.integerEvaluation("doubleFlag", 0, + new ImmutableContext()); + + // then + assertEquals(3, providerEvaluation.getValue()); + assertEquals("one", providerEvaluation.getVariant()); + assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason()); + } + + @Test + public void fetchDoubleAsInt() throws Exception { + // given + + final Map flagMap = new HashMap<>(); + flagMap.put("integerFlag", INT_FLAG); + + InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(flagMap), providerState -> { + }); + + // when + ProviderEvaluation providerEvaluation = inProcessResolver.doubleEvaluation("integerFlag", 0d, + new ImmutableContext()); + + // then + assertEquals(1d, providerEvaluation.getValue()); + assertEquals("one", providerEvaluation.getVariant()); + assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason()); + } + @Test public void simpleIntResolving() throws Exception { // given @@ -124,8 +165,8 @@ public void simpleIntResolving() throws Exception { }); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.integerEvaluation("integerFlag", 0, new ImmutableContext()); + ProviderEvaluation providerEvaluation = inProcessResolver.integerEvaluation("integerFlag", 0, + new ImmutableContext()); // then assertEquals(1, providerEvaluation.getValue()); @@ -147,8 +188,8 @@ public void simpleObjectResolving() throws Exception { typeDefault.put("date", "01.01.1990"); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.objectEvaluation("objectFlag", Value.objectToValue(typeDefault), new ImmutableContext()); + ProviderEvaluation providerEvaluation = inProcessResolver.objectEvaluation("objectFlag", + Value.objectToValue(typeDefault), new ImmutableContext()); // then Value value = providerEvaluation.getValue(); @@ -230,9 +271,8 @@ public void targetingMatchedEvaluationFlag() throws Exception { }); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.stringEvaluation("stringFlag", "loopAlg", - new MutableContext().add("email", "abc@faas.com")); + ProviderEvaluation providerEvaluation = inProcessResolver.stringEvaluation("stringFlag", "loopAlg", + new MutableContext().add("email", "abc@faas.com")); // then assertEquals("binetAlg", providerEvaluation.getValue()); @@ -250,9 +290,8 @@ public void targetingUnmatchedEvaluationFlag() throws Exception { }); // when - ProviderEvaluation providerEvaluation = - inProcessResolver.stringEvaluation("stringFlag", "loopAlg", - new MutableContext().add("email", "abc@abc.com")); + ProviderEvaluation providerEvaluation = inProcessResolver.stringEvaluation("stringFlag", "loopAlg", + new MutableContext().add("email", "abc@abc.com")); // then assertEquals("loopAlg", providerEvaluation.getValue()); @@ -275,13 +314,13 @@ public void targetingErrorEvaluationFlag() throws Exception { }); } - private InProcessResolver getInProcessResolverWth(final MockStorage storage, Consumer stateConsumer) throws NoSuchFieldException, IllegalAccessException { Field flagStore = InProcessResolver.class.getDeclaredField("flagStore"); flagStore.setAccessible(true); - InProcessResolver resolver = new InProcessResolver(FlagdOptions.builder().deadline(1000).build(), stateConsumer); + InProcessResolver resolver = new InProcessResolver(FlagdOptions.builder().deadline(1000).build(), + stateConsumer); flagStore.set(resolver, storage); return resolver; From 6a437727ec6419f27126baba3ca3ba4ac35bdb6e Mon Sep 17 00:00:00 2001 From: DBlanchard88 Date: Fri, 6 Oct 2023 17:56:09 -0400 Subject: [PATCH 2/4] FIX: float to int conversion and testing Signed-off-by: DBlanchard88 --- .../providers/flagd/resolver/process/InProcessResolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java index c02449d9f..2954915df 100644 --- a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java +++ b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java @@ -189,9 +189,9 @@ private ProviderEvaluation resolve(Class type, String key, // if this is an integer and we are trying to resolve a double, convert if (value instanceof Integer && type == Double.class) { value = ((Integer) value).doubleValue(); - } + // if this is a doulbe and we are trying to resolve an integer, convert - else if (value instanceof Double && type == Integer.class) { + } else if (value instanceof Double && type == Integer.class) { value = ((Double) value).intValue(); } if (!type.isAssignableFrom(value.getClass()) || !(resolvedVariant instanceof String)) { From cf4aadbb650fa51588700c6fd3279b445d8235d1 Mon Sep 17 00:00:00 2001 From: DBlanchard88 Date: Fri, 6 Oct 2023 18:12:17 -0400 Subject: [PATCH 3/4] formatting Signed-off-by: DBlanchard88 --- .../providers/flagd/resolver/process/InProcessResolverTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java index 59aea23e3..73a91c162 100644 --- a/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java +++ b/providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java @@ -118,7 +118,6 @@ public void simpleDoubleResolving() throws Exception { @Test public void fetchIntegerAsDouble() throws Exception { // given - final Map flagMap = new HashMap<>(); flagMap.put("doubleFlag", DOUBLE_FLAG); @@ -138,7 +137,6 @@ public void fetchIntegerAsDouble() throws Exception { @Test public void fetchDoubleAsInt() throws Exception { // given - final Map flagMap = new HashMap<>(); flagMap.put("integerFlag", INT_FLAG); From f2ce59ff16b1c41c2a77dd1e6e41323f75265da1 Mon Sep 17 00:00:00 2001 From: David Blanchard <89858058+DBlanchard88@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:06:25 -0400 Subject: [PATCH 4/4] Update providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java Co-authored-by: Kavindu Dodanduwa Signed-off-by: David Blanchard <89858058+DBlanchard88@users.noreply.github.com> --- .../providers/flagd/resolver/process/InProcessResolver.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java index 2954915df..db7961436 100644 --- a/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java +++ b/providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java @@ -186,12 +186,11 @@ private ProviderEvaluation resolve(Class type, String key, log.debug(message); throw new TypeMismatchError(message); } - // if this is an integer and we are trying to resolve a double, convert if (value instanceof Integer && type == Double.class) { + // if this is an integer and we are trying to resolve a double, convert value = ((Integer) value).doubleValue(); - - // if this is a doulbe and we are trying to resolve an integer, convert } else if (value instanceof Double && type == Integer.class) { + // if this is a double and we are trying to resolve an integer, convert value = ((Double) value).intValue(); } if (!type.isAssignableFrom(value.getClass()) || !(resolvedVariant instanceof String)) {