Skip to content

Commit 7da7d2a

Browse files
authored
fix: edge cases with flagd targeting (#567)
Signed-off-by: Todd Baert <[email protected]>
1 parent fed100e commit 7da7d2a

File tree

5 files changed

+61
-6
lines changed

5 files changed

+61
-6
lines changed

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolver.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
161161
throw new FlagNotFoundError("flag: " + key + " is disabled");
162162
}
163163

164-
final Object resolvedVariant;
164+
final String resolvedVariant;
165165
final String reason;
166166

167167
if (EMPTY_TARGETING_STRING.equals(flag.getTargeting())) {
@@ -174,7 +174,7 @@ private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
174174
resolvedVariant = flag.getDefaultVariant();
175175
reason = Reason.DEFAULT.toString();
176176
} else {
177-
resolvedVariant = jsonResolved;
177+
resolvedVariant = jsonResolved.toString(); // convert to string to support shorthand
178178
reason = Reason.TARGETING_MATCH.toString();
179179
}
180180
} catch (TargetingRuleException e) {
@@ -198,15 +198,15 @@ private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
198198
// if this is a double and we are trying to resolve an integer, convert
199199
value = ((Double) value).intValue();
200200
}
201-
if (!type.isAssignableFrom(value.getClass()) || !(resolvedVariant instanceof String)) {
201+
if (!type.isAssignableFrom(value.getClass())) {
202202
String message = "returning default variant for flagKey: %s, type not valid";
203203
log.debug(String.format(message, key));
204204
throw new TypeMismatchError(message);
205205
}
206206

207207
return ProviderEvaluation.<T>builder()
208208
.value((T) value)
209-
.variant((String) resolvedVariant)
209+
.variant(resolvedVariant)
210210
.reason(reason)
211211
.build();
212212
}

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/StepDefinitions.java

+25
Original file line numberDiff line numberDiff line change
@@ -374,20 +374,45 @@ public void a_context_containing_a_nested_property_with_outer_key_and_inner_key_
374374
this.customEvaluatorContext = new ImmutableContext(outerMap);
375375
}
376376

377+
@And("a context containing a nested property with outer key {string} and inner key {string}, with value {int}")
378+
public void a_context_containing_a_nested_property_with_outer_key_and_inner_key_with_value_int(String outerKey,
379+
String innerKey, Integer value) throws InstantiationException {
380+
Map<String, Value> innerMap = new HashMap<String, Value>();
381+
innerMap.put(innerKey, new Value(value));
382+
Map<String, Value> outerMap = new HashMap<String, Value>();
383+
outerMap.put(outerKey, new Value(new ImmutableStructure(innerMap)));
384+
this.customEvaluatorContext = new ImmutableContext(outerMap);
385+
}
386+
387+
377388
@And("a context containing a key {string}, with value {string}")
378389
public void a_context_containing_a_key_with_value(String key, String value) {
379390
Map<String, Value> attrs = new HashMap<String, Value>();
380391
attrs.put(key, new Value(value));
381392
this.customEvaluatorContext = new ImmutableContext(attrs);
382393
}
383394

395+
@And("a context containing a key {string}, with value {double}")
396+
public void a_context_containing_a_key_with_value_double(String key, Double value) {
397+
Map<String, Value> attrs = new HashMap<String, Value>();
398+
attrs.put(key, new Value(value));
399+
this.customEvaluatorContext = new ImmutableContext(attrs);
400+
}
401+
384402
@Then("the returned value should be {string}")
385403
public void the_returned_value_should_be(String expected) {
386404
String value = client.getStringValue(this.stringFlagKey, this.stringFlagDefaultValue,
387405
this.customEvaluatorContext);
388406
assertEquals(expected, value);
389407
}
390408

409+
@Then("the returned value should be {int}")
410+
public void the_returned_value_should_be(Integer expectedValue) {
411+
Integer value = client.getIntegerValue(this.intFlagKey, this.intFlagDefaultValue,
412+
this.customEvaluatorContext);
413+
assertEquals(expectedValue, value);
414+
}
415+
391416
/*
392417
* Events
393418
*/

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/InProcessResolverTest.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.DOUBLE_FLAG;
66
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.FLAG_WIH_IF_IN_TARGET;
77
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.FLAG_WIH_INVALID_TARGET;
8+
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.FLAG_WIH_SHORTHAND_TARGETING;
89
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.INT_FLAG;
910
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.OBJECT_FLAG;
1011
import static dev.openfeature.contrib.providers.flagd.resolver.process.MockFlags.VARIANT_MISMATCH_FLAG;
1112
import static org.junit.jupiter.api.Assertions.assertEquals;
1213
import static org.junit.jupiter.api.Assertions.assertThrows;
1314
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
14-
import static org.junit.jupiter.api.Assertions.fail;
1515

1616
import java.lang.reflect.Field;
1717
import java.time.Duration;
@@ -259,6 +259,24 @@ public void typeMismatchEvaluation() throws Exception {
259259
});
260260
}
261261

262+
@Test
263+
public void booleanShorthandEvaluation() throws Exception {
264+
// given
265+
final Map<String, FeatureFlag> flagMap = new HashMap<>();
266+
flagMap.put("shorthand", FLAG_WIH_SHORTHAND_TARGETING);
267+
268+
InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(flagMap), providerState -> {
269+
});
270+
271+
ProviderEvaluation<Boolean> providerEvaluation = inProcessResolver.booleanEvaluation("shorthand", false,
272+
new ImmutableContext());
273+
274+
// then
275+
assertEquals(true, providerEvaluation.getValue());
276+
assertEquals("true", providerEvaluation.getVariant());
277+
assertEquals(Reason.TARGETING_MATCH.toString(), providerEvaluation.getReason());
278+
}
279+
262280
@Test
263281
public void targetingMatchedEvaluationFlag() throws Exception {
264282
// given

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/process/MockFlags.java

+12
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
public class MockFlags {
99

1010
static final Map<String, Object> booleanVariant;
11+
static final Map<String, Object> shorthandVariant;
1112
static final Map<String, Object> stringVariants;
1213
static final Map<String, Object> doubleVariants;
1314
static final Map<String, Object> intVariants;
@@ -18,6 +19,10 @@ public class MockFlags {
1819
booleanVariant.put("on", true);
1920
booleanVariant.put("off", false);
2021

22+
shorthandVariant = new HashMap<>();
23+
shorthandVariant.put("true", true);
24+
shorthandVariant.put("false", false);
25+
2126
stringVariants = new HashMap<>();
2227
stringVariants.put("loop", "loopAlg");
2328
stringVariants.put("binet", "binetAlg");
@@ -46,6 +51,9 @@ public class MockFlags {
4651
// correct flag - boolean
4752
static final FeatureFlag BOOLEAN_FLAG = new FeatureFlag("ENABLED", "on", booleanVariant, null);
4853

54+
// correct flag - boolean
55+
static final FeatureFlag SHORTHAND_FLAG = new FeatureFlag("ENABLED", "false", booleanVariant, null);
56+
4957
// correct flag - double
5058
static final FeatureFlag DOUBLE_FLAG = new FeatureFlag("ENABLED", "one", doubleVariants, null);
5159

@@ -68,4 +76,8 @@ public class MockFlags {
6876
// flag with incorrect targeting rule
6977
static final FeatureFlag FLAG_WIH_INVALID_TARGET = new FeatureFlag("ENABLED", "loop", stringVariants,
7078
"{if this, then that}");
79+
80+
// flag with shorthand rule
81+
static final FeatureFlag FLAG_WIH_SHORTHAND_TARGETING = new FeatureFlag("ENABLED", "false", shorthandVariant,
82+
"{ \"if\": [true, true, false] }");
7183
}

providers/flagd/test-harness

0 commit comments

Comments
 (0)