Skip to content

Commit

Permalink
bugfix/1.0-final-fixbug-expt: check if sending to experiment (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsun0720 authored May 1, 2022
1 parent e536785 commit d6acf5f
Show file tree
Hide file tree
Showing 14 changed files with 75 additions and 19 deletions.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b4280218cd39bc02fb558bd8e4ee7efa
7f12f3beba700ff460e6abfe1023c037
Original file line number Diff line number Diff line change
@@ -1 +1 @@
05a5df22aa259f776f41df77193ab19712937f53
8afad1312216f72e32ca632a400c392ef6c8c01d
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0a768077917d309cbef0dd3e7713a368
d053acd6a8bb56f548908db75f36b20e
Original file line number Diff line number Diff line change
@@ -1 +1 @@
92fa2340edca34e151ffdcbaba978634a44fc5bd
ae86ec2c5ea1a115852c186f032e150c84b6d468
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ef631ba0bea93d6d90e7f70a51f6516b
2ce24f66fcd6c0de3266ca24122e0e79
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ce98eaf40dc2cf0a3e5d18febc3dd602784f4912
347e953f2393b52cb77c9885a1c9d70e8ad408d0
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@
<version>1.0</version>
<version>1.1</version>
</versions>
<lastUpdated>20220428163657</lastUpdated>
<lastUpdated>20220501074754</lastUpdated>
</versioning>
</metadata>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8bc9241f9d4c37ff08affad639963aab
3fa5a23d5d7e5cf53f23553b5dbed313
Original file line number Diff line number Diff line change
@@ -1 +1 @@
05da31cac057fe4e11ff7a07059ca12bce1e7dd9
68146dbd00679aa5aff62fb5343bd1fb2f611179
6 changes: 3 additions & 3 deletions src/main/java/co/featureflags/server/DataModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ public Integer getType() {
}

public Boolean isExptIncludeAllRules() {
return exptIncludeAllRules == null ? Boolean.FALSE : exptIncludeAllRules;
return exptIncludeAllRules;
}

public FeatureFlagBasicInfo getInfo() {
Expand Down Expand Up @@ -447,7 +447,7 @@ public String getStatus() {
}

public Boolean isDefaultRulePercentageRolloutsIncludedInExpt() {
return isDefaultRulePercentageRolloutsIncludedInExpt == null ? Boolean.FALSE : isDefaultRulePercentageRolloutsIncludedInExpt;
return isDefaultRulePercentageRolloutsIncludedInExpt;
}

public Date getLastUpdatedTime() {
Expand Down Expand Up @@ -505,7 +505,7 @@ public String getRuleName() {
}

public Boolean isIncludedInExpt() {
return isIncludedInExpt == null ? Boolean.FALSE : isIncludedInExpt;
return isIncludedInExpt;
}

public List<RuleItem> getRuleJsonContent() {
Expand Down
70 changes: 63 additions & 7 deletions src/main/java/co/featureflags/server/EvaluatorImp.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -88,15 +90,19 @@ private EvalResult matchFeatureFlagDisabledUserVariation(DataModel.FeatureFlag f
}

private EvalResult matchTargetedUserVariation(DataModel.FeatureFlag featureFlag, FFCUser user) {
return featureFlag.getTargets().stream().filter(target -> target.isTargeted(user.getKey())).findFirst().map(target -> EvalResult.of(target.getValueOption(), REASON_TARGET_MATCH, featureFlag.isExptIncludeAllRules(), featureFlag.getInfo().getKeyName(), featureFlag.getInfo().getName())).orElse(null);
return featureFlag.getTargets().stream().filter(target -> target.isTargeted(user.getKey())).findFirst().map(target -> EvalResult.of(target.getValueOption(), REASON_TARGET_MATCH, isSendToExperimentForTargetedUserVariation(featureFlag.isExptIncludeAllRules()), featureFlag.getInfo().getKeyName(), featureFlag.getInfo().getName())).orElse(null);
}

private EvalResult matchConditionedUserVariation(DataModel.FeatureFlag featureFlag, FFCUser user) {
DataModel.TargetRule targetRule = featureFlag.getRules().stream().filter(rule -> ifUserMatchRule(user, rule.getRuleJsonContent())).findFirst().orElse(null);
// optional flatmap can't infer inner type of collection
return targetRule == null ? null : getRollOutVariationOption(targetRule.getValueOptionsVariationRuleValues(), user, REASON_RULE_MATCH, targetRule.isIncludedInExpt(), featureFlag.getInfo().getKeyName(), featureFlag.getInfo().getName());


return targetRule == null ? null : getRollOutVariationOption(targetRule.getValueOptionsVariationRuleValues(),
user,
REASON_RULE_MATCH,
featureFlag.isExptIncludeAllRules(),
targetRule.isIncludedInExpt(),
featureFlag.getInfo().getKeyName(),
featureFlag.getInfo().getName());
}

private boolean ifUserMatchRule(FFCUser user, List<DataModel.RuleItem> clauses) {
Expand Down Expand Up @@ -240,11 +246,61 @@ private boolean oneOfClause(FFCUser user, DataModel.RuleItem clause) {
}

private EvalResult matchDefaultUserVariation(DataModel.FeatureFlag featureFlag, FFCUser user) {
return getRollOutVariationOption(featureFlag.getInfo().getDefaultRulePercentageRollouts(), user, REASON_FALLTHROUGH, featureFlag.getInfo().isDefaultRulePercentageRolloutsIncludedInExpt(), featureFlag.getInfo().getKeyName(), featureFlag.getInfo().getName());
return getRollOutVariationOption(featureFlag.getInfo().getDefaultRulePercentageRollouts(),
user,
REASON_FALLTHROUGH,
featureFlag.isExptIncludeAllRules(),
featureFlag.getInfo().isDefaultRulePercentageRolloutsIncludedInExpt(),
featureFlag.getInfo().getKeyName(),
featureFlag.getInfo().getName());
}

private EvalResult getRollOutVariationOption(Collection<DataModel.VariationOptionPercentageRollout> rollouts, FFCUser user, String reason, boolean sendToExperiment, String flagKeyName, String flagName) {
return rollouts.stream().filter(rollout -> VariationSplittingAlgorithm.ifKeyBelongsPercentage(user.getKey(), rollout.getRolloutPercentage())).findFirst().map(rollout -> EvalResult.of(rollout.getValueOption(), reason, sendToExperiment, flagKeyName, flagName)).orElse(null);
private EvalResult getRollOutVariationOption(Collection<DataModel.VariationOptionPercentageRollout> rollouts,
FFCUser user,
String reason,
boolean exptIncludeAllRules,
Boolean ruleIncludedInExperiment,
String flagKeyName,
String flagName) {
String newUserKey = Base64.getEncoder().encodeToString(user.getKey().getBytes());
return rollouts.stream()
.filter(rollout -> VariationSplittingAlgorithm.ifKeyBelongsPercentage(user.getKey(), rollout.getRolloutPercentage()))
.findFirst()
.map(rollout -> EvalResult.of(rollout.getValueOption(), reason, isSendToExperiment(newUserKey, rollout, exptIncludeAllRules, ruleIncludedInExperiment), flagKeyName, flagName))
.orElse(null);
}

private boolean isSendToExperimentForTargetedUserVariation(Boolean exptIncludeAllRules) {
return exptIncludeAllRules == null || exptIncludeAllRules.booleanValue();
}

private boolean isSendToExperiment(String userKey,
DataModel.VariationOptionPercentageRollout rollout,
Boolean exptIncludeAllRules,
Boolean ruleIncludedInExperiment) {
if (exptIncludeAllRules == null || exptIncludeAllRules.booleanValue()) {
return true;
}

if (ruleIncludedInExperiment == null || rollout.getExptRollout() == null) {
return true;
}

if (!ruleIncludedInExperiment) {
return false;
}

double sendToExperimentPercentage = rollout.getExptRollout();
double splittingPercentage = rollout.getRolloutPercentage().get(1) - rollout.getRolloutPercentage().get(0);
if (sendToExperimentPercentage == 0D || splittingPercentage == 0D) {
return false;
}

double upperBound = sendToExperimentPercentage / splittingPercentage;
if (upperBound > 1D) {
upperBound = 1D;
}
return VariationSplittingAlgorithm.ifKeyBelongsPercentage(userKey, Arrays.asList(0D, upperBound));
}


Expand Down

0 comments on commit d6acf5f

Please sign in to comment.