Skip to content

Commit

Permalink
evaluate boolean updates
Browse files Browse the repository at this point in the history
Signed-off-by: liran2000 <[email protected]>
  • Loading branch information
liran2000 committed Mar 17, 2024
1 parent fdbe6b1 commit 0c87b3b
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 22 deletions.
6 changes: 2 additions & 4 deletions providers/statsig/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ StatsigProviderConfig statsigProviderConfig = StatsigProviderConfig.builder().sd
statsigProvider = new StatsigProvider(statsigProviderConfig);
OpenFeatureAPI.getInstance().setProviderAndWait(statsigProvider);
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
boolean featureEnabled = client.getBooleanValue(FLAG_NAME, false);
MutableContext evaluationContext = new MutableContext();
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand Down Expand Up @@ -73,7 +74,4 @@ As it is limited, evaluation context based tests are limited.
See [statsigProviderTest](./src/test/java/dev/openfeature/contrib/providers/statsig/StatsigProviderTest.java)
for more information.

## Known issues
- Gate BooleanEvaluation with default value true cannot fallback to true.
https://github.com/statsig-io/java-server-sdk/issues/22

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* Transformer from OpenFeature context to statsig User.
Expand All @@ -29,27 +30,30 @@ static StatsigUser transform(EvaluationContext ctx) {
Map<String, String> customMap = new HashMap<>();
ctx.asObjectMap().forEach((k, v) -> {
switch (k) {
case "targetingKey":
user.setUserID(Objects.toString(v, null));
break;
case CONTEXT_APP_VERSION:
user.setAppVersion(String.valueOf(v));
user.setAppVersion(Objects.toString(v, null));
break;
case CONTEXT_COUNTRY:
user.setCountry(String.valueOf(v));
user.setCountry(Objects.toString(v, null));
break;
case CONTEXT_EMAIL:
user.setEmail(String.valueOf(v));
user.setEmail(Objects.toString(v, null));
break;
case CONTEXT_IP:
user.setIp(String.valueOf(v));
user.setIp(Objects.toString(v, null));
break;
case CONTEXT_USER_AGENT:
user.setUserAgent(String.valueOf(v));
user.setUserAgent(Objects.toString(v, null));
break;
case CONTEXT_LOCALE:
user.setLocale(String.valueOf(v));
user.setLocale(Objects.toString(v, null));
break;
default:
if (!CONTEXT_PRIVATE_ATTRIBUTES.equals(k)) {
customMap.put(k, String.valueOf(v));
customMap.put(k, Objects.toString(v, null));
}
break;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dev.openfeature.contrib.providers.statsig;

import com.statsig.sdk.APIFeatureGate;
import com.statsig.sdk.DynamicConfig;
import com.statsig.sdk.EvaluationReason;
import com.statsig.sdk.Layer;
import com.statsig.sdk.Statsig;
import com.statsig.sdk.StatsigUser;
Expand Down Expand Up @@ -86,7 +88,16 @@ public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defa
verifyEvaluation();
StatsigUser user = ContextTransformer.transform(ctx);
Boolean evaluatedValue = defaultValue;
try {
Value featureConfigValue = ctx.getValue(FEATURE_CONFIG_KEY);
String reason = null;
if (featureConfigValue == null) {
APIFeatureGate featureGate = Statsig.getFeatureGate(user, key);
if (assumeFailure(featureGate)) {
reason = featureGate.getReason().getReason();
} else {
evaluatedValue = featureGate.getValue();
}
} else {
FeatureConfig featureConfig = parseFeatureConfig(ctx);
switch (featureConfig.getType()) {
case CONFIG:
Expand All @@ -100,17 +111,22 @@ public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defa
default:
break;
}
} catch (Exception e) {
log.debug("could not fetch feature config. checking gate {}.", key);
Future<Boolean> featureOn = Statsig.checkGateAsync(user, key);
evaluatedValue = featureOn.get();
}

return ProviderEvaluation.<Boolean>builder()
.value(evaluatedValue)
.reason(reason)
.build();
}

private boolean assumeFailure(APIFeatureGate featureGate) {
EvaluationReason reason = featureGate.getReason();
return EvaluationReason.DEFAULT.equals(reason) ||
EvaluationReason.UNINITIALIZED.equals(reason) ||
EvaluationReason.UNRECOGNIZED.equals(reason) ||
EvaluationReason.UNSUPPORTED.equals(reason);
}

@Override
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
verifyEvaluation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.statsig.sdk.StatsigOptions;
import com.statsig.sdk.StatsigUser;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.FlagEvaluationDetails;
import dev.openfeature.sdk.ImmutableContext;
import dev.openfeature.sdk.MutableContext;
import dev.openfeature.sdk.OpenFeatureAPI;
Expand Down Expand Up @@ -54,6 +55,7 @@ class StatsigProviderTest {
public static final Double DOUBLE_FLAG_VALUE = 3.14;
public static final String USERS_FLAG_NAME = "userIdMatching";
public static final String PROPERTIES_FLAG_NAME = "emailMatching";
public static final String TARGETING_KEY = "user1";
private static StatsigProvider statsigProvider;
private static Client client;

Expand Down Expand Up @@ -115,15 +117,24 @@ static void shutdown() {

@Test
void getBooleanEvaluation() {
assertEquals(true, statsigProvider.getBooleanEvaluation(FLAG_NAME, false, new ImmutableContext()).getValue());
assertEquals(true, client.getBooleanValue(FLAG_NAME, false));
assertEquals(false, statsigProvider.getBooleanEvaluation("non-existing", false, new ImmutableContext()).getValue());
assertEquals(false, client.getBooleanValue("non-existing", false));

// expected to succeed when https://github.com/statsig-io/java-server-sdk/issues/22 is resolved and adopted
// assertEquals(true, client.getBooleanValue("non-existing", true));

// TODO issue
FlagEvaluationDetails<Boolean> flagEvaluationDetails = client.getBooleanDetails(FLAG_NAME, false, new ImmutableContext());
assertEquals(false, flagEvaluationDetails.getValue());
// TODO add reason


MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
assertEquals(true, statsigProvider.getBooleanEvaluation(FLAG_NAME, false, evaluationContext).getValue());
assertEquals(true, client.getBooleanValue(FLAG_NAME, false, evaluationContext));
assertEquals(false, statsigProvider.getBooleanEvaluation("non-existing", false, evaluationContext).getValue());
assertEquals(false, client.getBooleanValue("non-existing", false, evaluationContext));

// expected to succeed when https://github.com/statsig-io/java-server-sdk/issues/22 is resolved and adopted
assertEquals(true, client.getBooleanValue("non-existing", true));

MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand All @@ -135,6 +146,7 @@ void getBooleanEvaluation() {
@Test
void getStringEvaluation() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand All @@ -149,6 +161,7 @@ void getStringEvaluation() {
@Test
void getObjectConfigEvaluation() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "object-config-name");
Expand All @@ -164,6 +177,7 @@ void getObjectConfigEvaluation() {
@Test
void getObjectLayerEvaluation() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "LAYER");
featureConfig.add("name", "layer-name");
Expand All @@ -180,6 +194,7 @@ void getObjectLayerEvaluation() {
@Test
void getIntegerEvaluation() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand All @@ -197,6 +212,7 @@ void getIntegerEvaluation() {
@Test
void getDoubleEvaluation() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand All @@ -214,6 +230,7 @@ void getDoubleEvaluation() {
@Test
void getBooleanEvaluationByUser() {
MutableContext evaluationContext = new MutableContext();
evaluationContext.setTargetingKey(TARGETING_KEY);
MutableContext featureConfig = new MutableContext();
featureConfig.add("type", "CONFIG");
featureConfig.add("name", "product");
Expand Down

0 comments on commit 0c87b3b

Please sign in to comment.