Skip to content

Commit 63b541c

Browse files
fix: int/float auto-conversion (#472)
Signed-off-by: DBlanchard88 <[email protected]> Co-authored-by: Kavindu Dodanduwa <[email protected]>
1 parent 4873ebc commit 63b541c

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

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

+14-8
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
import static dev.openfeature.contrib.providers.flagd.resolver.process.model.FeatureFlag.EMPTY_TARGETING_STRING;
2727

2828
/**
29-
* flagd in-process resolver. Resolves feature flags in-process. Flags are retrieved from {@link Storage}, where the
29+
* flagd in-process resolver. Resolves feature flags in-process. Flags are
30+
* retrieved from {@link Storage}, where the
3031
* {@link Storage} maintain flag configurations obtained from known source.
3132
*/
3233
@Slf4j
@@ -97,31 +98,31 @@ public void shutdown() throws InterruptedException {
9798
* Resolve a boolean flag.
9899
*/
99100
public ProviderEvaluation<Boolean> booleanEvaluation(String key, Boolean defaultValue,
100-
EvaluationContext ctx) {
101+
EvaluationContext ctx) {
101102
return resolve(Boolean.class, key, ctx);
102103
}
103104

104105
/**
105106
* Resolve a string flag.
106107
*/
107108
public ProviderEvaluation<String> stringEvaluation(String key, String defaultValue,
108-
EvaluationContext ctx) {
109+
EvaluationContext ctx) {
109110
return resolve(String.class, key, ctx);
110111
}
111112

112113
/**
113114
* Resolve a double flag.
114115
*/
115116
public ProviderEvaluation<Double> doubleEvaluation(String key, Double defaultValue,
116-
EvaluationContext ctx) {
117+
EvaluationContext ctx) {
117118
return resolve(Double.class, key, ctx);
118119
}
119120

120121
/**
121122
* Resolve an integer flag.
122123
*/
123124
public ProviderEvaluation<Integer> integerEvaluation(String key, Integer defaultValue,
124-
EvaluationContext ctx) {
125+
EvaluationContext ctx) {
125126
return resolve(Integer.class, key, ctx);
126127
}
127128

@@ -142,7 +143,7 @@ public ProviderEvaluation<Value> objectEvaluation(String key, Value defaultValue
142143
}
143144

144145
private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
145-
EvaluationContext ctx) {
146+
EvaluationContext ctx) {
146147
final FeatureFlag flag = flagStore.getFlag(key);
147148

148149
// missing flag
@@ -155,7 +156,6 @@ private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
155156
throw new FlagNotFoundError("flag: " + key + " is disabled");
156157
}
157158

158-
159159
final Object resolvedVariant;
160160
final String reason;
161161

@@ -186,7 +186,13 @@ private <T> ProviderEvaluation<T> resolve(Class<T> type, String key,
186186
log.debug(message);
187187
throw new TypeMismatchError(message);
188188
}
189-
189+
if (value instanceof Integer && type == Double.class) {
190+
// if this is an integer and we are trying to resolve a double, convert
191+
value = ((Integer) value).doubleValue();
192+
} else if (value instanceof Double && type == Integer.class) {
193+
// if this is a double and we are trying to resolve an integer, convert
194+
value = ((Double) value).intValue();
195+
}
190196
if (!type.isAssignableFrom(value.getClass()) || !(resolvedVariant instanceof String)) {
191197
String message = "returning default variant for flagKey: %s, type not valid";
192198
log.debug(String.format(message, key));

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

+5-6
Original file line numberDiff line numberDiff line change
@@ -460,16 +460,15 @@ public void the_resolved_boolean_zero_value_should_be(String expected) {
460460
// float/double value
461461
@When("a zero-value float flag with key {string} is evaluated with default value {double}")
462462
public void a_zero_value_float_flag_with_key_is_evaluated_with_default_value(String flagKey, Double defaultValue) {
463-
// TODO: There is a bug here with 0 value floats
464-
// this.doubleFlagKey = flagKey;
465-
// this.doubleFlagDefaultValue = defaultValue;
463+
this.doubleFlagKey = flagKey;
464+
this.doubleFlagDefaultValue = defaultValue;
466465
}
467466

468467
@Then("the resolved float zero-value should be {double}")
469468
public void the_resolved_float_zero_value_should_be(Double expected) {
470-
// FlagEvaluationDetails<Double> details =
471-
// client.getDoubleDetails("float-zero-flag", this.doubleFlagDefaultValue);
472-
// assertEquals(expected, details.getValue());
469+
FlagEvaluationDetails<Double> details =
470+
client.getDoubleDetails("float-zero-flag", this.doubleFlagDefaultValue);
471+
assertEquals(expected, details.getValue());
473472
}
474473

475474
// integer value

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

+56-19
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ public void eventHandling() throws Throwable {
4747
final BlockingQueue<StorageState> sender = new LinkedBlockingQueue<>(5);
4848
final BlockingQueue<ProviderState> receiver = new LinkedBlockingQueue<>(5);
4949

50-
InProcessResolver inProcessResolver =
51-
getInProcessResolverWth(new MockStorage(new HashMap<>(), sender), providerState -> {
50+
InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(new HashMap<>(), sender),
51+
providerState -> {
5252
receiver.offer(providerState);
5353
});
5454

5555
// when - init and emit events
5656
Thread initThread = new Thread(() -> {
5757
try {
5858
inProcessResolver.init();
59-
} catch (Exception e) {}
59+
} catch (Exception e) {
60+
}
6061
});
6162
initThread.start();
6263
if (!sender.offer(StorageState.OK, 100, TimeUnit.MILLISECONDS)) {
@@ -86,8 +87,8 @@ public void simpleBooleanResolving() throws Exception {
8687
});
8788

8889
// when
89-
ProviderEvaluation<Boolean> providerEvaluation =
90-
inProcessResolver.booleanEvaluation("booleanFlag", false, new ImmutableContext());
90+
ProviderEvaluation<Boolean> providerEvaluation = inProcessResolver.booleanEvaluation("booleanFlag", false,
91+
new ImmutableContext());
9192

9293
// then
9394
assertEquals(true, providerEvaluation.getValue());
@@ -105,15 +106,53 @@ public void simpleDoubleResolving() throws Exception {
105106
});
106107

107108
// when
108-
ProviderEvaluation<Double> providerEvaluation =
109-
inProcessResolver.doubleEvaluation("doubleFlag", 0d, new ImmutableContext());
109+
ProviderEvaluation<Double> providerEvaluation = inProcessResolver.doubleEvaluation("doubleFlag", 0d,
110+
new ImmutableContext());
110111

111112
// then
112113
assertEquals(3.141d, providerEvaluation.getValue());
113114
assertEquals("one", providerEvaluation.getVariant());
114115
assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason());
115116
}
116117

118+
@Test
119+
public void fetchIntegerAsDouble() throws Exception {
120+
// given
121+
final Map<String, FeatureFlag> flagMap = new HashMap<>();
122+
flagMap.put("doubleFlag", DOUBLE_FLAG);
123+
124+
InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(flagMap), providerState -> {
125+
});
126+
127+
// when
128+
ProviderEvaluation<Integer> providerEvaluation = inProcessResolver.integerEvaluation("doubleFlag", 0,
129+
new ImmutableContext());
130+
131+
// then
132+
assertEquals(3, providerEvaluation.getValue());
133+
assertEquals("one", providerEvaluation.getVariant());
134+
assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason());
135+
}
136+
137+
@Test
138+
public void fetchDoubleAsInt() throws Exception {
139+
// given
140+
final Map<String, FeatureFlag> flagMap = new HashMap<>();
141+
flagMap.put("integerFlag", INT_FLAG);
142+
143+
InProcessResolver inProcessResolver = getInProcessResolverWth(new MockStorage(flagMap), providerState -> {
144+
});
145+
146+
// when
147+
ProviderEvaluation<Double> providerEvaluation = inProcessResolver.doubleEvaluation("integerFlag", 0d,
148+
new ImmutableContext());
149+
150+
// then
151+
assertEquals(1d, providerEvaluation.getValue());
152+
assertEquals("one", providerEvaluation.getVariant());
153+
assertEquals(Reason.STATIC.toString(), providerEvaluation.getReason());
154+
}
155+
117156
@Test
118157
public void simpleIntResolving() throws Exception {
119158
// given
@@ -124,8 +163,8 @@ public void simpleIntResolving() throws Exception {
124163
});
125164

126165
// when
127-
ProviderEvaluation<Integer> providerEvaluation =
128-
inProcessResolver.integerEvaluation("integerFlag", 0, new ImmutableContext());
166+
ProviderEvaluation<Integer> providerEvaluation = inProcessResolver.integerEvaluation("integerFlag", 0,
167+
new ImmutableContext());
129168

130169
// then
131170
assertEquals(1, providerEvaluation.getValue());
@@ -147,8 +186,8 @@ public void simpleObjectResolving() throws Exception {
147186
typeDefault.put("date", "01.01.1990");
148187

149188
// when
150-
ProviderEvaluation<Value> providerEvaluation =
151-
inProcessResolver.objectEvaluation("objectFlag", Value.objectToValue(typeDefault), new ImmutableContext());
189+
ProviderEvaluation<Value> providerEvaluation = inProcessResolver.objectEvaluation("objectFlag",
190+
Value.objectToValue(typeDefault), new ImmutableContext());
152191

153192
// then
154193
Value value = providerEvaluation.getValue();
@@ -230,9 +269,8 @@ public void targetingMatchedEvaluationFlag() throws Exception {
230269
});
231270

232271
// when
233-
ProviderEvaluation<String> providerEvaluation =
234-
inProcessResolver.stringEvaluation("stringFlag", "loopAlg",
235-
new MutableContext().add("email", "[email protected]"));
272+
ProviderEvaluation<String> providerEvaluation = inProcessResolver.stringEvaluation("stringFlag", "loopAlg",
273+
new MutableContext().add("email", "[email protected]"));
236274

237275
// then
238276
assertEquals("binetAlg", providerEvaluation.getValue());
@@ -250,9 +288,8 @@ public void targetingUnmatchedEvaluationFlag() throws Exception {
250288
});
251289

252290
// when
253-
ProviderEvaluation<String> providerEvaluation =
254-
inProcessResolver.stringEvaluation("stringFlag", "loopAlg",
255-
new MutableContext().add("email", "[email protected]"));
291+
ProviderEvaluation<String> providerEvaluation = inProcessResolver.stringEvaluation("stringFlag", "loopAlg",
292+
new MutableContext().add("email", "[email protected]"));
256293

257294
// then
258295
assertEquals("loopAlg", providerEvaluation.getValue());
@@ -275,13 +312,13 @@ public void targetingErrorEvaluationFlag() throws Exception {
275312
});
276313
}
277314

278-
279315
private InProcessResolver getInProcessResolverWth(final MockStorage storage, Consumer<ProviderState> stateConsumer)
280316
throws NoSuchFieldException, IllegalAccessException {
281317
Field flagStore = InProcessResolver.class.getDeclaredField("flagStore");
282318
flagStore.setAccessible(true);
283319

284-
InProcessResolver resolver = new InProcessResolver(FlagdOptions.builder().deadline(1000).build(), stateConsumer);
320+
InProcessResolver resolver = new InProcessResolver(FlagdOptions.builder().deadline(1000).build(),
321+
stateConsumer);
285322
flagStore.set(resolver, storage);
286323

287324
return resolver;

0 commit comments

Comments
 (0)