Support for object types

fixes #7
This commit is contained in:
Justin Abrahms 2022-05-28 00:39:42 -07:00
parent 9a8beadfd6
commit b34331a571
No known key found for this signature in database
GPG Key ID: 599E2E12011DC474
9 changed files with 76 additions and 19 deletions

View File

@ -5,4 +5,5 @@ public interface FeatureProvider {
ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
<T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options);
}

View File

@ -26,6 +26,12 @@ public interface Features {
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx);
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
// TODO: Object
<T> T getObjectValue(String key, T defaultValue);
<T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx);
<T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue);
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx);
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
}

View File

@ -32,4 +32,13 @@ public class NoOpProvider implements FeatureProvider {
.reason(Reason.DEFAULT)
.build();
}
@Override
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
return ProviderEvaluation.<T>builder()
.value(defaultValue)
.variant("Passed in default")
.reason(Reason.DEFAULT)
.build();
}
}

View File

@ -69,6 +69,8 @@ public class OpenFeatureClient implements Client {
providerEval = (ProviderEvaluation<T>) provider.getStringEvaluation(key, (String) defaultValue, invocationContext, options);
} else if (type == FlagValueType.INTEGER) {
providerEval = (ProviderEvaluation<T>) provider.getIntegerEvaluation(key, (Integer) defaultValue, invocationContext, options);
} else if (type == FlagValueType.OBJECT) {
providerEval = (ProviderEvaluation<T>) provider.getObjectEvaluation(key, defaultValue, invocationContext, options);
} else {
throw new GeneralError("Unknown flag type");
}
@ -215,4 +217,34 @@ public class OpenFeatureClient implements Client {
public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
return this.evaluateFlag(FlagValueType.INTEGER, key, defaultValue, ctx, options);
}
@Override
public <T> T getObjectValue(String key, T defaultValue) {
return getObjectDetails(key, defaultValue).getValue();
}
@Override
public <T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx) {
return getObjectDetails(key, defaultValue, ctx).getValue();
}
@Override
public <T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
return getObjectDetails(key, defaultValue, ctx, options).getValue();
}
@Override
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue) {
return getObjectDetails(key, defaultValue, null);
}
@Override
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx) {
return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
}
@Override
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
return this.evaluateFlag(FlagValueType.OBJECT, key, defaultValue, ctx, options);
}
}

View File

@ -21,4 +21,9 @@ public class AlwaysBrokenProvider implements FeatureProvider {
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
throw new NotImplementedException();
}
@Override
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
throw new NotImplementedException();
}
}

View File

@ -25,4 +25,11 @@ public class DoSomethingProvider implements FeatureProvider {
.value(defaultValue * 100)
.build();
}
@Override
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
return ProviderEvaluation.<T>builder()
.value(null)
.build();
}
}

View File

@ -99,17 +99,11 @@ public class FlagEvaluationSpecTests {
assertEquals(400, c.getIntegerValue(key, 4, new EvaluationContext()));
assertEquals(400, c.getIntegerValue(key, 4, new EvaluationContext(), FlagEvaluationOptions.builder().build()));
assertEquals(null, c.getObjectValue(key, new Node<Integer>()));
assertEquals(null, c.getObjectValue(key, new Node<Integer>(), new EvaluationContext()));
assertEquals(null, c.getObjectValue(key, new Node<Integer>(), new EvaluationContext(), FlagEvaluationOptions.builder().build()));
}
@Specification(spec="flag evaluation", number="1.7", text="The client MUST provide methods for flag evaluation, with" +
" parameters flag key (string, required), default value (boolean | number | string | structure, required), " +
"evaluation context (optional), and evaluation options (optional), which returns the flag value.")
@Disabled
@Test void value_flags__object() {
throw new NotImplementedException();
}
@Specification(spec="flag evaluation", number="1.9", text="The client MUST provide methods for detailed flag value " +
"evaluation with parameters flag key (string, required), default value (boolean | number | string | " +
"structure, required), evaluation context (optional), and evaluation options (optional), which returns an " +

View File

@ -1,7 +1,5 @@
package dev.openfeature.javasdk;
import dev.openfeature.javasdk.NoOpProvider;
import dev.openfeature.javasdk.ProviderEvaluation;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -25,4 +23,11 @@ public class NoOpProviderTest {
ProviderEvaluation<Integer> eval = p.getIntegerEvaluation("key", 4, null, null);
assertEquals(4, eval.getValue());
}
@Test void structure() {
NoOpProvider p = new NoOpProvider();
Node<Integer> node = new Node<Integer>();
ProviderEvaluation<Node> eval = p.getObjectEvaluation("key", node, null, null);
assertEquals(node, eval.getValue());
}
}

View File

@ -1,6 +1,5 @@
package dev.openfeature.javasdk;
import dev.openfeature.javasdk.*;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -15,6 +14,8 @@ public class ProviderSpecTests {
assertNotNull(p.getName());
}
@Specification(spec="provider", number="2.3.1", text="The feature provider interface MUST define methods for typed " +
"flag resolution, including boolean, numeric, string, and structure.")
@Specification(spec="provider", number="2.4", text="In cases of normal execution, the provider MUST populate the " +
"flag resolution structure's value field with the resolved flag value.")
@Specification(spec="provider", number="2.2", text="The feature provider interface MUST define methods to resolve " +
@ -32,6 +33,9 @@ public class ProviderSpecTests {
ProviderEvaluation<Boolean> boolean_result = p.getBooleanEvaluation("key", false, new EvaluationContext(), FlagEvaluationOptions.builder().build());
assertNotNull(boolean_result.getValue());
ProviderEvaluation<Node<Integer>> object_result = p.getObjectEvaluation("key", new Node<Integer>(), new EvaluationContext(), FlagEvaluationOptions.builder().build());
assertNotNull(boolean_result.getValue());
}
@Specification(spec="provider", number="2.6", text="The provider SHOULD populate the flag resolution structure's " +
@ -48,12 +52,6 @@ public class ProviderSpecTests {
assertNull(result.getErrorCode());
}
@Specification(spec="provider", number="2.3.1", text="The feature provider interface MUST define methods for typed " +
"flag resolution, including boolean, numeric, string, and structure.")
@Disabled("Don't yet support structures") @Test void structure_validation() {
}
@Specification(spec="provider", number="2.8", text="In cases of abnormal execution, the provider MUST indicate an " +
"error using the idioms of the implementation language, with an associated error code having possible " +
"values PROVIDER_NOT_READY, FLAG_NOT_FOUND, PARSE_ERROR, TYPE_MISMATCH, or GENERAL.")