diff --git a/client/pom.xml b/client/pom.xml
index 3c1162ee..f3506732 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -168,7 +168,7 @@
org.apache.httpcomponents.client5
httpclient5
- 5.4.3
+ 5.4.4
com.google.code.gson
diff --git a/client/src/main/java/io/split/client/CacheUpdaterService.java b/client/src/main/java/io/split/client/CacheUpdaterService.java
index 6d5f8a06..63b42663 100644
--- a/client/src/main/java/io/split/client/CacheUpdaterService.java
+++ b/client/src/main/java/io/split/client/CacheUpdaterService.java
@@ -51,7 +51,7 @@ public void updateCache(Map map) {
String treatment = conditions.size() > 0 ? Treatments.CONTROL : localhostSplit.treatment;
configurations.put(localhostSplit.treatment, localhostSplit.config);
- split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations, new HashSet<>(), true);
+ split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations, new HashSet<>(), true, null);
parsedSplits.removeIf(parsedSplit -> parsedSplit.feature().equals(splitName));
parsedSplits.add(split);
}
diff --git a/client/src/main/java/io/split/client/api/SplitView.java b/client/src/main/java/io/split/client/api/SplitView.java
index a7701327..cc217fe1 100644
--- a/client/src/main/java/io/split/client/api/SplitView.java
+++ b/client/src/main/java/io/split/client/api/SplitView.java
@@ -1,6 +1,7 @@
package io.split.client.api;
import io.split.client.dtos.Partition;
+import io.split.client.dtos.Prerequisites;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
@@ -27,6 +28,7 @@ public class SplitView {
public List sets;
public String defaultTreatment;
public boolean impressionsDisabled;
+ public List prerequisites;
public static SplitView fromParsedSplit(ParsedSplit parsedSplit) {
SplitView splitView = new SplitView();
@@ -48,6 +50,8 @@ public static SplitView fromParsedSplit(ParsedSplit parsedSplit) {
splitView.treatments = new ArrayList(treatments);
splitView.configs = parsedSplit.configurations() == null? Collections.emptyMap() : parsedSplit.configurations() ;
splitView.impressionsDisabled = parsedSplit.impressionsDisabled();
+ splitView.prerequisites = parsedSplit.prerequisitesMatcher() != null ?
+ parsedSplit.prerequisitesMatcher().getPrerequisites(): new ArrayList<>();
return splitView;
}
diff --git a/client/src/main/java/io/split/client/dtos/Prerequisites.java b/client/src/main/java/io/split/client/dtos/Prerequisites.java
new file mode 100644
index 00000000..644cb5fc
--- /dev/null
+++ b/client/src/main/java/io/split/client/dtos/Prerequisites.java
@@ -0,0 +1,12 @@
+package io.split.client.dtos;
+
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+
+public class Prerequisites {
+ @SerializedName("n")
+ public String featureFlagName;
+ @SerializedName("ts")
+ public List treatments;
+}
diff --git a/client/src/main/java/io/split/client/dtos/Split.java b/client/src/main/java/io/split/client/dtos/Split.java
index 866300d3..1b9a01e3 100644
--- a/client/src/main/java/io/split/client/dtos/Split.java
+++ b/client/src/main/java/io/split/client/dtos/Split.java
@@ -19,6 +19,7 @@ public class Split {
public Map configurations;
public HashSet sets;
public Boolean impressionsDisabled = null;
+ public List prerequisites;
@Override
public String toString() {
diff --git a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
index a97902eb..6d31952c 100644
--- a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
+++ b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
@@ -86,8 +86,8 @@ private List getFeatureFlagNamesByFlagSets(List flagSets) {
private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bucketingKey, ParsedSplit parsedSplit, Map attributes) throws ChangeNumberExceptionWrapper {
try {
+ String config = getConfig(parsedSplit, parsedSplit.defaultTreatment());
if (parsedSplit.killed()) {
- String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null;
return new TreatmentLabelAndChangeNumber(
parsedSplit.defaultTreatment(),
Labels.KILLED,
@@ -96,6 +96,17 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
parsedSplit.impressionsDisabled());
}
+ String bk = getBucketingKey(bucketingKey, matchingKey);
+
+ if (!parsedSplit.prerequisitesMatcher().match(matchingKey, bk, attributes, _evaluationContext)) {
+ return new TreatmentLabelAndChangeNumber(
+ parsedSplit.defaultTreatment(),
+ Labels.PREREQUISITES_NOT_MET,
+ parsedSplit.changeNumber(),
+ config,
+ parsedSplit.impressionsDisabled());
+ }
+
/*
* There are three parts to a single Feature flag: 1) Whitelists 2) Traffic Allocation
* 3) Rollout. The flag inRollout is there to understand when we move into the Rollout
@@ -104,11 +115,9 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
*/
boolean inRollout = false;
- String bk = (bucketingKey == null) ? matchingKey : bucketingKey;
-
for (ParsedCondition parsedCondition : parsedSplit.parsedConditions()) {
- if (!inRollout && parsedCondition.conditionType() == ConditionType.ROLLOUT) {
+ if (checkRollout(inRollout, parsedCondition)) {
if (parsedSplit.trafficAllocation() < 100) {
// if the traffic allocation is 100%, no need to do anything special.
@@ -116,8 +125,7 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
if (bucket > parsedSplit.trafficAllocation()) {
// out of split
- String config = parsedSplit.configurations() != null ?
- parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null;
+ config = getConfig(parsedSplit, parsedSplit.defaultTreatment());
return new TreatmentLabelAndChangeNumber(parsedSplit.defaultTreatment(), Labels.NOT_IN_SPLIT,
parsedSplit.changeNumber(), config, parsedSplit.impressionsDisabled());
}
@@ -128,7 +136,7 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
if (parsedCondition.matcher().match(matchingKey, bucketingKey, attributes, _evaluationContext)) {
String treatment = Splitter.getTreatment(bk, parsedSplit.seed(), parsedCondition.partitions(), parsedSplit.algo());
- String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(treatment) : null;
+ config = getConfig(parsedSplit, treatment);
return new TreatmentLabelAndChangeNumber(
treatment,
parsedCondition.label(),
@@ -138,7 +146,8 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
}
}
- String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null;
+ config = getConfig(parsedSplit, parsedSplit.defaultTreatment());
+
return new TreatmentLabelAndChangeNumber(
parsedSplit.defaultTreatment(),
Labels.DEFAULT_RULE,
@@ -150,13 +159,24 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu
}
}
+ private boolean checkRollout(boolean inRollout, ParsedCondition parsedCondition) {
+ return (!inRollout && parsedCondition.conditionType() == ConditionType.ROLLOUT);
+ }
+
+ private String getBucketingKey(String bucketingKey, String matchingKey) {
+ return (bucketingKey == null) ? matchingKey : bucketingKey;
+ }
+
+ private String getConfig(ParsedSplit parsedSplit, String returnedTreatment) {
+ return parsedSplit.configurations() != null ? parsedSplit.configurations().get(returnedTreatment) : null;
+ }
+
private TreatmentLabelAndChangeNumber evaluateParsedSplit(String matchingKey, String bucketingKey, Map attributes,
ParsedSplit parsedSplit) {
try {
if (parsedSplit == null) {
return new TreatmentLabelAndChangeNumber(Treatments.CONTROL, Labels.DEFINITION_NOT_FOUND);
}
-
return getTreatment(matchingKey, bucketingKey, parsedSplit, attributes);
} catch (ChangeNumberExceptionWrapper e) {
_log.error("Evaluator Exception", e.wrappedException());
diff --git a/client/src/main/java/io/split/engine/evaluator/Labels.java b/client/src/main/java/io/split/engine/evaluator/Labels.java
index ac5a465a..9bda16a8 100644
--- a/client/src/main/java/io/split/engine/evaluator/Labels.java
+++ b/client/src/main/java/io/split/engine/evaluator/Labels.java
@@ -7,4 +7,5 @@ public class Labels {
public static final String DEFINITION_NOT_FOUND = "definition not found";
public static final String EXCEPTION = "exception";
public static final String UNSUPPORTED_MATCHER = "targeting rule type unsupported by sdk";
+ public static final String PREREQUISITES_NOT_MET = "prerequisites not met";
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/engine/experiments/ParsedSplit.java b/client/src/main/java/io/split/engine/experiments/ParsedSplit.java
index a4d52d6a..e202474f 100644
--- a/client/src/main/java/io/split/engine/experiments/ParsedSplit.java
+++ b/client/src/main/java/io/split/engine/experiments/ParsedSplit.java
@@ -2,6 +2,7 @@
import com.google.common.collect.ImmutableList;
import io.split.engine.matchers.AttributeMatcher;
+import io.split.engine.matchers.PrerequisitesMatcher;
import io.split.engine.matchers.RuleBasedSegmentMatcher;
import io.split.engine.matchers.UserDefinedSegmentMatcher;
@@ -34,6 +35,7 @@ public class ParsedSplit {
private final Map _configurations;
private final HashSet _flagSets;
private final boolean _impressionsDisabled;
+ private PrerequisitesMatcher _prerequisitesMatcher;
public static ParsedSplit createParsedSplitForTests(
String feature,
@@ -45,7 +47,8 @@ public static ParsedSplit createParsedSplitForTests(
long changeNumber,
int algo,
HashSet flagSets,
- boolean impressionsDisabled
+ boolean impressionsDisabled,
+ PrerequisitesMatcher prerequisitesMatcher
) {
return new ParsedSplit(
feature,
@@ -60,7 +63,8 @@ public static ParsedSplit createParsedSplitForTests(
algo,
null,
flagSets,
- impressionsDisabled
+ impressionsDisabled,
+ prerequisitesMatcher
);
}
@@ -75,7 +79,8 @@ public static ParsedSplit createParsedSplitForTests(
int algo,
Map configurations,
HashSet flagSets,
- boolean impressionsDisabled
+ boolean impressionsDisabled,
+ PrerequisitesMatcher prerequisitesMatcher
) {
return new ParsedSplit(
feature,
@@ -90,7 +95,8 @@ public static ParsedSplit createParsedSplitForTests(
algo,
configurations,
flagSets,
- impressionsDisabled
+ impressionsDisabled,
+ prerequisitesMatcher
);
}
@@ -107,7 +113,8 @@ public ParsedSplit(
int algo,
Map configurations,
HashSet flagSets,
- boolean impressionsDisabled
+ boolean impressionsDisabled,
+ PrerequisitesMatcher prerequisitesMatcher
) {
_split = feature;
_seed = seed;
@@ -125,6 +132,7 @@ public ParsedSplit(
_configurations = configurations;
_flagSets = flagSets;
_impressionsDisabled = impressionsDisabled;
+ _prerequisitesMatcher = prerequisitesMatcher;
}
public String feature() {
@@ -171,6 +179,7 @@ public Map configurations() {
public boolean impressionsDisabled() {
return _impressionsDisabled;
}
+ public PrerequisitesMatcher prerequisitesMatcher() { return _prerequisitesMatcher; }
@Override
public int hashCode() {
@@ -195,17 +204,20 @@ public boolean equals(Object obj) {
if (!(obj instanceof ParsedSplit)) return false;
ParsedSplit other = (ParsedSplit) obj;
+ boolean trafficTypeCond = _trafficTypeName == null ? other._trafficTypeName == null : _trafficTypeName.equals(other._trafficTypeName);
+ boolean configCond = _configurations == null ? other._configurations == null : _configurations.equals(other._configurations);
return _split.equals(other._split)
&& _seed == other._seed
&& _killed == other._killed
&& _defaultTreatment.equals(other._defaultTreatment)
&& _parsedCondition.equals(other._parsedCondition)
- && _trafficTypeName == null ? other._trafficTypeName == null : _trafficTypeName.equals(other._trafficTypeName)
+ && trafficTypeCond
&& _changeNumber == other._changeNumber
&& _algo == other._algo
- && _configurations == null ? other._configurations == null : _configurations.equals(other._configurations)
- && _impressionsDisabled == other._impressionsDisabled;
+ && configCond
+ && _impressionsDisabled == other._impressionsDisabled
+ && _prerequisitesMatcher == other._prerequisitesMatcher;
}
@Override
@@ -231,6 +243,9 @@ public String toString() {
bldr.append(_configurations);
bldr.append(", impressionsDisabled:");
bldr.append(_impressionsDisabled);
+ bldr.append(", prerequisites:");
+ bldr.append(_prerequisitesMatcher);
+
return bldr.toString();
}
diff --git a/client/src/main/java/io/split/engine/experiments/SplitParser.java b/client/src/main/java/io/split/engine/experiments/SplitParser.java
index 414e5dfe..5771c9ae 100644
--- a/client/src/main/java/io/split/engine/experiments/SplitParser.java
+++ b/client/src/main/java/io/split/engine/experiments/SplitParser.java
@@ -6,6 +6,7 @@
import io.split.client.dtos.Partition;
import io.split.client.dtos.Split;
import io.split.engine.matchers.CombiningMatcher;
+import io.split.engine.matchers.PrerequisitesMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -68,6 +69,7 @@ private ParsedSplit parseWithoutExceptionHandling(Split split) {
split.algo,
split.configurations,
split.sets,
- split.impressionsDisabled);
+ split.impressionsDisabled,
+ new PrerequisitesMatcher(split.prerequisites));
}
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/engine/matchers/PrerequisitesMatcher.java b/client/src/main/java/io/split/engine/matchers/PrerequisitesMatcher.java
new file mode 100644
index 00000000..12278449
--- /dev/null
+++ b/client/src/main/java/io/split/engine/matchers/PrerequisitesMatcher.java
@@ -0,0 +1,71 @@
+package io.split.engine.matchers;
+
+import io.split.client.dtos.Prerequisites;
+import io.split.engine.evaluator.EvaluationContext;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class PrerequisitesMatcher implements Matcher {
+ private List _prerequisites;
+
+ public PrerequisitesMatcher(List prerequisites) {
+ _prerequisites = prerequisites;
+ }
+
+ public List getPrerequisites() { return _prerequisites; }
+
+ @Override
+ public boolean match(Object matchValue, String bucketingKey, Map attributes, EvaluationContext evaluationContext) {
+ if (matchValue == null) {
+ return false;
+ }
+
+ if (!(matchValue instanceof String)) {
+ return false;
+ }
+
+ if (_prerequisites == null) {
+ return true;
+ }
+
+ for (Prerequisites prerequisites : _prerequisites) {
+ String treatment = evaluationContext.getEvaluator().evaluateFeature((String) matchValue, bucketingKey,
+ prerequisites.featureFlagName, attributes). treatment;
+ if (!prerequisites.treatments.contains(treatment)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder bldr = new StringBuilder();
+ bldr.append("prerequisites: ");
+ if (this._prerequisites != null) {
+ bldr.append(this._prerequisites.stream().map(pr -> pr.featureFlagName + " " +
+ pr.treatments.toString()).map(Object::toString).collect(Collectors.joining(", ")));
+ }
+ return bldr.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ PrerequisitesMatcher that = (PrerequisitesMatcher) o;
+
+ return Objects.equals(_prerequisites, that._prerequisites);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = _prerequisites != null ? _prerequisites.hashCode() : 0;
+ result = 31 * result + (_prerequisites != null ? _prerequisites.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java
index 57c63b99..83e9f3b7 100644
--- a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java
+++ b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java
@@ -131,7 +131,8 @@ public void kill(String splitName, String defaultTreatment, long changeNumber) {
parsedSplit.algo(),
parsedSplit.configurations(),
parsedSplit.flagSets(),
- parsedSplit.impressionsDisabled()
+ parsedSplit.impressionsDisabled(),
+ parsedSplit.prerequisitesMatcher()
);
_concurrentMap.put(splitName, updatedSplit);
diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java
index 1e27e96e..5b56708d 100644
--- a/client/src/test/java/io/split/client/SplitClientImplTest.java
+++ b/client/src/test/java/io/split/client/SplitClientImplTest.java
@@ -11,6 +11,12 @@
import io.split.client.impressions.ImpressionsManager;
import io.split.client.interceptors.FlagSetsFilter;
import io.split.client.interceptors.FlagSetsFilterImpl;
+import io.split.engine.matchers.PrerequisitesMatcher;
+import io.split.engine.matchers.CombiningMatcher;
+import io.split.engine.matchers.EqualToMatcher;
+import io.split.engine.matchers.GreaterThanOrEqualToMatcher;
+import io.split.engine.matchers.AllKeysMatcher;
+import io.split.engine.matchers.DependencyMatcher;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SplitCacheConsumer;
@@ -18,11 +24,6 @@
import io.split.engine.SDKReadinessGates;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
-import io.split.engine.matchers.AllKeysMatcher;
-import io.split.engine.matchers.CombiningMatcher;
-import io.split.engine.matchers.DependencyMatcher;
-import io.split.engine.matchers.EqualToMatcher;
-import io.split.engine.matchers.GreaterThanOrEqualToMatcher;
import io.split.engine.matchers.collections.ContainsAnyOfSetMatcher;
import io.split.engine.matchers.strings.WhitelistMatcher;
import io.split.grammar.Treatments;
@@ -83,7 +84,7 @@ public void nullKeyResultsInControl() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -113,7 +114,7 @@ public void nullTestResultsInControl() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, null);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -167,7 +168,7 @@ public void works() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -206,7 +207,7 @@ public void worksNullConfig() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -242,7 +243,7 @@ public void worksAndHasConfig() {
Map configurations = new HashMap<>();
configurations.put(Treatments.ON, "{\"size\" : 30}");
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, configurations, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -279,7 +280,7 @@ public void lastConditionIsAlwaysDefault() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("adil@codigo.com"))), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -319,7 +320,7 @@ public void lastConditionIsAlwaysDefaultButWithTreatment() {
configurations.put(Treatments.OFF, "{\"size\" : 30}");
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- "user", 1, 1, configurations, new HashSet<>(), true);
+ "user", 1, 1, configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -354,7 +355,7 @@ public void multipleConditionsWork() {
ParsedCondition trevor_is_always_shown = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("trevor@codigo.com"))), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(adil_is_always_on, pato_is_never_shown, trevor_is_always_shown);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -389,7 +390,7 @@ public void killedTestAlwaysGoesToDefault() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("adil@codigo.com"))), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -429,7 +430,7 @@ public void killedTestAlwaysGoesToDefaultHasConfig() {
configurations.put(Treatments.OFF, "{\"size\" : 30}");
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions,
- "user", 1, 1, configurations, new HashSet<>(), true);
+ "user", 1, 1, configurations, new HashSet<>(), true, null);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -462,11 +463,11 @@ public void dependencyMatcherOn() {
ParsedCondition parent_is_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition(Treatments.ON, 100)));
List parent_conditions = Lists.newArrayList(parent_is_on);
- ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher(parent, Lists.newArrayList(Treatments.ON))), Lists.newArrayList(partition(Treatments.ON, 100)));
List dependent_conditions = Lists.newArrayList(dependent_needs_parent);
- ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -497,11 +498,11 @@ public void dependencyMatcherOff() {
ParsedCondition parent_is_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition(Treatments.ON, 100)));
List parent_conditions = Lists.newArrayList(parent_is_on);
- ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher(parent, Lists.newArrayList(Treatments.OFF))), Lists.newArrayList(partition(Treatments.ON, 100)));
List dependent_conditions = Lists.newArrayList(dependent_needs_parent);
- ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -531,7 +532,7 @@ public void dependencyMatcherControl() {
ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher("not-exists", Lists.newArrayList(Treatments.OFF))), Lists.newArrayList(partition(Treatments.OFF, 100)));
List dependent_conditions = Lists.newArrayList(dependent_needs_parent);
- ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.ON, dependent_conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.ON, dependent_conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -561,7 +562,7 @@ public void attributesWork() {
ParsedCondition users_with_age_greater_than_10_are_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new GreaterThanOrEqualToMatcher(10, DataType.NUMBER)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(adil_is_always_on, users_with_age_greater_than_10_are_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -596,7 +597,7 @@ public void attributesWork2() {
ParsedCondition age_equal_to_0_should_be_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new EqualToMatcher(0, DataType.NUMBER)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -632,7 +633,7 @@ public void attributesGreaterThanNegativeNumber() {
ParsedCondition age_equal_to_0_should_be_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new EqualToMatcher(-20, DataType.NUMBER)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -670,7 +671,7 @@ public void attributesForSets() {
ParsedCondition any_of_set = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("products", new ContainsAnyOfSetMatcher(Lists.newArrayList("sms", "video"))), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(any_of_set);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -714,7 +715,7 @@ public void labelsArePopulated() {
);
List conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
@@ -817,7 +818,7 @@ private void trafficAllocation(String key, int trafficAllocation, int trafficAll
List conditions = Lists.newArrayList(whitelistCondition, rollOutToEveryone);
ParsedSplit parsedSplit = new ParsedSplit(test, 123, false, Treatments.OFF, conditions, null, 1,
- trafficAllocation, trafficAllocationSeed, 1, null, new HashSet<>(), true);
+ trafficAllocation, trafficAllocationSeed, 1, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -869,7 +870,7 @@ public void notInTrafficAllocationDefaultConfig() {
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = new ParsedSplit(test, 123, false, Treatments.OFF, conditions, null,
- 1, trafficAllocation, trafficAllocationSeed, 1, configurations, new HashSet<>(), true);
+ 1, trafficAllocation, trafficAllocationSeed, 1, configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -916,7 +917,7 @@ public void matchingBucketingKeysWork() {
ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(aijaz_should_match);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -953,7 +954,7 @@ public void matchingBucketingKeysByFlagSetWork() {
ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(aijaz_should_match);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -994,7 +995,7 @@ public void matchingBucketingKeysByFlagSetsWork() {
ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(aijaz_should_match);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1037,7 +1038,7 @@ public void impressionMetadataIsPropagated() {
);
List conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1229,7 +1230,7 @@ public void getTreatmentWithInvalidKeys() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1388,7 +1389,7 @@ public void clientCannotPerformActionsWhenDestroyed() throws InterruptedExceptio
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1445,7 +1446,7 @@ public void worksAndHasConfigTryKetTreatmentWithKey() {
configurations.put(Treatments.ON, "{\"size\" : 30}");
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(), true);
+ null, 1, 1, configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1490,7 +1491,7 @@ public void worksAndHasConfigByFlagSetTryKetTreatmentWithKey() {
configurations.put(Treatments.ON, "{\"size\" : 30}");
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true);
+ null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1539,7 +1540,7 @@ public void worksAndHasConfigByFlagSetsTryKetTreatmentWithKey() {
configurations.put(Treatments.ON, "{\"size\" : 30}");
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true);
+ null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1582,7 +1583,7 @@ public void blockUntilReadyException() throws TimeoutException, InterruptedExcep
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1612,7 +1613,7 @@ public void nullKeyResultsInControlGetTreatments() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map splits = new HashMap<>();
splits.put(test, parsedSplit);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
@@ -1643,7 +1644,7 @@ public void nullSplitsResultsInEmptyGetTreatments() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map splits = new HashMap<>();
splits.put(test, parsedSplit);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
@@ -1699,7 +1700,7 @@ public void getTreatmentsWorks() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map splits = new HashMap<>();
splits.put(test, parsedSplit);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
@@ -1731,7 +1732,7 @@ public void emptySplitsResultsInNullGetTreatments() {
String test = "test1";
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map splits = new HashMap<>();
splits.put(test, parsedSplit);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
@@ -1789,9 +1790,9 @@ public void worksTreatments() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
ParsedSplit parsedSplit2 = ParsedSplit.createParsedSplitForTests(test2, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(), true);
+ null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
parsedSplits.put(test2, parsedSplit2);
@@ -1830,7 +1831,7 @@ public void worksOneControlTreatments() {
ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
@@ -1877,7 +1878,7 @@ public void treatmentsWorksAndHasConfig() {
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(), true);
+ null, 1, 1, configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
@@ -1914,7 +1915,7 @@ public void testTreatmentsByFlagSet() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1961,7 +1962,7 @@ public void testTreatmentsByFlagSetInvalid() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -1992,9 +1993,9 @@ public void testTreatmentsByFlagSets() {
Lists.newArrayList(partition("on", 100)));
List conditions = Lists.newArrayList(rollOutToEveryone);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true, new PrerequisitesMatcher(null));
ParsedSplit parsedSplit2 = ParsedSplit.createParsedSplitForTests(test2, 123, false, Treatments.OFF, conditions,
- null, 1, 1, new HashSet<>(Arrays.asList("set3", "set4")), true);
+ null, 1, 1, new HashSet<>(Arrays.asList("set3", "set4")), true, new PrerequisitesMatcher(null));
SDKReadinessGates gates = mock(SDKReadinessGates.class);
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
@@ -2054,7 +2055,7 @@ public void treatmentsWorksAndHasConfigFlagSet() {
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true);
+ null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
@@ -2111,7 +2112,7 @@ public void treatmentsWorksAndHasConfigFlagSets() {
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions,
- null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true);
+ null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
@@ -2158,7 +2159,7 @@ public void impressionPropertiesTest() {
);
List conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
- ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(Arrays.asList("set")), true);
+ ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(Arrays.asList("set")), true, new PrerequisitesMatcher(null));
Map parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);
diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
index 82f65602..bba82452 100644
--- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
+++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
@@ -528,7 +528,7 @@ public void splitClientMultiFactory() throws Exception {
.until(() -> "on_whitelist".equals(client2.getTreatment("admin", "push_test")));
Awaitility.await()
- .atMost(50L, TimeUnit.SECONDS)
+ .atMost(100L, TimeUnit.SECONDS)
.until(() -> "on_whitelist".equals(client3.getTreatment("admin", "push_test")));
Awaitility.await()
@@ -1101,6 +1101,80 @@ public MockResponse dispatch(RecordedRequest request) {
Assert.assertTrue(check2);
}
+ @Test
+ public void getTreatmentWithPrerequisites() throws Exception {
+ String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_prereq.json")), StandardCharsets.UTF_8);
+ List allRequests = new ArrayList<>();
+ Dispatcher dispatcher = new Dispatcher() {
+ @Override
+ public MockResponse dispatch(RecordedRequest request) {
+ allRequests.add(request);
+ switch (request.getPath()) {
+ case "/api/splitChanges?s=1.3&since=-1&rbSince=-1":
+ return new MockResponse().setResponseCode(200).setBody(splits);
+ case "/api/splitChanges?s=1.3&since=1585948850109&rbSince=1585948850109":
+ return new MockResponse().setResponseCode(200).setBody("{\"ff\":{\"d\": [], \"s\":1585948850109, \"t\":1585948850109},\"rbs\":{\"d\":[],\"t\":1585948850109,\"s\":1585948850109}}");
+ case "/api/segmentChanges/segment-test?since=-1":
+ return new MockResponse().setResponseCode(200).setBody("{\"name\":\"segment-test\",\"added\":[\"user-1\"],\"removed\":[],\"since\":-1,\"till\":-1}");
+ case "/api/testImpressions/bulk":
+ return new MockResponse().setResponseCode(200);
+ case "/api/testImpressions/count":
+ return new MockResponse().setResponseCode(200);
+ case "/v1/keys/ss":
+ return new MockResponse().setResponseCode(200);
+ case "/v1/metrics/usage":
+ return new MockResponse().setResponseCode(200);
+ case "/v1/metrics/config":
+ return new MockResponse().setResponseCode(200);
+ }
+ return new MockResponse().setResponseCode(404);
+ }
+ };
+
+ MockWebServer splitServer = new MockWebServer();
+ splitServer.setDispatcher(dispatcher);
+ splitServer.start();
+ String serverURL = String.format("http://%s:%s", splitServer.getHostName(), splitServer.getPort());
+
+ SplitClientConfig config = SplitClientConfig.builder()
+ .setBlockUntilReadyTimeout(10000)
+ .endpoint(serverURL, serverURL)
+ .telemetryURL(serverURL + "/v1")
+ .authServiceURL(String.format("%s/api/auth/enabled", serverURL))
+ .streamingEnabled(false)
+ .featuresRefreshRate(5)
+ .impressionsMode(ImpressionsManager.Mode.DEBUG)
+ .build();
+
+ SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config);
+ SplitClient client = factory.client();
+ client.blockUntilReady();
+
+ Assert.assertEquals("on", client.getTreatment("bilal@split.io", "test_prereq", new HashMap() {{
+ put("email", "bilal@@split.io");
+ }}));
+ Assert.assertEquals("def_treatment", client.getTreatment("bilal@split.io", "test_prereq"));
+ Assert.assertEquals("def_treatment", client.getTreatment("mauro@split.io", "test_prereq", new HashMap() {{
+ put("email", "mauro@@split.io");
+ }}));
+ Assert.assertEquals("on", client.getTreatment("pato@split.io", "test_prereq", new HashMap() {{
+ put("email", "pato@@split.io");
+ }}));
+
+ Assert.assertEquals("on_whitelist", client.getTreatment("bilal@split.io", "prereq_chain", new HashMap() {{
+ put("email", "bilal@@split.io");
+ }}));
+ Assert.assertEquals("on", client.getTreatment("pato@split.io", "prereq_chain", new HashMap() {{
+ put("email", "pato@@split.io");
+ }}));
+ Assert.assertEquals("on_default", client.getTreatment("mauro@split.io", "prereq_chain", new HashMap() {{
+ put("email", "mauro@@split.io");
+ }}));
+
+ client.destroy();
+ splitServer.shutdown();
+ }
+
private SSEMockServer buildSSEMockServer(SSEMockServer.SseEventQueue eventQueue) {
return new SSEMockServer(eventQueue, (token, version, channel) -> {
if (!"1.1".equals(version)) {
diff --git a/client/src/test/java/io/split/client/SplitManagerImplTest.java b/client/src/test/java/io/split/client/SplitManagerImplTest.java
index 4843bd81..f3c04454 100644
--- a/client/src/test/java/io/split/client/SplitManagerImplTest.java
+++ b/client/src/test/java/io/split/client/SplitManagerImplTest.java
@@ -3,6 +3,7 @@
import com.google.common.collect.Lists;
import io.split.client.api.SplitView;
+import io.split.client.dtos.Prerequisites;
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import io.split.client.utils.Json;
@@ -13,6 +14,7 @@
import io.split.engine.experiments.SplitParser;
import io.split.engine.matchers.AllKeysMatcher;
import io.split.engine.matchers.CombiningMatcher;
+import io.split.engine.matchers.PrerequisitesMatcher;
import io.split.grammar.Treatments;
import io.split.storages.SplitCacheConsumer;
import io.split.telemetry.storage.InMemoryTelemetryStorage;
@@ -66,7 +68,11 @@ public void splitCallWithExistentSplit() {
String existent = "existent";
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
- ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), false);
+ Prerequisites prereq = new Prerequisites();
+ prereq.featureFlagName = "feature1";
+ prereq.treatments = Lists.newArrayList("on");
+ ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), false,
+ new PrerequisitesMatcher(Lists.newArrayList(prereq)));
when(splitCacheConsumer.get(existent)).thenReturn(response);
SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer,
@@ -81,6 +87,7 @@ public void splitCallWithExistentSplit() {
Assert.assertEquals("off", theOne.treatments.get(0));
Assert.assertEquals(0, theOne.configs.size());
Assert.assertEquals("off", theOne.defaultTreatment);
+ Assert.assertEquals(Lists.newArrayList(prereq), theOne.prerequisites);
}
@Test
@@ -92,7 +99,7 @@ public void splitCallWithExistentSplitAndConfigs() {
Map configurations = new HashMap<>();
configurations.put(Treatments.OFF, "{\"size\" : 30}");
- ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, configurations, new HashSet<>(), false);
+ ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, configurations, new HashSet<>(), false, null);
when(splitCacheConsumer.get(existent)).thenReturn(response);
SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer,
@@ -128,7 +135,7 @@ public void splitsCallWithSplit() {
List parsedSplits = Lists.newArrayList();
SDKReadinessGates gates = mock(SDKReadinessGates.class);
when(gates.isSDKReady()).thenReturn(false);
- ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), false);
+ ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), false, null);
parsedSplits.add(response);
when(splitCacheConsumer.getAll()).thenReturn(parsedSplits);
@@ -203,7 +210,7 @@ public void splitCallWithExistentSets() {
String existent = "existent";
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off",
- Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(Arrays.asList("set1", "set2", "set3")), false);
+ Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(Arrays.asList("set1", "set2", "set3")), false, null);
when(splitCacheConsumer.get(existent)).thenReturn(response);
SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer,
@@ -218,7 +225,7 @@ public void splitCallWithEmptySets() {
String existent = "existent";
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off",
- Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, null, false);
+ Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, null, false, null);
when(splitCacheConsumer.get(existent)).thenReturn(response);
SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer,
diff --git a/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java b/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java
index cb92bc17..5cc6d01d 100644
--- a/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java
+++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java
@@ -11,6 +11,7 @@
import io.split.engine.experiments.ParsedSplit;
import io.split.engine.matchers.AttributeMatcher;
import io.split.engine.matchers.CombiningMatcher;
+import io.split.engine.matchers.PrerequisitesMatcher;
import io.split.engine.matchers.RuleBasedSegmentMatcher;
import io.split.engine.matchers.strings.EndsWithAnyOfMatcher;
import io.split.engine.matchers.strings.WhitelistMatcher;
@@ -200,11 +201,11 @@ private Evaluator buildEvaluatorAndLoadCache(boolean killed, int trafficAllocati
List conditions = Lists.newArrayList(whitelistCondition, rollOutCondition);
List conditionsForRBS = Lists.newArrayList(ruleBasedSegmentCondition, rollOutCondition);
- ParsedSplit parsedSplit1 = new ParsedSplit("split_1", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366551, 100, 0, 2, null, new HashSet<>(), true);
- ParsedSplit parsedSplit2 = new ParsedSplit("split_2", 0, true, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366552, 100, 0, 2, null, new HashSet<>(), true);
- ParsedSplit parsedSplit3 = new ParsedSplit("split_3", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>(), true);
- ParsedSplit parsedSplit4 = new ParsedSplit("split_test", 0, killed, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366555, trafficAllocation, 0, 2, null, new HashSet<>(), true);
- ParsedSplit parsedSplit5 = new ParsedSplit("split_5", 0, false, DEFAULT_TREATMENT_VALUE, conditionsForRBS, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>(), true);
+ ParsedSplit parsedSplit1 = new ParsedSplit("split_1", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366551, 100, 0, 2, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
+ ParsedSplit parsedSplit2 = new ParsedSplit("split_2", 0, true, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366552, 100, 0, 2, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
+ ParsedSplit parsedSplit3 = new ParsedSplit("split_3", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
+ ParsedSplit parsedSplit4 = new ParsedSplit("split_test", 0, killed, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366555, trafficAllocation, 0, 2, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
+ ParsedSplit parsedSplit5 = new ParsedSplit("split_5", 0, false, DEFAULT_TREATMENT_VALUE, conditionsForRBS, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>(), true, new PrerequisitesMatcher(null));
splitCache.putMany(Stream.of(parsedSplit1, parsedSplit2, parsedSplit3, parsedSplit4, parsedSplit5).collect(Collectors.toList()));
ParsedRuleBasedSegment parsedRuleBasedSegment = new ParsedRuleBasedSegment("sample_rule_based_segment",
diff --git a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java
index 2fe2d83e..cf166bd2 100644
--- a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java
+++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java
@@ -2,9 +2,12 @@
import io.split.client.dtos.ConditionType;
import io.split.client.dtos.Partition;
+import io.split.client.dtos.Prerequisites;
+import io.split.client.utils.Json;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
import io.split.engine.matchers.CombiningMatcher;
+import io.split.engine.matchers.PrerequisitesMatcher;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SplitCacheConsumer;
@@ -68,7 +71,7 @@ public void evaluateWhenSplitNameDoesNotExistReturnControl() {
@Test
public void evaluateWhenSplitIsKilledReturnDefaultTreatment() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, true, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, true, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true, new PrerequisitesMatcher(null));
Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
@@ -80,7 +83,7 @@ public void evaluateWhenSplitIsKilledReturnDefaultTreatment() {
@Test
public void evaluateWithoutConditionsReturnDefaultTreatment() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true, new PrerequisitesMatcher(null));
Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
@@ -99,7 +102,7 @@ public void evaluateWithRollOutConditionBucketIsBiggerTrafficAllocationReturnDef
ParsedCondition condition = new ParsedCondition(ConditionType.ROLLOUT, _matcher,_partitions, TEST_LABEL_VALUE);
_conditions.add(condition);
- ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 10, 12, 2, _configurations, new HashSet<>(), true);
+ ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 10, 12, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
Mockito.when(condition.matcher().match(MATCHING_KEY, BUCKETING_KEY, null, _evaluationContext)).thenReturn(true);
@@ -120,7 +123,7 @@ public void evaluateWithRollOutConditionTrafficAllocationIsBiggerBucketReturnTre
ParsedCondition condition = new ParsedCondition(ConditionType.ROLLOUT, _matcher, _partitions, TEST_LABEL_VALUE);
_conditions.add(condition);
- ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true);
+ ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(true);
@@ -141,7 +144,7 @@ public void evaluateWithWhitelistConditionReturnTreatment() {
ParsedCondition condition = new ParsedCondition(ConditionType.WHITELIST, _matcher, _partitions, "test whitelist label");
_conditions.add(condition);
- ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true);
+ ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(true);
@@ -155,7 +158,7 @@ public void evaluateWithWhitelistConditionReturnTreatment() {
@Test
public void evaluateWithSets() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true, new PrerequisitesMatcher(null));
List sets = new ArrayList<>(Arrays.asList("set1", "empty_set"));
Map> flagSets = new HashMap<>();
flagSets.put("set1", new HashSet<>(Arrays.asList(SPLIT_NAME)));
@@ -176,7 +179,7 @@ public void evaluateWithSets() {
@Test
public void evaluateWithSetsNotHaveFlags() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true, new PrerequisitesMatcher(null));
List sets = new ArrayList<>(Arrays.asList("set2"));
Map> flagSets = new HashMap<>();
Mockito.when(_splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagSets);
@@ -186,4 +189,41 @@ public void evaluateWithSetsNotHaveFlags() {
Map result = _evaluator.evaluateFeaturesByFlagSets(MATCHING_KEY, BUCKETING_KEY, sets, null);
Assert.assertTrue(result.isEmpty());
}
+
+ @Test
+ public void evaluateWithPrerequisites() {
+ Partition partition = new Partition();
+ partition.treatment = TREATMENT_VALUE;
+ partition.size = 100;
+ _partitions.add(partition);
+ ParsedCondition condition = new ParsedCondition(ConditionType.WHITELIST, _matcher, _partitions, "test whitelist label");
+ _conditions.add(condition);
+ List prerequisites = Arrays.asList(Json.fromJson("{\"n\": \"split1\", \"ts\": [\"" + TREATMENT_VALUE + "\"]}", Prerequisites.class));
+
+ ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(prerequisites));
+ ParsedSplit split1 = new ParsedSplit("split1", 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(null));
+
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
+ Mockito.when(_splitCacheConsumer.get("split1")).thenReturn(split1);
+ Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(true);
+
+ EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals(TREATMENT_VALUE, result.treatment);
+ assertEquals("test whitelist label", result.label);
+ assertEquals(CHANGE_NUMBER, result.changeNumber);
+
+ Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(false);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals(DEFAULT_TREATMENT_VALUE, result.treatment);
+ assertEquals(Labels.PREREQUISITES_NOT_MET, result.label);
+ assertEquals(CHANGE_NUMBER, result.changeNumber);
+
+ // if split is killed, label should be killed.
+ split = new ParsedSplit(SPLIT_NAME, 0, true, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true, new PrerequisitesMatcher(prerequisites));
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals(DEFAULT_TREATMENT_VALUE, result.treatment);
+ assertEquals(Labels.KILLED, result.label);
+ assertEquals(CHANGE_NUMBER, result.changeNumber);
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java
index f2cc0cc4..a6c2468a 100644
--- a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java
+++ b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java
@@ -88,7 +88,7 @@ private void works(long startingChangeNumber) throws InterruptedException {
ParsedCondition expectedParsedCondition = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(ConditionsTestUtil.partition("on", 10)));
List expectedListOfMatcherAndSplits = Lists.newArrayList(expectedParsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("" + cache.getChangeNumber(), (int) cache.getChangeNumber(), false, Treatments.OFF, expectedListOfMatcherAndSplits, null, cache.getChangeNumber(), 1, new HashSet<>(), true);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("" + cache.getChangeNumber(), (int) cache.getChangeNumber(), false, Treatments.OFF, expectedListOfMatcherAndSplits, null, cache.getChangeNumber(), 1, new HashSet<>(), true, null);
ParsedSplit actual = cache.get("" + cache.getChangeNumber());
Thread.sleep(1000);
diff --git a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java
index 5b581983..4676a8c3 100644
--- a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java
+++ b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java
@@ -11,11 +11,7 @@
import io.split.client.dtos.Split;
import io.split.client.dtos.SplitChange;
import io.split.client.dtos.Status;
-import io.split.storages.SegmentCache;
-import io.split.storages.memory.SegmentCacheInMemoryImpl;
-import io.split.client.utils.Json;
-import io.split.engine.evaluator.Labels;
-import io.split.engine.ConditionsTestUtil;
+import io.split.engine.matchers.PrerequisitesMatcher;
import io.split.engine.matchers.AttributeMatcher;
import io.split.engine.matchers.BetweenMatcher;
import io.split.engine.matchers.CombiningMatcher;
@@ -23,6 +19,11 @@
import io.split.engine.matchers.GreaterThanOrEqualToMatcher;
import io.split.engine.matchers.LessThanOrEqualToMatcher;
import io.split.engine.matchers.UserDefinedSegmentMatcher;
+import io.split.storages.SegmentCache;
+import io.split.storages.memory.SegmentCacheInMemoryImpl;
+import io.split.client.utils.Json;
+import io.split.engine.evaluator.Labels;
+import io.split.engine.ConditionsTestUtil;
import io.split.engine.matchers.collections.ContainsAllOfSetMatcher;
import io.split.engine.matchers.collections.ContainsAnyOfSetMatcher;
import io.split.engine.matchers.collections.EqualToSetMatcher;
@@ -94,11 +95,12 @@ public void works() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
assertTrue(expected.hashCode() != 0);
assertTrue(expected.equals(expected));
+ Assert.assertEquals(expected.toString(), actual.toString());
}
@Test
@@ -137,9 +139,23 @@ public void worksWithConfig() {
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF,
- listOfMatcherAndSplits, "user", 1, 1, configurations, new HashSet<>(), false);
+ listOfMatcherAndSplits, "user", 1, 1, configurations, new HashSet<>(), false, new PrerequisitesMatcher(null));
+
+ Assert.assertEquals(actual.parsedConditions(), expected.parsedConditions());
+ Assert.assertEquals(actual.feature(), expected.feature());
+ Assert.assertEquals(actual.changeNumber(), expected.changeNumber());
+ Assert.assertEquals(actual.defaultTreatment(), expected.defaultTreatment());
+ Assert.assertEquals(actual.killed(), expected.killed());
+ Assert.assertEquals(actual.impressionsDisabled(), expected.impressionsDisabled());
+ Assert.assertEquals(null, actual.flagSets());
+ Assert.assertEquals(actual.algo(), expected.algo());
+ Assert.assertEquals(actual.seed(), expected.seed());
+ Assert.assertEquals(actual.trafficAllocation(), expected.trafficAllocation());
+ Assert.assertEquals(actual.trafficAllocationSeed(), expected.trafficAllocationSeed());
+ Assert.assertEquals(actual.getSegmentsNames(), expected.getSegmentsNames());
+ Assert.assertEquals(actual.getRuleBasedSegmentsNames(), expected.getRuleBasedSegmentsNames());
+ Assert.assertEquals(actual.prerequisitesMatcher().toString(), expected.prerequisitesMatcher().toString());
- Assert.assertEquals(actual, expected);
Assert.assertEquals(actual.configurations().get("on"), configurations.get("on"));
}
@@ -173,12 +189,12 @@ public void worksForTwoConditions() {
ParsedSplit actual = parser.parse(split);
ParsedCondition parsedCondition1 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), fullyRollout);
- ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), turnOff);
+ ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(SALES_PEOPLE)), turnOff);
List listOfParsedConditions = Lists.newArrayList(parsedCondition1, parsedCondition2);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfParsedConditions, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfParsedConditions, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -245,9 +261,9 @@ public void worksWithAttributes() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -278,9 +294,9 @@ public void lessThanOrEqualTo() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -310,9 +326,9 @@ public void equalTo() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -341,9 +357,9 @@ public void equalToNegativeNumber() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -377,9 +393,9 @@ public void between() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
- Assert.assertEquals(actual, expected);
+ compareParsed(actual, expected);
}
@Test
@@ -693,9 +709,27 @@ public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("splitName", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), false);
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("splitName", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
+
+ compareParsed(actual, expected);
+ }
- Assert.assertEquals(actual, expected);
+ private void compareParsed(ParsedSplit actual, ParsedSplit expected) {
+ Assert.assertEquals(actual.getRuleBasedSegmentsNames(), expected.getRuleBasedSegmentsNames());
+ Assert.assertEquals(actual.seed(), expected.seed());
+ Assert.assertEquals(actual.algo(), expected.algo());
+ Assert.assertEquals(actual.trafficAllocationSeed(), expected.trafficAllocationSeed());
+ Assert.assertEquals(actual.flagSets(), expected.flagSets());
+ Assert.assertEquals(actual.parsedConditions(), expected.parsedConditions());
+ Assert.assertEquals(actual.trafficAllocation(), expected.trafficAllocation());
+ Assert.assertEquals(actual.getSegmentsNames(), expected.getSegmentsNames());
+ Assert.assertEquals(actual.impressionsDisabled(), expected.impressionsDisabled());
+ Assert.assertEquals(actual.killed(), expected.killed());
+ Assert.assertEquals(actual.defaultTreatment(), expected.defaultTreatment());
+ Assert.assertEquals(actual.changeNumber(), expected.changeNumber());
+ Assert.assertEquals(actual.feature(), expected.feature());
+ Assert.assertEquals(actual.configurations(), expected.configurations());
+ Assert.assertEquals(actual.prerequisitesMatcher().toString(), expected.prerequisitesMatcher().toString());
}
private Split makeSplit(String name, int seed, List conditions, long changeNumber) {
@@ -715,6 +749,7 @@ private Split makeSplit(String name, int seed, List conditions, long
split.changeNumber = changeNumber;
split.algo = 1;
split.configurations = configurations;
+ split.prerequisites = new ArrayList<>();
return split;
}
diff --git a/client/src/test/java/io/split/engine/matchers/PrerequisitesMatcherTest.java b/client/src/test/java/io/split/engine/matchers/PrerequisitesMatcherTest.java
new file mode 100644
index 00000000..4fe92d04
--- /dev/null
+++ b/client/src/test/java/io/split/engine/matchers/PrerequisitesMatcherTest.java
@@ -0,0 +1,55 @@
+package io.split.engine.matchers;
+
+import io.split.client.dtos.Prerequisites;
+import io.split.client.utils.Json;
+import io.split.engine.evaluator.EvaluationContext;
+import io.split.engine.evaluator.Evaluator;
+import io.split.engine.evaluator.EvaluatorImp;
+import io.split.storages.RuleBasedSegmentCache;
+import io.split.storages.SegmentCache;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for Prerequisites matcher
+ */
+public class PrerequisitesMatcherTest {
+
+ @Test
+ public void works() {
+ Evaluator evaluator = Mockito.mock(Evaluator.class);
+ EvaluationContext evaluationContext = new EvaluationContext(evaluator, Mockito.mock(SegmentCache.class), Mockito.mock(RuleBasedSegmentCache.class));
+ List prerequisites = Arrays.asList(Json.fromJson("{\"n\": \"split1\", \"ts\": [\"on\"]}", Prerequisites.class), Json.fromJson("{\"n\": \"split2\", \"ts\": [\"off\"]}", Prerequisites.class));
+ PrerequisitesMatcher matcher = new PrerequisitesMatcher(prerequisites);
+ Assert.assertEquals("prerequisites: split1 [on], split2 [off]", matcher.toString());
+ PrerequisitesMatcher matcher2 = new PrerequisitesMatcher(prerequisites);
+ Assert.assertTrue(matcher.equals(matcher2));
+ Assert.assertTrue(matcher.hashCode() != 0);
+
+ Mockito.when(evaluator.evaluateFeature("user", "user", "split1", null)).thenReturn(new EvaluatorImp.TreatmentLabelAndChangeNumber("on", ""));
+ Mockito.when(evaluator.evaluateFeature("user", "user", "split2", null)).thenReturn(new EvaluatorImp.TreatmentLabelAndChangeNumber("off", ""));
+ Assert.assertTrue(matcher.match("user", "user", null, evaluationContext));
+
+ Mockito.when(evaluator.evaluateFeature("user", "user", "split2", null)).thenReturn(new EvaluatorImp.TreatmentLabelAndChangeNumber("on", ""));
+ Assert.assertFalse(matcher.match("user", "user", null, evaluationContext));
+ }
+
+ @Test
+ public void invalidParams() {
+ Evaluator evaluator = Mockito.mock(Evaluator.class);
+ EvaluationContext evaluationContext = new EvaluationContext(evaluator, Mockito.mock(SegmentCache.class), Mockito.mock(RuleBasedSegmentCache.class));
+
+ List prerequisites = Arrays.asList(Json.fromJson("{\"n\": \"split1\", \"ts\": [\"on\"]}", Prerequisites.class), Json.fromJson("{\"n\": \"split2\", \"ts\": [\"off\"]}", Prerequisites.class));
+ PrerequisitesMatcher matcher = new PrerequisitesMatcher(prerequisites);
+ Mockito.when(evaluator.evaluateFeature("user", "user", "split1", null)).thenReturn(new EvaluatorImp.TreatmentLabelAndChangeNumber("on", ""));
+ Assert.assertFalse(matcher.match(null, null, null, evaluationContext));
+ Assert.assertFalse(matcher.match(123, null, null, evaluationContext));
+
+ matcher = new PrerequisitesMatcher(null);
+ Assert.assertFalse(matcher.match(123, null, null, evaluationContext));
+ }
+}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java
index d2079f1b..5589d71d 100644
--- a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java
+++ b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java
@@ -139,10 +139,10 @@ public void getMany() {
@Test
public void trafficTypesExist() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true);
- ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true);
- ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, null, true);
- ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, null, true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true, null);
+ ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true, null);
+ ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, null, true, null);
+ ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, null, true, null);
_cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList()));
assertTrue(_cache.trafficTypeExists("tt_2"));
@@ -163,10 +163,10 @@ public void testSegmentNames() {
ParsedCondition parsedCondition1 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), fullyRollout);
ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES+"2")), turnOff);
- ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt", 123, 2, null, true);
- ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt", 123, 2, null, true);
- ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt_2", 123, 2, null, true);
- ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt_3", 123, 2, null, true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt", 123, 2, null, true, null);
+ ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt", 123, 2, null, true, null);
+ ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt_2", 123, 2, null, true, null);
+ ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt_3", 123, 2, null, true, null);
_cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList()));
@@ -178,19 +178,19 @@ public void testSegmentNames() {
}
private ParsedSplit getParsedSplitWithFlagSetsSameStorage(String splitName) {
- return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2")), true);
+ return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2")), true, null);
}
private ParsedSplit getParsedSplitWithFlagSetsNotSameStorage(String splitName) {
- return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set3")), true);
+ return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set3")), true, null);
}
private ParsedSplit getParsedSplitFlagSetsNull(String splitName) {
- return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true);
+ return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true, null);
}
private ParsedSplit getParsedSplitFlagSetsEmpty(String splitName) {
- return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true);
+ return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true, null);
}
@Test
@@ -204,7 +204,7 @@ public void testPutMany() {
@Test
public void testIncreaseTrafficType() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true, null);
_cache.putMany(Stream.of(split).collect(Collectors.toList()));
_cache.increaseTrafficType("tt_2");
assertTrue(_cache.trafficTypeExists("tt_2"));
@@ -212,7 +212,7 @@ public void testIncreaseTrafficType() {
@Test
public void testDecreaseTrafficType() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true, null);
_cache.putMany(Stream.of(split).collect(Collectors.toList()));
_cache.decreaseTrafficType("tt");
assertFalse(_cache.trafficTypeExists("tt_2"));
@@ -220,10 +220,10 @@ public void testDecreaseTrafficType() {
@Test
public void testGetNamesByFlagSets() {
- ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2", "set3")), true);
- ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1")), true);
- ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, new HashSet<>(Arrays.asList("set4")), true);
- ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, new HashSet<>(Arrays.asList("set2")), true);
+ ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2", "set3")), true, null);
+ ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1")), true, null);
+ ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, new HashSet<>(Arrays.asList("set4")), true, null);
+ ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, new HashSet<>(Arrays.asList("set2")), true, null);
_cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList()));
Map> namesByFlagSets = _cache.getNamesByFlagSets(new ArrayList<>(Arrays.asList("set1", "set2", "set3")));
diff --git a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomSplitAdapterConsumerTest.java b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomSplitAdapterConsumerTest.java
index 26114711..d12badc0 100644
--- a/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomSplitAdapterConsumerTest.java
+++ b/client/src/test/java/io/split/storages/pluggable/adapters/UserCustomSplitAdapterConsumerTest.java
@@ -76,9 +76,23 @@ public void testGetSplit() {
SplitParser splitParser = new SplitParser();
Split split = getSplit(SPLIT_NAME);
Mockito.when(_userStorageWrapper.get(PrefixAdapter.buildSplitKey(SPLIT_NAME))).thenReturn(getSplitAsJson(split));
- ParsedSplit result = _userCustomSplitAdapterConsumer.get(SPLIT_NAME);
+ ParsedSplit actual = _userCustomSplitAdapterConsumer.get(SPLIT_NAME);
ParsedSplit expected = splitParser.parse(split);
- Assert.assertEquals(expected, result);
+ Assert.assertEquals(actual.getRuleBasedSegmentsNames(), expected.getRuleBasedSegmentsNames());
+ Assert.assertEquals(actual.seed(), expected.seed());
+ Assert.assertEquals(actual.algo(), expected.algo());
+ Assert.assertEquals(actual.trafficAllocationSeed(), expected.trafficAllocationSeed());
+ Assert.assertEquals(actual.flagSets(), expected.flagSets());
+ Assert.assertEquals(actual.parsedConditions(), expected.parsedConditions());
+ Assert.assertEquals(actual.trafficAllocation(), expected.trafficAllocation());
+ Assert.assertEquals(actual.getSegmentsNames(), expected.getSegmentsNames());
+ Assert.assertEquals(actual.impressionsDisabled(), expected.impressionsDisabled());
+ Assert.assertEquals(actual.killed(), expected.killed());
+ Assert.assertEquals(actual.defaultTreatment(), expected.defaultTreatment());
+ Assert.assertEquals(actual.changeNumber(), expected.changeNumber());
+ Assert.assertEquals(actual.feature(), expected.feature());
+ Assert.assertEquals(actual.configurations(), expected.configurations());
+ Assert.assertEquals(actual.prerequisitesMatcher().toString(), expected.prerequisitesMatcher().toString());
}
@Test
diff --git a/client/src/test/resources/splits_prereq.json b/client/src/test/resources/splits_prereq.json
new file mode 100644
index 00000000..5efa7fed
--- /dev/null
+++ b/client/src/test/resources/splits_prereq.json
@@ -0,0 +1,293 @@
+{"ff": {
+ "d": [
+ {
+ "trafficTypeName": "user",
+ "name": "test_prereq",
+ "prerequisites": [
+ { "n": "feature_segment", "ts": ["off", "def_test"] },
+ { "n": "rbs_flag", "ts": ["on"] }
+ ],
+ "trafficAllocation": 100,
+ "trafficAllocationSeed": 1582960494,
+ "seed": 1842944006,
+ "status": "ACTIVE",
+ "killed": false,
+ "defaultTreatment": "def_treatment",
+ "changeNumber": 1582741588594,
+ "algo": 2,
+ "configurations": {},
+ "conditions": [
+ {
+ "conditionType": "ROLLOUT",
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": {
+ "trafficType": "user",
+ "attribute": null
+ },
+ "matcherType": "ALL_KEYS",
+ "negate": false,
+ "userDefinedSegmentMatcherData": null,
+ "whitelistMatcherData": null,
+ "unaryNumericMatcherData": null,
+ "betweenMatcherData": null,
+ "booleanMatcherData": null,
+ "dependencyMatcherData": null,
+ "stringMatcherData": null
+ }
+ ]
+ },
+ "partitions": [
+ {
+ "treatment": "on",
+ "size": 100
+ },
+ {
+ "treatment": "off",
+ "size": 0
+ }
+ ],
+ "label": "default rule"
+ }
+ ]
+ },
+ {
+ "name":"feature_segment",
+ "trafficTypeId":"u",
+ "trafficTypeName":"User",
+ "trafficAllocation": 100,
+ "trafficAllocationSeed": 1582960494,
+ "seed":-1177551240,
+ "status":"ACTIVE",
+ "killed":false,
+ "defaultTreatment":"def_test",
+ "changeNumber": 1582741588594,
+ "algo": 2,
+ "configurations": {},
+ "conditions":[
+ {
+ "matcherGroup":{
+ "combiner":"AND",
+ "matchers":[
+ {
+ "matcherType":"IN_SEGMENT",
+ "negate":false,
+ "userDefinedSegmentMatcherData":{
+ "segmentName":"segment-test"
+ },
+ "whitelistMatcherData":null
+ }
+ ]
+ },
+ "partitions":[
+ {
+ "treatment":"on",
+ "size":100
+ },
+ {
+ "treatment":"off",
+ "size":0
+ }
+ ],
+ "label": "default label"
+ }
+ ]
+ },
+ {
+ "changeNumber": 10,
+ "trafficTypeName": "user",
+ "name": "rbs_flag",
+ "trafficAllocation": 100,
+ "trafficAllocationSeed": 1828377380,
+ "seed": -286617921,
+ "status": "ACTIVE",
+ "killed": false,
+ "defaultTreatment": "off",
+ "algo": 2,
+ "conditions": [
+ {
+ "conditionType": "ROLLOUT",
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": {
+ "trafficType": "user"
+ },
+ "matcherType": "IN_RULE_BASED_SEGMENT",
+ "negate": false,
+ "userDefinedSegmentMatcherData": {
+ "segmentName": "sample_rule_based_segment"
+ }
+ }
+ ]
+ },
+ "partitions": [
+ {
+ "treatment": "on",
+ "size": 100
+ },
+ {
+ "treatment": "off",
+ "size": 0
+ }
+ ],
+ "label": "in rule based segment sample_rule_based_segment"
+ },
+ {
+ "conditionType": "ROLLOUT",
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": {
+ "trafficType": "user"
+ },
+ "matcherType": "ALL_KEYS",
+ "negate": false
+ }
+ ]
+ },
+ "partitions": [
+ {
+ "treatment": "on",
+ "size": 0
+ },
+ {
+ "treatment": "off",
+ "size": 100
+ }
+ ],
+ "label": "default rule"
+ }
+ ],
+ "configurations": {},
+ "sets": [],
+ "impressionsDisabled": false
+ },
+ {
+ "trafficTypeName": "user",
+ "name": "prereq_chain",
+ "prerequisites": [
+ { "n": "test_prereq", "ts": ["on"] }
+ ],
+ "trafficAllocation": 100,
+ "trafficAllocationSeed": -2092979940,
+ "seed": 105482719,
+ "status": "ACTIVE",
+ "killed": false,
+ "defaultTreatment": "on_default",
+ "changeNumber": 1585948850109,
+ "algo": 2,
+ "configurations": {},
+ "conditions": [
+ {
+ "conditionType": "WHITELIST",
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": null,
+ "matcherType": "WHITELIST",
+ "negate": false,
+ "userDefinedSegmentMatcherData": null,
+ "whitelistMatcherData": {
+ "whitelist": [
+ "bilal@split.io"
+ ]
+ },
+ "unaryNumericMatcherData": null,
+ "betweenMatcherData": null,
+ "booleanMatcherData": null,
+ "dependencyMatcherData": null,
+ "stringMatcherData": null
+ }
+ ]
+ },
+ "partitions": [
+ {
+ "treatment": "on_whitelist",
+ "size": 100
+ }
+ ],
+ "label": "whitelisted"
+ },
+ {
+ "conditionType": "ROLLOUT",
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": {
+ "trafficType": "user",
+ "attribute": null
+ },
+ "matcherType": "ALL_KEYS",
+ "negate": false,
+ "userDefinedSegmentMatcherData": null,
+ "whitelistMatcherData": null,
+ "unaryNumericMatcherData": null,
+ "betweenMatcherData": null,
+ "booleanMatcherData": null,
+ "dependencyMatcherData": null,
+ "stringMatcherData": null
+ }
+ ]
+ },
+ "partitions": [
+ {
+ "treatment": "on",
+ "size": 100
+ },
+ {
+ "treatment": "off",
+ "size": 0
+ },
+ {
+ "treatment": "V1",
+ "size": 0
+ }
+ ],
+ "label": "default rule"
+ }
+ ]
+ }
+ ],
+ "s": -1,
+ "t": 1585948850109
+}, "rbs":{"d": [
+ {
+ "changeNumber": 5,
+ "name": "sample_rule_based_segment",
+ "status": "ACTIVE",
+ "trafficTypeName": "user",
+ "excluded":{
+ "keys":["mauro@split.io","gaston@split.io"],
+ "segments":[]
+ },
+ "conditions": [
+ {
+ "matcherGroup": {
+ "combiner": "AND",
+ "matchers": [
+ {
+ "keySelector": {
+ "trafficType": "user",
+ "attribute": "email"
+ },
+ "matcherType": "ENDS_WITH",
+ "negate": false,
+ "whitelistMatcherData": {
+ "whitelist": [
+ "@split.io"
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }], "s": -1, "t": 1585948850109}
+}