diff --git a/CHANGES.txt b/CHANGES.txt
index 4dbbb9ee4..1001aa2e6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,6 @@
+4.18.0 (Sep 12, 2025)
+- Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs.
+
4.17.0 (Aug 22, 2025)
- Added a maximum size payload when posting unique keys telemetry in batches
- Added ProxyConfiguration parameter to support proxies, including Harness Forward Proxy, allowing also for more secured authentication options: MTLS, Bearer token and user/password authentication. Read more in our docs.
diff --git a/client/pom.xml b/client/pom.xml
index 768f79e9f..4db1af756 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -5,9 +5,9 @@
io.split.client
java-client-parent
- 4.17.0
+ 4.18.0
- 4.17.0
+ 4.18.0
java-client
jar
Java Client
diff --git a/client/src/main/java/io/split/client/SplitClientConfig.java b/client/src/main/java/io/split/client/SplitClientConfig.java
index f32b9b091..e6e7a70af 100644
--- a/client/src/main/java/io/split/client/SplitClientConfig.java
+++ b/client/src/main/java/io/split/client/SplitClientConfig.java
@@ -1,5 +1,7 @@
package io.split.client;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.dtos.ProxyConfiguration;
import io.split.client.impressions.ImpressionListener;
import io.split.client.impressions.ImpressionsManager;
@@ -16,10 +18,13 @@
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ThreadFactory;
import java.io.InputStream;
+import static io.split.inputValidation.FallbackTreatmentValidator.isValidByFlagTreatment;
+import static io.split.inputValidation.FallbackTreatmentValidator.isValidTreatment;
import static io.split.inputValidation.FlagSetsValidator.cleanup;
/**
@@ -91,6 +96,7 @@ private HttpScheme() {
private final CustomStorageWrapper _customStorageWrapper;
private final StorageMode _storageMode;
private final ThreadFactory _threadFactory;
+ private final FallbackTreatmentsConfiguration _fallbackTreatments;
// Proxy configs
private final ProxyConfiguration _proxyConfiguration;
@@ -163,7 +169,8 @@ private SplitClientConfig(String endpoint,
HashSet flagSetsFilter,
int invalidSets,
CustomHeaderDecorator customHeaderDecorator,
- CustomHttpModule alternativeHTTPModule) {
+ CustomHttpModule alternativeHTTPModule,
+ FallbackTreatmentsConfiguration fallbackTreatments) {
_endpoint = endpoint;
_eventsEndpoint = eventsEndpoint;
_featuresRefreshRate = pollForFeatureChangesEveryNSeconds;
@@ -218,6 +225,7 @@ private SplitClientConfig(String endpoint,
_invalidSets = invalidSets;
_customHeaderDecorator = customHeaderDecorator;
_alternativeHTTPModule = alternativeHTTPModule;
+ _fallbackTreatments = fallbackTreatments;
Properties props = new Properties();
try {
@@ -436,6 +444,8 @@ public boolean isSdkEndpointOverridden() {
public CustomHttpModule alternativeHTTPModule() { return _alternativeHTTPModule; }
+ public FallbackTreatmentsConfiguration fallbackTreatments() { return _fallbackTreatments; }
+
public static final class Builder {
private String _endpoint = SDK_ENDPOINT;
private boolean _endpointSet = false;
@@ -494,6 +504,7 @@ public static final class Builder {
private int _invalidSetsCount = 0;
private CustomHeaderDecorator _customHeaderDecorator = null;
private CustomHttpModule _alternativeHTTPModule = null;
+ private FallbackTreatmentsConfiguration _fallbackTreatments;
public Builder() {
}
@@ -1022,6 +1033,17 @@ public Builder alternativeHTTPModule(CustomHttpModule alternativeHTTPModule) {
return this;
}
+ /**
+ * Fallback Treatments
+ *
+ * @param fallbackTreatments
+ * @return this builder
+ */
+ public Builder fallbackTreatments(FallbackTreatmentsConfiguration fallbackTreatments) {
+ _fallbackTreatments = fallbackTreatments;
+ return this;
+ }
+
/**
* Thread Factory
*
@@ -1158,6 +1180,25 @@ private void verifyProxy() {
}
}
+ private void verifyFallbackTreatments() {
+ if (_fallbackTreatments == null)
+ return;
+
+ FallbackTreatment processedGlobalFallbackTreatment = _fallbackTreatments.getGlobalFallbackTreatment();
+ Map processedByFlagFallbackTreatment = _fallbackTreatments.getByFlagFallbackTreatment();
+
+ if (_fallbackTreatments.getGlobalFallbackTreatment() != null) {
+ processedGlobalFallbackTreatment = new FallbackTreatment(
+ isValidTreatment(_fallbackTreatments.getGlobalFallbackTreatment().getTreatment(), "Fallback treatments"),
+ _fallbackTreatments.getGlobalFallbackTreatment().getConfig());
+ }
+
+ if (_fallbackTreatments.getByFlagFallbackTreatment() != null) {
+ processedByFlagFallbackTreatment = isValidByFlagTreatment(_fallbackTreatments.getByFlagFallbackTreatment(), "config");
+ }
+ _fallbackTreatments = new FallbackTreatmentsConfiguration(processedGlobalFallbackTreatment, processedByFlagFallbackTreatment);
+ }
+
public SplitClientConfig build() {
verifyRates();
@@ -1172,6 +1213,8 @@ public SplitClientConfig build() {
verifyProxy();
+ verifyFallbackTreatments();
+
if (_numThreadsForSegmentFetch <= 0) {
throw new IllegalArgumentException("Number of threads for fetching segments MUST be greater than zero");
}
@@ -1230,7 +1273,8 @@ public SplitClientConfig build() {
_flagSetsFilter,
_invalidSetsCount,
_customHeaderDecorator,
- _alternativeHTTPModule);
+ _alternativeHTTPModule,
+ _fallbackTreatments);
}
}
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java
index 9f4b8ff9e..38ab5e6ba 100644
--- a/client/src/main/java/io/split/client/SplitClientImpl.java
+++ b/client/src/main/java/io/split/client/SplitClientImpl.java
@@ -3,9 +3,7 @@
import com.google.gson.GsonBuilder;
import io.split.client.api.Key;
import io.split.client.api.SplitResult;
-import io.split.client.dtos.DecoratedImpression;
-import io.split.client.dtos.EvaluationOptions;
-import io.split.client.dtos.Event;
+import io.split.client.dtos.*;
import io.split.client.events.EventsStorageProducer;
import io.split.client.impressions.Impression;
import io.split.client.impressions.ImpressionsManager;
@@ -14,7 +12,6 @@
import io.split.engine.evaluator.Evaluator;
import io.split.engine.evaluator.EvaluatorImp;
import io.split.engine.evaluator.Labels;
-import io.split.grammar.Treatments;
import io.split.inputValidation.EventsValidator;
import io.split.inputValidation.KeyValidator;
import io.split.inputValidation.SplitNameValidator;
@@ -49,7 +46,6 @@
* @author adil
*/
public final class SplitClientImpl implements SplitClient {
- public static final SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null);
private static final String CLIENT_DESTROY = "Client has already been destroyed - no calls possible";
private static final String CATCHALL_EXCEPTION = "CatchAll Exception";
private static final String MATCHING_KEY = "matchingKey";
@@ -66,6 +62,7 @@ public final class SplitClientImpl implements SplitClient {
private final TelemetryEvaluationProducer _telemetryEvaluationProducer;
private final TelemetryConfigProducer _telemetryConfigProducer;
private final FlagSetsFilter _flagSetsFilter;
+ private final FallbackTreatmentCalculator _fallbackTreatmentCalculator;
public SplitClientImpl(SplitFactory container,
SplitCacheConsumer splitCacheConsumer,
@@ -76,7 +73,8 @@ public SplitClientImpl(SplitFactory container,
Evaluator evaluator,
TelemetryEvaluationProducer telemetryEvaluationProducer,
TelemetryConfigProducer telemetryConfigProducer,
- FlagSetsFilter flagSetsFilter) {
+ FlagSetsFilter flagSetsFilter,
+ FallbackTreatmentCalculator fallbackTreatmentCalculator) {
_container = container;
_splitCacheConsumer = checkNotNull(splitCacheConsumer);
_impressionManager = checkNotNull(impressionManager);
@@ -87,6 +85,7 @@ public SplitClientImpl(SplitFactory container,
_telemetryEvaluationProducer = checkNotNull(telemetryEvaluationProducer);
_telemetryConfigProducer = checkNotNull(telemetryConfigProducer);
_flagSetsFilter = flagSetsFilter;
+ _fallbackTreatmentCalculator = fallbackTreatmentCalculator;
}
@Override
@@ -492,31 +491,34 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
if (_container.isDestroyed()) {
_log.error(CLIENT_DESTROY);
- return SPLIT_RESULT_CONTROL;
+ return checkFallbackTreatment(featureFlag);
}
if (!KeyValidator.isValid(matchingKey, MATCHING_KEY, _config.maxStringLength(), methodEnum.getMethod())) {
- return SPLIT_RESULT_CONTROL;
+ return checkFallbackTreatment(featureFlag);
}
if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) {
- return SPLIT_RESULT_CONTROL;
+ return checkFallbackTreatment(featureFlag);
}
Optional splitNameResult = SplitNameValidator.isValid(featureFlag, methodEnum.getMethod());
if (!splitNameResult.isPresent()) {
- return SPLIT_RESULT_CONTROL;
+ return checkFallbackTreatment(featureFlag);
}
featureFlag = splitNameResult.get();
long start = System.currentTimeMillis();
EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(matchingKey, bucketingKey, featureFlag, attributes);
-
- if (result.treatment.equals(Treatments.CONTROL) && result.label.equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
- _log.warn(String.format(
- "%s: you passed \"%s\" that does not exist in this environment, " +
- "please double check what feature flags exist in the Split user interface.", methodEnum.getMethod(), featureFlag));
- return SPLIT_RESULT_CONTROL;
+ String label = result.label;
+ if (result.label != null && result.label.contains(Labels.DEFINITION_NOT_FOUND)) {
+ if (_gates.isSDKReady()) {
+ _log.warn(String.format(
+ "%s: you passed \"%s\" that does not exist in this environment, " +
+ "please double check what feature flags exist in the Split user interface.", methodEnum.getMethod(), featureFlag));
+ return checkFallbackTreatment(featureFlag);
+ }
+ label = result.label.replace(Labels.DEFINITION_NOT_FOUND, Labels.NOT_READY);
}
recordStats(
@@ -526,7 +528,7 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
start,
result.treatment,
String.format("sdk.%s", methodEnum.getMethod()),
- _config.labelsEnabled() ? result.label : null,
+ _config.labelsEnabled() ? label : null,
result.changeNumber,
attributes,
result.track,
@@ -541,8 +543,17 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
} catch (Exception e1) {
// ignore
}
- return SPLIT_RESULT_CONTROL;
+ return checkFallbackTreatment(featureFlag);
+ }
+ }
+
+ private SplitResult checkFallbackTreatment(String featureName) {
+ FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, "");
+ String config = null;
+ if (fallbackTreatment.getConfig() != null) {
+ config = fallbackTreatment.getConfig();
}
+ return new SplitResult(fallbackTreatment.getTreatment(), config);
}
private String validateProperties(Map properties) {
@@ -563,6 +574,7 @@ private Map getTreatmentsWithConfigInternal(String matching
_log.error(String.format("%s: featureFlagNames must be a non-empty array", methodEnum.getMethod()));
return new HashMap<>();
}
+
try {
checkSDKReady(methodEnum, featureFlagNames);
Map result = validateBeforeEvaluate(featureFlagNames, matchingKey, methodEnum, bucketingKey);
@@ -601,47 +613,47 @@ private Map getTreatmentsBySetsWithConfigInternal(String ma
if (cleanFlagSets.isEmpty()) {
return new HashMap<>();
}
- List featureFlagNames = new ArrayList<>();
- try {
- checkSDKReady(methodEnum);
- Map result = validateBeforeEvaluateByFlagSets(matchingKey, methodEnum,bucketingKey);
- if(result != null) {
- return result;
- }
- Map evaluatorResult = _evaluator.evaluateFeaturesByFlagSets(matchingKey,
- bucketingKey, new ArrayList<>(cleanFlagSets), attributes);
+ checkSDKReady(methodEnum);
+ Map result = validateBeforeEvaluateByFlagSets(matchingKey, methodEnum,bucketingKey);
+ if(result != null) {
+ return result;
+ }
+ Map evaluatorResult = _evaluator.evaluateFeaturesByFlagSets(matchingKey,
+ bucketingKey, new ArrayList<>(cleanFlagSets), attributes);
- return processEvaluatorResult(evaluatorResult, methodEnum, matchingKey, bucketingKey, attributes, initTime,
- validateProperties(evaluationOptions.getProperties()));
- } catch (Exception e) {
- try {
+ evaluatorResult.entrySet().forEach(flag -> {
+ if (flag.getValue().label != null &&
+ flag.getValue().label.contains(io.split.engine.evaluator.Labels.EXCEPTION)) {
_telemetryEvaluationProducer.recordException(methodEnum);
- _log.error(CATCHALL_EXCEPTION, e);
- } catch (Exception e1) {
- // ignore
}
- return createMapControl(featureFlagNames);
- }
+ });
+ return processEvaluatorResult(evaluatorResult, methodEnum, matchingKey, bucketingKey, attributes, initTime,
+ validateProperties(evaluationOptions.getProperties()));
}
+
private Map processEvaluatorResult(Map evaluatorResult,
MethodEnum methodEnum, String matchingKey, String bucketingKey, Map attributes, long initTime, String properties){
List decoratedImpressions = new ArrayList<>();
Map result = new HashMap<>();
- evaluatorResult.keySet().forEach(t -> {
- if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label.
- equals(Labels.DEFINITION_NOT_FOUND) && _gates.isSDKReady()) {
- _log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " +
- "what feature flags exist in the Split user interface.", methodEnum.getMethod(), t));
- result.put(t, SPLIT_RESULT_CONTROL);
- } else {
- result.put(t, new SplitResult(evaluatorResult.get(t).treatment, evaluatorResult.get(t).configurations));
- decoratedImpressions.add(
- new DecoratedImpression(
- new Impression(matchingKey, bucketingKey, t, evaluatorResult.get(t).treatment, System.currentTimeMillis(),
- evaluatorResult.get(t).label, evaluatorResult.get(t).changeNumber, attributes, properties),
- evaluatorResult.get(t).track));
+ evaluatorResult.keySet().forEach(flag -> {
+ String label = evaluatorResult.get(flag).label;
+ if (evaluatorResult.get(flag).label != null &&
+ evaluatorResult.get(flag).label.contains(Labels.DEFINITION_NOT_FOUND)) {
+ if (_gates.isSDKReady()) {
+ _log.warn(String.format("%s: you passed \"%s\" that does not exist in this environment please double check " +
+ "what feature flags exist in the Split user interface.", methodEnum.getMethod(), flag));
+ result.put(flag, checkFallbackTreatment(flag));
+ return;
+ }
+ label = evaluatorResult.get(flag).label.replace(Labels.DEFINITION_NOT_FOUND, Labels.NOT_READY);
}
+ result.put(flag, new SplitResult(evaluatorResult.get(flag).treatment, evaluatorResult.get(flag).configurations));
+ decoratedImpressions.add(
+ new DecoratedImpression(
+ new Impression(matchingKey, bucketingKey, flag, evaluatorResult.get(flag).treatment, System.currentTimeMillis(),
+ label, evaluatorResult.get(flag).changeNumber, attributes, properties),
+ evaluatorResult.get(flag).track));
});
_telemetryEvaluationProducer.recordLatency(methodEnum, System.currentTimeMillis() - initTime);
if (!decoratedImpressions.isEmpty()) {
@@ -735,7 +747,7 @@ private void checkSDKReady(MethodEnum methodEnum) {
private Map createMapControl(List featureFlags) {
Map result = new HashMap<>();
- featureFlags.forEach(s -> result.put(s, SPLIT_RESULT_CONTROL));
+ featureFlags.forEach(s -> result.put(s, checkFallbackTreatment(s)));
return result;
}
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java
index cca655612..9ad38ef1b 100644
--- a/client/src/main/java/io/split/client/SplitFactoryImpl.java
+++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java
@@ -2,6 +2,7 @@
import com.google.common.io.Files;
import io.split.client.dtos.BearerCredentialsProvider;
+import io.split.client.dtos.FallbackTreatmentCalculatorImp;
import io.split.client.dtos.Metadata;
import io.split.client.events.EventsSender;
import io.split.client.events.EventsStorage;
@@ -256,8 +257,9 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_telemetrySyncTask = new TelemetrySyncTask(config.getTelemetryRefreshRate(), _telemetrySynchronizer,
config.getThreadFactory());
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(config.fallbackTreatments());
// Evaluator
- _evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache);
+ _evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, fallbackTreatmentCalculatorImp);
// SplitClient
_client = new SplitClientImpl(this,
@@ -269,7 +271,9 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
- flagSetsFilter);
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
+ );
// SplitManager
_manager = new SplitManagerImpl(splitCache, config, _gates, _telemetryStorageProducer);
@@ -348,7 +352,9 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_telemetrySynchronizer = new TelemetryConsumerSubmitter(customStorageWrapper, _sdkMetadata);
UserCustomRuleBasedSegmentAdapterConsumer userCustomRuleBasedSegmentAdapterConsumer =
new UserCustomRuleBasedSegmentAdapterConsumer(customStorageWrapper);
- _evaluator = new EvaluatorImp(userCustomSplitAdapterConsumer, userCustomSegmentAdapterConsumer, userCustomRuleBasedSegmentAdapterConsumer);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(config.fallbackTreatments());
+ _evaluator = new EvaluatorImp(userCustomSplitAdapterConsumer, userCustomSegmentAdapterConsumer,
+ userCustomRuleBasedSegmentAdapterConsumer, fallbackTreatmentCalculatorImp);
_impressionsSender = PluggableImpressionSender.create(customStorageWrapper);
_uniqueKeysTracker = createUniqueKeysTracker(config);
_impressionsManager = buildImpressionsManager(config, userCustomImpressionAdapterConsumer,
@@ -377,7 +383,9 @@ protected SplitFactoryImpl(String apiToken, SplitClientConfig config, CustomStor
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
- flagSetsFilter);
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
+ );
// SyncManager
_syncManager = new ConsumerSyncManager(synchronizer);
@@ -445,8 +453,9 @@ protected SplitFactoryImpl(SplitClientConfig config) {
SplitTasks splitTasks = SplitTasks.build(_splitSynchronizationTask, _segmentSynchronizationTaskImp,
_impressionsManager, null, null, null);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(config.fallbackTreatments());
// Evaluator
- _evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache);
+ _evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, fallbackTreatmentCalculatorImp);
EventsStorage eventsStorage = new NoopEventsStorageImp();
@@ -460,7 +469,9 @@ protected SplitFactoryImpl(SplitClientConfig config) {
_evaluator,
_telemetryStorageProducer, // TelemetryEvaluation instance
_telemetryStorageProducer, // TelemetryConfiguration instance
- flagSetsFilter);
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
+ );
// Synchronizer
Synchronizer synchronizer = new LocalhostSynchronizer(splitTasks, _splitFetcher,
diff --git a/client/src/main/java/io/split/client/dtos/FallbackTreatment.java b/client/src/main/java/io/split/client/dtos/FallbackTreatment.java
new file mode 100644
index 000000000..291db4f48
--- /dev/null
+++ b/client/src/main/java/io/split/client/dtos/FallbackTreatment.java
@@ -0,0 +1,37 @@
+package io.split.client.dtos;
+
+public class FallbackTreatment {
+ private final String _config;
+ private final String _treatment;
+ private final String _label;
+
+ public FallbackTreatment(String treatment, String config) {
+ _treatment = treatment;
+ _config = config;
+ _label = null;
+ }
+
+ public FallbackTreatment(String treatment) {
+ _treatment = treatment;
+ _config = null;
+ _label = null;
+ }
+
+ public FallbackTreatment(String treatment, String config, String label) {
+ _treatment = treatment;
+ _config = config;
+ _label = label;
+ }
+
+ public String getConfig() {
+ return _config;
+ }
+
+ public String getTreatment() {
+ return _treatment;
+ }
+
+ public String getLabel() {
+ return _label;
+ }
+}
diff --git a/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculator.java b/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculator.java
new file mode 100644
index 000000000..b172a1cb2
--- /dev/null
+++ b/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculator.java
@@ -0,0 +1,6 @@
+package io.split.client.dtos;
+
+public interface FallbackTreatmentCalculator
+{
+ FallbackTreatment resolve(String flagName, String label);
+}
diff --git a/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculatorImp.java b/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculatorImp.java
new file mode 100644
index 000000000..936abc493
--- /dev/null
+++ b/client/src/main/java/io/split/client/dtos/FallbackTreatmentCalculatorImp.java
@@ -0,0 +1,40 @@
+package io.split.client.dtos;
+
+import io.split.grammar.Treatments;
+
+public class FallbackTreatmentCalculatorImp implements FallbackTreatmentCalculator
+{
+ private final FallbackTreatmentsConfiguration _fallbackTreatmentsConfiguration;
+ private final static String labelPrefix = "fallback - ";
+
+ public FallbackTreatmentCalculatorImp(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration) {
+ _fallbackTreatmentsConfiguration = fallbackTreatmentsConfiguration;
+ }
+
+ public FallbackTreatment resolve(String flagName, String label) {
+ if (_fallbackTreatmentsConfiguration != null) {
+ if (_fallbackTreatmentsConfiguration.getByFlagFallbackTreatment() != null
+ && _fallbackTreatmentsConfiguration.getByFlagFallbackTreatment().get(flagName) != null) {
+ return copyWithLabel(_fallbackTreatmentsConfiguration.getByFlagFallbackTreatment().get(flagName),
+ resolveLabel(label));
+ }
+ if (_fallbackTreatmentsConfiguration.getGlobalFallbackTreatment() != null) {
+ return copyWithLabel(_fallbackTreatmentsConfiguration.getGlobalFallbackTreatment(),
+ resolveLabel(label));
+ }
+ }
+
+ return new FallbackTreatment(Treatments.CONTROL, null, label);
+ }
+
+ private String resolveLabel(String label) {
+ if (label == null) {
+ return null;
+ }
+ return labelPrefix + label;
+ }
+
+ private FallbackTreatment copyWithLabel(FallbackTreatment fallbackTreatment, String label) {
+ return new FallbackTreatment(fallbackTreatment.getTreatment(), fallbackTreatment.getConfig(), label);
+ }
+}
diff --git a/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java b/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java
new file mode 100644
index 000000000..aa47d1163
--- /dev/null
+++ b/client/src/main/java/io/split/client/dtos/FallbackTreatmentsConfiguration.java
@@ -0,0 +1,19 @@
+package io.split.client.dtos;
+
+import java.util.Map;
+
+public class FallbackTreatmentsConfiguration {
+ private final FallbackTreatment _globalFallbackTreatment;
+ private final Map _byFlagFallbackTreatment;
+
+ public FallbackTreatmentsConfiguration(FallbackTreatment globalFallbackTreatment, Map byFlagFallbackTreatment) {
+ _globalFallbackTreatment = globalFallbackTreatment;
+ _byFlagFallbackTreatment = byFlagFallbackTreatment;
+ }
+
+ public FallbackTreatment getGlobalFallbackTreatment() {
+ return _globalFallbackTreatment;
+ }
+
+ public Map getByFlagFallbackTreatment() { return _byFlagFallbackTreatment;}
+}
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 6d31952c3..8d7147aa6 100644
--- a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
+++ b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java
@@ -1,11 +1,12 @@
package io.split.engine.evaluator;
import io.split.client.dtos.ConditionType;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentCalculator;
import io.split.client.exceptions.ChangeNumberExceptionWrapper;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
import io.split.engine.splitter.Splitter;
-import io.split.grammar.Treatments;
import io.split.storages.RuleBasedSegmentCacheConsumer;
import io.split.storages.SegmentCacheConsumer;
import io.split.storages.SplitCacheConsumer;
@@ -26,19 +27,23 @@ public class EvaluatorImp implements Evaluator {
private final SegmentCacheConsumer _segmentCacheConsumer;
private final EvaluationContext _evaluationContext;
private final SplitCacheConsumer _splitCacheConsumer;
+ private final FallbackTreatmentCalculator _fallbackTreatmentCalculator;
+ private final String _evaluatorException = "Evaluator Exception";
public EvaluatorImp(SplitCacheConsumer splitCacheConsumer, SegmentCacheConsumer segmentCache,
- RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer) {
+ RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer,
+ FallbackTreatmentCalculator fallbackTreatmentCalculator) {
_splitCacheConsumer = checkNotNull(splitCacheConsumer);
_segmentCacheConsumer = checkNotNull(segmentCache);
_evaluationContext = new EvaluationContext(this, _segmentCacheConsumer, ruleBasedSegmentCacheConsumer);
+ _fallbackTreatmentCalculator = fallbackTreatmentCalculator;
}
@Override
public TreatmentLabelAndChangeNumber evaluateFeature(String matchingKey, String bucketingKey, String featureFlag, Map attributes) {
ParsedSplit parsedSplit = _splitCacheConsumer.get(featureFlag);
- return evaluateParsedSplit(matchingKey, bucketingKey, attributes, parsedSplit);
+ return evaluateParsedSplit(matchingKey, bucketingKey, attributes, parsedSplit, featureFlag);
}
@Override
@@ -49,7 +54,7 @@ public Map evaluateFeatures(String matchi
if (parsedSplits == null) {
return results;
}
- featureFlags.forEach(s -> results.put(s, evaluateParsedSplit(matchingKey, bucketingKey, attributes, parsedSplits.get(s))));
+ featureFlags.forEach(s -> results.put(s, evaluateParsedSplit(matchingKey, bucketingKey, attributes, parsedSplits.get(s), s)));
return results;
}
@@ -57,7 +62,27 @@ public Map evaluateFeatures(String matchi
public Map evaluateFeaturesByFlagSets(String key, String bucketingKey,
List flagSets, Map attributes) {
List flagSetsWithNames = getFeatureFlagNamesByFlagSets(flagSets);
- return evaluateFeatures(key, bucketingKey, flagSetsWithNames, attributes);
+ try {
+ return evaluateFeatures(key, bucketingKey, flagSetsWithNames, attributes);
+ } catch (Exception e) {
+ _log.error(_evaluatorException, e);
+ return createMapControl(flagSetsWithNames, io.split.engine.evaluator.Labels.EXCEPTION);
+ }
+ }
+
+ private Map createMapControl(List featureFlags, String label) {
+ Map result = new HashMap<>();
+ featureFlags.forEach(s -> result.put(s, checkFallbackTreatment(s, label)));
+ return result;
+ }
+
+ private EvaluatorImp.TreatmentLabelAndChangeNumber checkFallbackTreatment(String featureName, String label) {
+ FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, label);
+ return new EvaluatorImp.TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(),
+ fallbackTreatment.getLabel(),
+ null,
+ getFallbackConfig(fallbackTreatment),
+ false);
}
private List getFeatureFlagNamesByFlagSets(List flagSets) {
@@ -171,19 +196,34 @@ private String getConfig(ParsedSplit parsedSplit, String returnedTreatment) {
return parsedSplit.configurations() != null ? parsedSplit.configurations().get(returnedTreatment) : null;
}
+ private String getFallbackConfig(FallbackTreatment fallbackTreatment) {
+ if (fallbackTreatment.getConfig() != null) {
+ return fallbackTreatment.getConfig();
+ }
+
+ return null;
+ }
+
private TreatmentLabelAndChangeNumber evaluateParsedSplit(String matchingKey, String bucketingKey, Map attributes,
- ParsedSplit parsedSplit) {
+ ParsedSplit parsedSplit, String featureName) {
try {
if (parsedSplit == null) {
- return new TreatmentLabelAndChangeNumber(Treatments.CONTROL, Labels.DEFINITION_NOT_FOUND);
+ FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, Labels.DEFINITION_NOT_FOUND);
+ return new TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(),
+ fallbackTreatment.getLabel(),
+ null,
+ getFallbackConfig(fallbackTreatment),
+ false);
}
return getTreatment(matchingKey, bucketingKey, parsedSplit, attributes);
} catch (ChangeNumberExceptionWrapper e) {
- _log.error("Evaluator Exception", e.wrappedException());
- return new EvaluatorImp.TreatmentLabelAndChangeNumber(Treatments.CONTROL, Labels.EXCEPTION, e.changeNumber());
+ _log.error(_evaluatorException, e.wrappedException());
+ FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, Labels.EXCEPTION);
+ return new TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(), fallbackTreatment.getLabel(), e.changeNumber());
} catch (Exception e) {
- _log.error("Evaluator Exception", e);
- return new EvaluatorImp.TreatmentLabelAndChangeNumber(Treatments.CONTROL, Labels.EXCEPTION);
+ _log.error(_evaluatorException, e);
+ FallbackTreatment fallbackTreatment = _fallbackTreatmentCalculator.resolve(featureName, Labels.EXCEPTION);
+ return new TreatmentLabelAndChangeNumber(fallbackTreatment.getTreatment(), fallbackTreatment.getLabel());
}
}
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 9bda16a8b..28966d51e 100644
--- a/client/src/main/java/io/split/engine/evaluator/Labels.java
+++ b/client/src/main/java/io/split/engine/evaluator/Labels.java
@@ -8,4 +8,5 @@ public class Labels {
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";
+ public static final String NOT_READY = "not ready";
}
\ No newline at end of file
diff --git a/client/src/main/java/io/split/inputValidation/FallbackTreatmentValidator.java b/client/src/main/java/io/split/inputValidation/FallbackTreatmentValidator.java
new file mode 100644
index 000000000..9fafe5eea
--- /dev/null
+++ b/client/src/main/java/io/split/inputValidation/FallbackTreatmentValidator.java
@@ -0,0 +1,67 @@
+package io.split.inputValidation;
+
+import io.split.client.dtos.FallbackTreatment;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+import static io.split.inputValidation.SplitNameValidator.isValid;
+
+public class FallbackTreatmentValidator {
+ private static final Logger _log = LoggerFactory.getLogger(FallbackTreatmentValidator.class);
+ private static final Pattern TREATMENT_MATCHER = Pattern.compile("^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$");
+ private static final int MAX_LENGTH = 100;
+
+ public static String isValidTreatment(String name, String method) {
+ if (name == null) {
+ _log.error(String.format("%s: you passed a null treatment, fallback treatment must be a non-empty string", method));
+ return null;
+ }
+
+ if (name.isEmpty()) {
+ _log.error(String.format("%s: you passed an empty treatment, fallback treatment must be a non-empty string", method));
+ return null;
+ }
+
+ String trimmed = name.trim();
+ if (!trimmed.equals(name)) {
+ _log.warn(String.format("%s: fallback treatment %s has extra whitespace, trimming", method, name));
+ name = trimmed;
+ }
+
+ if (name.length() > MAX_LENGTH) {
+ return null;
+ }
+
+ if (!TREATMENT_MATCHER.matcher(name).find()) {
+ _log.error(String.format("%s: you passed %s, treatment must adhere to the regular expression " +
+ "^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$", method, name));
+ return null;
+ }
+
+ return name;
+ }
+
+ public static Map isValidByFlagTreatment(Map byFlagTreatment, String method) {
+ Map result = new HashMap<>();
+ for (Map.Entry entry : byFlagTreatment.entrySet()) {
+ Optional featureName = isValid(entry.getKey(), method);
+ if (featureName.equals(Optional.empty()) || !featureName.isPresent()) {
+ continue;
+ }
+
+ FallbackTreatment fallbackTreatment = entry.getValue();
+ String treatment = isValidTreatment(fallbackTreatment.getTreatment(), method);
+ if (treatment != null) {
+ result.put(featureName.get(), new FallbackTreatment(treatment, fallbackTreatment.getConfig()));
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/client/src/main/java/io/split/inputValidation/SplitNameValidator.java b/client/src/main/java/io/split/inputValidation/SplitNameValidator.java
index 72f6a1b9d..f138f51c1 100644
--- a/client/src/main/java/io/split/inputValidation/SplitNameValidator.java
+++ b/client/src/main/java/io/split/inputValidation/SplitNameValidator.java
@@ -6,10 +6,13 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class SplitNameValidator {
private static final Logger _log = LoggerFactory.getLogger(SplitNameValidator.class);
+ private static final int MAX_LENGTH = 100;
+ private static final Pattern NAME_MATCHER = Pattern.compile("^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$");
public static Optional isValid(String name, String method) {
if (name == null) {
@@ -28,6 +31,16 @@ public static Optional isValid(String name, String method) {
name = trimmed;
}
+ if (name.length() > MAX_LENGTH) {
+ return Optional.empty();
+ }
+
+ if (!NAME_MATCHER.matcher(name).find()) {
+ _log.error(String.format("%s: you passed %s, feature flag name must adhere to the regular expression " +
+ "^[0-9]+[.a-zA-Z0-9_-]*$|^[a-zA-Z]+[a-zA-Z0-9_-]*$", method, name));
+ return Optional.empty();
+ }
+
return Optional.of(name);
}
diff --git a/client/src/test/java/io/split/client/SplitClientConfigTest.java b/client/src/test/java/io/split/client/SplitClientConfigTest.java
index be9e85544..e8ed6dfdb 100644
--- a/client/src/test/java/io/split/client/SplitClientConfigTest.java
+++ b/client/src/test/java/io/split/client/SplitClientConfigTest.java
@@ -1,13 +1,13 @@
package io.split.client;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import io.split.client.dtos.BasicCredentialsProvider;
-import io.split.client.dtos.BearerCredentialsProvider;
+import io.split.client.dtos.RequestContext;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
+import io.split.client.dtos.FallbackTreatment;
import io.split.client.dtos.ProxyConfiguration;
import io.split.client.impressions.Impression;
import io.split.client.impressions.ImpressionListener;
import io.split.client.impressions.ImpressionsManager;
-import io.split.client.dtos.RequestContext;
import io.split.integrations.IntegrationsConfig;
import org.junit.Assert;
import org.junit.Test;
@@ -17,6 +17,7 @@
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@@ -362,4 +363,25 @@ public void mustUseP12PassKeyWithProxyMtls() throws MalformedURLException, FileN
.build())
.build();
}
+
+ @Test
+ public void fallbackTreatmentCheckRegex() {
+ SplitClientConfig config = SplitClientConfig.builder()
+ .fallbackTreatments(new FallbackTreatmentsConfiguration(new FallbackTreatment("12#2"), null))
+ .build();
+ Assert.assertEquals(null, config.fallbackTreatments().getGlobalFallbackTreatment().getTreatment());
+
+ config = SplitClientConfig.builder()
+ .fallbackTreatments(new FallbackTreatmentsConfiguration(null, new HashMap() {{ put("flag", new FallbackTreatment("12#2")); }} ))
+ .build();
+ Assert.assertEquals(0, config.fallbackTreatments().getByFlagFallbackTreatment().size());
+
+ config = SplitClientConfig.builder()
+ .fallbackTreatments(new FallbackTreatmentsConfiguration(
+ new FallbackTreatment("on"),
+ new HashMap() {{ put("flag", new FallbackTreatment("off")); }} ))
+ .build();
+ Assert.assertEquals("on", config.fallbackTreatments().getGlobalFallbackTreatment().getTreatment());
+ Assert.assertEquals("off", config.fallbackTreatments().getByFlagFallbackTreatment().get("flag").getTreatment());
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java
index 5b56708d9..2556508c6 100644
--- a/client/src/test/java/io/split/client/SplitClientImplTest.java
+++ b/client/src/test/java/io/split/client/SplitClientImplTest.java
@@ -99,8 +99,9 @@ public void nullKeyResultsInControl() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.CONTROL, client.getTreatment(null, "test1"));
@@ -129,8 +130,9 @@ public void nullTestResultsInControl() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", null));
@@ -152,8 +154,9 @@ public void exceptionsResultInControl() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", "test1"));
@@ -184,8 +187,9 @@ public void works() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -222,8 +226,9 @@ public void worksNullConfig() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
String randomKey = RandomStringUtils.random(10);
SplitResult result = client.getTreatmentWithConfig(randomKey, test);
@@ -258,8 +263,9 @@ public void worksAndHasConfig() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -295,8 +301,9 @@ public void lastConditionIsAlwaysDefault() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.OFF, client.getTreatment("pato@codigo.com", test));
@@ -335,8 +342,9 @@ public void lastConditionIsAlwaysDefaultButWithTreatment() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
SplitResult result = client.getTreatmentWithConfig("pato@codigo.com", test);
@@ -371,8 +379,9 @@ public void multipleConditionsWork() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals("on", client.getTreatment("adil@codigo.com", test));
@@ -405,8 +414,9 @@ public void killedTestAlwaysGoesToDefault() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.OFF, client.getTreatment("adil@codigo.com", test));
@@ -445,8 +455,9 @@ public void killedTestAlwaysGoesToDefaultHasConfig() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
SplitResult result = client.getTreatmentWithConfig("adil@codigo.com", test);
@@ -483,8 +494,9 @@ public void dependencyMatcherOn() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.ON, client.getTreatment("key", parent));
@@ -510,7 +522,7 @@ public void dependencyMatcherOff() {
RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
when(splitCacheConsumer.get(parent)).thenReturn(parentSplit);
when(splitCacheConsumer.get(dependent)).thenReturn(dependentSplit);
-
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
splitCacheConsumer,
@@ -518,8 +530,9 @@ public void dependencyMatcherOff() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
assertEquals(Treatments.ON, client.getTreatment("key", parent));
@@ -539,6 +552,7 @@ public void dependencyMatcherControl() {
SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
when(splitCacheConsumer.get(dependent)).thenReturn(dependentSplit);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -547,8 +561,9 @@ public void dependencyMatcherControl() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
assertEquals(Treatments.ON, client.getTreatment("key", dependent));
@@ -577,8 +592,9 @@ public void attributesWork() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals("on", client.getTreatment("adil@codigo.com", test));
@@ -612,8 +628,9 @@ public void attributesWork2() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals("off", client.getTreatment("adil@codigo.com", test));
@@ -648,8 +665,9 @@ public void attributesGreaterThanNegativeNumber() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals("off", client.getTreatment("adil@codigo.com", test));
@@ -686,8 +704,9 @@ public void attributesForSets() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer ,segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer ,segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals("off", client.getTreatment("adil@codigo.com", test));
@@ -731,8 +750,9 @@ public void labelsArePopulated() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map attributes = ImmutableMap.of("age", -20, "acv", "1000000");
@@ -834,8 +854,9 @@ private void trafficAllocation(String key, int trafficAllocation, int trafficAll
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(expected_treatment_on_or_off, client.getTreatment(key, test));
@@ -888,8 +909,9 @@ public void notInTrafficAllocationDefaultConfig() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.OFF, client.getTreatment("pato@split.io", test));
@@ -932,8 +954,9 @@ public void matchingBucketingKeysWork() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Key bad_key = new Key("adil", "aijaz");
@@ -975,8 +998,9 @@ public void matchingBucketingKeysByFlagSetWork() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Key bad_key = new Key("adil", "aijaz");
@@ -1016,8 +1040,9 @@ public void matchingBucketingKeysByFlagSetsWork() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Key bad_key = new Key("adil", "aijaz");
@@ -1054,8 +1079,9 @@ public void impressionMetadataIsPropagated() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map attributes = ImmutableMap.of("age", -20, "acv", "1000000");
@@ -1097,8 +1123,9 @@ public void blockUntilReadyDoesNotTimeWhenSdkIsReady() throws TimeoutException,
NoopEventsStorageImp.create(),
config,
ready,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
client.blockUntilReady();
@@ -1119,8 +1146,9 @@ public void blockUntilReadyTimesWhenSdkIsNotReady() throws TimeoutException, Int
NoopEventsStorageImp.create(),
config,
ready,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
client.blockUntilReady();
@@ -1140,8 +1168,9 @@ public void trackWithValidParameters() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertTrue(client.track("validKey", "valid_traffic_type", "valid_event"));
@@ -1166,8 +1195,9 @@ public void trackWithInvalidEventTypeIds() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Assert.assertFalse(client.track("validKey", "valid_traffic_type", ""));
Assert.assertFalse(client.track("validKey", "valid_traffic_type", null));
@@ -1191,8 +1221,9 @@ public void trackWithInvalidTrafficTypeNames() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Assert.assertFalse(client.track("validKey", "", "valid"));
@@ -1213,8 +1244,9 @@ public void trackWithInvalidKeys() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Assert.assertFalse(client.track("", "valid_traffic_type", "valid"));
@@ -1245,8 +1277,9 @@ public void getTreatmentWithInvalidKeys() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Assert.assertNotEquals(Treatments.CONTROL, client.getTreatment("valid", "split"));
assertEquals(Treatments.CONTROL, client.getTreatment("", "split"));
@@ -1296,8 +1329,9 @@ public void trackWithProperties() {
eventClientMock,
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
HashMap properties = new HashMap<>();
@@ -1420,8 +1454,9 @@ public void clientCannotPerformActionsWhenDestroyed() throws InterruptedExceptio
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.ON, client.getTreatment("valid", "split"));
@@ -1461,8 +1496,9 @@ public void worksAndHasConfigTryKetTreatmentWithKey() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -1512,8 +1548,9 @@ public void worksAndHasConfigByFlagSetTryKetTreatmentWithKey() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -1561,8 +1598,9 @@ public void worksAndHasConfigByFlagSetsTryKetTreatmentWithKey() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -1599,8 +1637,9 @@ public void blockUntilReadyException() throws TimeoutException, InterruptedExcep
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
client.blockUntilReady();
@@ -1629,8 +1668,9 @@ public void nullKeyResultsInControlGetTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(Treatments.CONTROL, client.getTreatments(null, Collections.singletonList("test1")).get("test1"));
@@ -1660,8 +1700,9 @@ public void nullSplitsResultsInEmptyGetTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertEquals(0, client.getTreatments("key", null).size());
@@ -1683,8 +1724,9 @@ public void exceptionsResultInControlGetTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map result = client.getTreatments("adil@relateiq.com", Arrays.asList("test1", "test2"));
assertEquals(2, result.values().size());
@@ -1709,6 +1751,7 @@ public void getTreatmentsWorks() {
RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
when(splitCacheConsumer.fetchMany(anyList())).thenReturn(splits);
when(gates.isSDKReady()).thenReturn(true);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -1717,8 +1760,9 @@ public void getTreatmentsWorks() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
Map result = client.getTreatments("randomKey", Arrays.asList(test, "test2"));
assertEquals("on", result.get(test));
@@ -1748,8 +1792,9 @@ public void emptySplitsResultsInNullGetTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map result = client.getTreatments("key", new ArrayList<>());
assertNotNull(result);
@@ -1773,8 +1818,9 @@ public void exceptionsResultInControlTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map result = client.getTreatments("adil@relateiq.com", Arrays.asList("test1"));
assertEquals(1, result.size());
@@ -1811,8 +1857,9 @@ public void worksTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
Map result = client.getTreatments("anyKey", Arrays.asList(test, test2));
assertNotNull(result);
@@ -1841,6 +1888,7 @@ public void worksOneControlTreatments() {
RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
when(splitCacheConsumer.fetchMany(anyList())).thenReturn(parsedSplits);
when(gates.isSDKReady()).thenReturn(true);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -1849,8 +1897,9 @@ public void worksOneControlTreatments() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
Map result = client.getTreatments("anyKey", Arrays.asList(test, test2));
@@ -1886,6 +1935,7 @@ public void treatmentsWorksAndHasConfig() {
SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
when(splitCacheConsumer.fetchMany(anyList())).thenReturn(parsedSplits);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -1894,8 +1944,9 @@ public void treatmentsWorksAndHasConfig() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
Map attributes = new HashMap<>();
Map result = client.getTreatmentsWithConfig("randomKey", Arrays.asList(test, test2, "", null), attributes);
@@ -1937,8 +1988,9 @@ public void testTreatmentsByFlagSet() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
@@ -1978,8 +2030,9 @@ public void testTreatmentsByFlagSetInvalid() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", new HashMap<>()).isEmpty());
}
@@ -2022,8 +2075,9 @@ public void testTreatmentsByFlagSets() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ new FallbackTreatmentCalculatorImp(null)
);
int numKeys = 5;
Map getTreatmentResult;
@@ -2070,6 +2124,7 @@ public void treatmentsWorksAndHasConfigFlagSet() {
when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -2078,8 +2133,9 @@ public void treatmentsWorksAndHasConfigFlagSet() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
Map attributes = new HashMap<>();
Map result = client.getTreatmentsWithConfigByFlagSet("randomKey", "set1", attributes);
@@ -2127,6 +2183,7 @@ public void treatmentsWorksAndHasConfigFlagSets() {
when(splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagsBySets);
SDKReadinessGates gates = mock(SDKReadinessGates.class);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
@@ -2135,8 +2192,9 @@ public void treatmentsWorksAndHasConfigFlagSets() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- flagSetsFilter
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculatorImp), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ flagSetsFilter,
+ fallbackTreatmentCalculatorImp
);
Map attributes = new HashMap<>();
Map result = client.getTreatmentsWithConfigByFlagSets("randomKey", new ArrayList<>(Arrays.asList("set1")), attributes);
@@ -2181,8 +2239,10 @@ public void impressionPropertiesTest() {
NoopEventsStorageImp.create(),
config,
gates,
- new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
- new FlagSetsFilterImpl(new HashSet<>())
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, null), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ new FallbackTreatmentCalculatorImp(null)
+
);
Map attributes = ImmutableMap.of("age", -20, "acv", "1000000");
EvaluationOptions properties = new EvaluationOptions(new HashMap()
@@ -2233,4 +2293,350 @@ public void impressionPropertiesTest() {
assertEquals("{\"prop2\":\"val2\",\"prop1\":\"val1\"}", impression.impression().properties());
}
}
+
+ @Test
+ public void fallbackTreatmentWithExceptionsResult() {
+ SDKReadinessGates gates = mock(SDKReadinessGates.class);
+ SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
+ SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
+ RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
+ when(splitCacheConsumer.get(anyString())).thenThrow(RuntimeException.class);
+ when(splitCacheConsumer.fetchMany(anyList())).thenThrow(RuntimeException.class);
+ HashMap> features = new HashMap<>();
+ features.put("flag", new HashSet<>(Arrays.asList("test1")));
+ when(splitCacheConsumer.getNamesByFlagSets(anyList())).thenReturn(features);
+
+ String fallbcakConfigGlobal = "{\"prop1\", \"val1\"}";
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(
+ new FallbackTreatment("on", fallbcakConfigGlobal),
+ null);
+ FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ SplitClientImpl client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator),
+ TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals("on", client.getTreatment("adil@relateiq.com", "test1"));
+ assertEquals("on", client.getTreatmentWithConfig("adil@relateiq.com", "test1").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentWithConfig("adil@relateiq.com", "test1").config());
+ assertEquals("on", client.getTreatments("adil@relateiq.com", Arrays.asList("test1")).get("test1"));
+ assertEquals("on", client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("test1")).get("test1").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("test1")).get("test1").config());
+
+ assertEquals("on", client.getTreatmentsByFlagSet("adil@relateiq.com", "flag").get("test1"));
+ assertEquals("on", client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test1"));
+ assertEquals("on", client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test1").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test1").config());
+ assertEquals("on", client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test1").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test1").config());
+
+ String fallbcakConfigByFlag = "{\"prop2\", \"val2\"}";
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on", fallbcakConfigGlobal),
+ new HashMap() {{ put("feature", new FallbackTreatment("off", fallbcakConfigByFlag)); }});
+
+ features = new HashMap<>();
+ features.put("flag", new HashSet<>(Arrays.asList("test", "feature")));
+ when(splitCacheConsumer.getNamesByFlagSets(anyList())).thenReturn(features);
+
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator),
+ TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals("on", client.getTreatment("adil@relateiq.com", "test"));
+ assertEquals("off", client.getTreatment("adil@relateiq.com", "feature"));
+ assertEquals("on", client.getTreatmentWithConfig("adil@relateiq.com", "test1").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentWithConfig("adil@relateiq.com", "test1").config());
+ assertEquals("off", client.getTreatmentWithConfig("adil@relateiq.com", "feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentWithConfig("adil@relateiq.com", "feature").config());
+ Map result = client.getTreatments("adil@relateiq.com", Arrays.asList("feature", "test"));
+ assertEquals("off", result.get("feature"));
+ assertEquals("on", result.get("test"));
+ Map results = client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("feature", "test"));
+ assertEquals("off", results.get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("feature").config());
+ assertEquals("on", results.get("test").treatment());
+ assertEquals(fallbcakConfigGlobal, results.get("test").config());
+
+ assertEquals("on", client.getTreatmentsByFlagSet("adil@relateiq.com", "flag").get("test"));
+ assertEquals("off", client.getTreatmentsByFlagSet("adil@relateiq.com", "flag").get("feature"));
+ assertEquals("on", client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test"));
+ assertEquals("off", client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature"));
+ assertEquals("on", client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test").config());
+ assertEquals("off", client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("feature").config());
+ assertEquals("on", client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test").config());
+ assertEquals("off", client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature").config());
+
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(null,
+ new HashMap() {{ put("feature", new FallbackTreatment("off", fallbcakConfigByFlag)); }});
+
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", "test"));
+ assertEquals("off", client.getTreatment("adil@relateiq.com", "feature"));
+ assertEquals(Treatments.CONTROL, client.getTreatmentWithConfig("adil@relateiq.com", "test1").treatment());
+ assertEquals(null, client.getTreatmentWithConfig("adil@relateiq.com", "test1").config());
+ assertEquals("off", client.getTreatmentWithConfig("adil@relateiq.com", "feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentWithConfig("adil@relateiq.com", "feature").config());
+ result = client.getTreatments("adil@relateiq.com", Arrays.asList("feature", "test"));
+ assertEquals("off", result.get("feature"));
+ assertEquals(Treatments.CONTROL, result.get("test"));
+ results = client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("feature", "test"));
+ assertEquals("off", results.get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("feature").config());
+ assertEquals(Treatments.CONTROL, results.get("test").treatment());
+ assertEquals(null, results.get("test").config());
+
+ assertEquals(Treatments.CONTROL, client.getTreatmentsByFlagSet("adil@relateiq.com", "flag").get("test"));
+ assertEquals("off", client.getTreatmentsByFlagSet("adil@relateiq.com", "flag").get("feature"));
+ assertEquals(Treatments.CONTROL, client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test"));
+ assertEquals("off", client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature"));
+ assertEquals(Treatments.CONTROL, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test").treatment());
+ assertEquals(null, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("test").config());
+ assertEquals("off", client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag").get("feature").config());
+ assertEquals(Treatments.CONTROL, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test").treatment());
+ assertEquals(null, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("test").config());
+ assertEquals("off", client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag")).get("feature").config());
+ }
+
+ @Test
+ public void fallbackTreatmentWithSplitNotFoundResult() {
+ SDKReadinessGates gates = mock(SDKReadinessGates.class);
+ SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
+ SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
+ RuleBasedSegmentCacheConsumer ruleBasedSegmentCacheConsumer = mock(RuleBasedSegmentCacheConsumer.class);
+ 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,
+ null, 1, 1, new HashSet<>(), false, new PrerequisitesMatcher(null));
+
+ when(splitCacheConsumer.get("test1")).thenReturn(parsedSplit);
+ when(splitCacheConsumer.get("test2")).thenReturn(null);
+ when(splitCacheConsumer.get("test3")).thenReturn(null);
+ HashMap features = new HashMap<>();
+ features.put("test1", parsedSplit);
+ features.put("test2", null);
+ features.put("test3", null);
+ when(splitCacheConsumer.fetchMany(anyList())).thenReturn(features);
+ HashMap> flagFeatures = new HashMap<>();
+ flagFeatures.put("flag", new HashSet<>(Arrays.asList("test1", "test2", "test3")));
+ when(splitCacheConsumer.getNamesByFlagSets(anyList())).thenReturn(flagFeatures);
+
+ String fallbcakConfigGlobal = "{\"prop1\", \"val1\"}";
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(
+ new FallbackTreatment("on", fallbcakConfigGlobal),
+ null);
+ FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ SplitClientImpl client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator),
+ TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals("off", client.getTreatment("adil@relateiq.com", "test1"));
+ assertEquals("on", client.getTreatment("adil@relateiq.com", "test2"));
+ assertEquals("on", client.getTreatmentWithConfig("adil@relateiq.com", "test2").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentWithConfig("adil@relateiq.com", "test2").config());
+
+ Map result = client.getTreatments("adil@relateiq.com", Arrays.asList("test1", "test2"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("on", result.get("test2"));
+ Map resultWithConfig = client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("test1", "test2"));
+ assertEquals("off", resultWithConfig.get("test1").treatment());
+ assertEquals(null, resultWithConfig.get("test1").config());
+ assertEquals("on", resultWithConfig.get("test2").treatment());
+ assertEquals(fallbcakConfigGlobal, resultWithConfig.get("test2").config());
+
+ result = client.getTreatmentsByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", result.get("test1"));
+ assertEquals("on", result.get("test2"));
+ result = client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("on", result.get("test2"));
+ resultWithConfig = client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", resultWithConfig.get("test1").treatment());
+ assertEquals(null, resultWithConfig.get("test1").config());
+ assertEquals("on", resultWithConfig.get("test2").treatment());
+ assertEquals(fallbcakConfigGlobal, resultWithConfig.get("test2").config());
+ resultWithConfig = client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", resultWithConfig.get("test1").treatment());
+ assertEquals(null, resultWithConfig.get("test1").config());
+ assertEquals("on", resultWithConfig.get("test2").treatment());
+ assertEquals(fallbcakConfigGlobal, resultWithConfig.get("test2").config());
+
+ String fallbcakConfigByFlag = "{\"prop2\", \"val2\"}";
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on", fallbcakConfigGlobal),
+ new HashMap() {{ put("test2", new FallbackTreatment("off-fallback", fallbcakConfigByFlag)); }});
+
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator),
+ TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals("off", client.getTreatment("adil@relateiq.com", "test1"));
+ assertEquals("off-fallback", client.getTreatment("adil@relateiq.com", "test2"));
+ assertEquals("on", client.getTreatment("adil@relateiq.com", "test3"));
+
+ assertEquals("off", client.getTreatmentWithConfig("adil@relateiq.com", "test1").treatment());
+ assertEquals(null, client.getTreatmentWithConfig("adil@relateiq.com", "test1").config());
+ assertEquals("off-fallback", client.getTreatmentWithConfig("adil@relateiq.com", "test2").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentWithConfig("adil@relateiq.com", "test2").config());
+ assertEquals("on", client.getTreatmentWithConfig("adil@relateiq.com", "test3").treatment());
+ assertEquals(fallbcakConfigGlobal, client.getTreatmentWithConfig("adil@relateiq.com", "test3").config());
+
+ result = client.getTreatments("adil@relateiq.com", Arrays.asList("test1", "test2", "test3"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals("on", result.get("test3"));
+
+ Map results = client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("test1", "test2", "test3"));
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals("on", results.get("test3").treatment());
+ assertEquals(fallbcakConfigGlobal, results.get("test3").config());
+
+ result = client.getTreatmentsByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals("on", result.get("test3"));
+
+ result = client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals("on", result.get("test3"));
+
+ results = client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals("on", results.get("test3").treatment());
+ assertEquals(fallbcakConfigGlobal, results.get("test3").config());
+
+ results = client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals("on", results.get("test3").treatment());
+ assertEquals(fallbcakConfigGlobal, results.get("test3").config());
+
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(null,
+ new HashMap() {{ put("test2", new FallbackTreatment("off-fallback", fallbcakConfigByFlag)); }});
+
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+
+ client = new SplitClientImpl(
+ mock(SplitFactory.class),
+ splitCacheConsumer,
+ new ImpressionsManager.NoOpImpressionsManager(),
+ NoopEventsStorageImp.create(),
+ config,
+ gates,
+ new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer, ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
+ new FlagSetsFilterImpl(new HashSet<>()),
+ fallbackTreatmentCalculator
+ );
+ assertEquals("off", client.getTreatment("adil@relateiq.com", "test1"));
+ assertEquals("off-fallback", client.getTreatment("adil@relateiq.com", "test2"));
+ assertEquals(Treatments.CONTROL, client.getTreatment("adil@relateiq.com", "test3"));
+
+ assertEquals("off", client.getTreatmentWithConfig("adil@relateiq.com", "test1").treatment());
+ assertEquals(null, client.getTreatmentWithConfig("adil@relateiq.com", "test1").config());
+ assertEquals("off-fallback", client.getTreatmentWithConfig("adil@relateiq.com", "test2").treatment());
+ assertEquals(fallbcakConfigByFlag, client.getTreatmentWithConfig("adil@relateiq.com", "test2").config());
+ assertEquals(Treatments.CONTROL, client.getTreatmentWithConfig("adil@relateiq.com", "test3").treatment());
+ assertEquals(null, client.getTreatmentWithConfig("adil@relateiq.com", "test3").config());
+
+ result = client.getTreatments("adil@relateiq.com", Arrays.asList("test1", "test2", "test3"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals(Treatments.CONTROL, result.get("test3"));
+
+ results = client.getTreatmentsWithConfig("adil@relateiq.com", Arrays.asList("test1", "test2", "test3"));
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals(Treatments.CONTROL, results.get("test3").treatment());
+ assertEquals(null, results.get("test3").config());
+
+ result = client.getTreatmentsByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals(Treatments.CONTROL, result.get("test3"));
+
+ result = client.getTreatmentsByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", result.get("test1"));
+ assertEquals("off-fallback", result.get("test2"));
+ assertEquals(Treatments.CONTROL, result.get("test3"));
+
+ results = client.getTreatmentsWithConfigByFlagSet("adil@relateiq.com", "flag");
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals(Treatments.CONTROL, results.get("test3").treatment());
+ assertEquals(null, results.get("test3").config());
+
+ results = client.getTreatmentsWithConfigByFlagSets("adil@relateiq.com", Arrays.asList("flag"));
+ assertEquals("off", results.get("test1").treatment());
+ assertEquals(null, results.get("test1").config());
+ assertEquals("off-fallback", results.get("test2").treatment());
+ assertEquals(fallbcakConfigByFlag, results.get("test2").config());
+ assertEquals(Treatments.CONTROL, results.get("test3").treatment());
+ assertEquals(null, results.get("test3").config());
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
index bba824527..4bdbc598d 100644
--- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
+++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java
@@ -4,6 +4,8 @@
import io.split.SplitMockServer;
import io.split.client.api.SplitView;
import io.split.client.dtos.EvaluationOptions;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.CustomDispatcher;
import io.split.storages.enums.OperationMode;
@@ -712,10 +714,10 @@ public void testPluggableMode() throws IOException, URISyntaxException {
Assert.assertTrue(events.stream().anyMatch(e -> "keyProperties".equals(e.getEventDto().key) && e.getEventDto().properties != null));
Assert.assertEquals(3, splits.size());
- Assert.assertTrue(splits.stream().anyMatch(sw -> "first.name".equals(sw.name)));
- Assert.assertTrue(splits.stream().anyMatch(sw -> "second.name".equals(sw.name)));
- Assert.assertEquals("on", client.getTreatment("key", "first.name"));
- Assert.assertEquals("off", client.getTreatmentWithConfig("FakeKey", "second.name").treatment());
+ Assert.assertTrue(splits.stream().anyMatch(sw -> "first-name".equals(sw.name)));
+ Assert.assertTrue(splits.stream().anyMatch(sw -> "second-name".equals(sw.name)));
+ Assert.assertEquals("on", client.getTreatment("key", "first-name"));
+ Assert.assertEquals("off", client.getTreatmentWithConfig("FakeKey", "second-name").treatment());
Assert.assertEquals("control", client.getTreatment("FakeKey", "noSplit"));
Assert.assertEquals("on", client.getTreatment("bilal@@split.io", "rbs_flag", new HashMap() {{
put("email", "bilal@@split.io");
@@ -726,8 +728,8 @@ public void testPluggableMode() throws IOException, URISyntaxException {
List impressions = customStorageWrapper.getImps();
Assert.assertEquals(4, impressions.size());
- Assert.assertTrue(impressions.stream().anyMatch(imp -> "first.name".equals(imp.getKeyImpression().feature) && "on".equals(imp.getKeyImpression().treatment)));
- Assert.assertTrue(impressions.stream().anyMatch(imp -> "second.name".equals(imp.getKeyImpression().feature) && "off".equals(imp.getKeyImpression().treatment)));
+ Assert.assertTrue(impressions.stream().anyMatch(imp -> "first-name".equals(imp.getKeyImpression().feature) && "on".equals(imp.getKeyImpression().treatment)));
+ Assert.assertTrue(impressions.stream().anyMatch(imp -> "second-name".equals(imp.getKeyImpression().feature) && "off".equals(imp.getKeyImpression().treatment)));
Map latencies = customStorageWrapper.getLatencies();
@@ -1175,6 +1177,299 @@ public MockResponse dispatch(RecordedRequest request) {
splitServer.shutdown();
}
+ @Test
+ public void FallbackTreatmentGlobalAndByFlagTest() throws Exception {
+ String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.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=1602796638344&rbSince=-1":
+ return new MockResponse().setResponseCode(200).setBody("{\"ff\":{\"d\":[], \"s\":1602796638344, \"t\":1602796638344}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-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 server = new MockWebServer();
+ server.setDispatcher(dispatcher);
+
+ server.start();
+ String serverURL = String.format("http://%s:%s", server.getHostName(), server.getPort());
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-fallback", "{\"prop1\", \"val1\"}"),
+ new HashMap() {{ put("feature", new FallbackTreatment("off-fallback", "{\"prop2\", \"val2\"}")); }});
+
+ 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)
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
+ .build();
+
+ SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config);
+ SplitClient client = factory.client();
+ client.blockUntilReady();
+
+ Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle"));
+ Assert.assertEquals("off-fallback", client.getTreatmentWithConfig("user2", "feature").treatment());
+ Assert.assertEquals("{\"prop2\", \"val2\"}", client.getTreatmentWithConfig("user2", "feature").config());
+ Assert.assertEquals("on-fallback", client.getTreatmentWithConfig("user2", "feature2").treatment());
+ Assert.assertEquals("{\"prop1\", \"val1\"}", client.getTreatmentWithConfig("user2", "feature2").config());
+
+ client.destroy();
+ boolean check1 = false;
+ for (int i=0; i < allRequests.size(); i++ ) {
+ if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) {
+ String body = allRequests.get(i).getBody().readUtf8();
+ if (body.contains("user1")) {
+ check1 = true;
+ Assert.assertTrue(body.contains("without_impression_toggle"));
+ }
+ }
+ }
+ server.shutdown();
+ Assert.assertTrue(check1);
+ }
+
+ @Test
+ public void FallbackTreatmentGlobalTest() throws Exception {
+ String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.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=1602796638344&rbSince=-1":
+ return new MockResponse().setResponseCode(200).setBody("{\"ff\":{\"d\":[], \"s\":1602796638344, \"t\":1602796638344}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-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 server = new MockWebServer();
+ server.setDispatcher(dispatcher);
+
+ server.start();
+ String serverURL = String.format("http://%s:%s", server.getHostName(), server.getPort());
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-fallback", "{\"prop1\", \"val1\"}"),
+ null);
+
+ 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)
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
+ .build();
+
+ SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config);
+ SplitClient client = factory.client();
+ client.blockUntilReady();
+
+ Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle"));
+ Assert.assertEquals("on-fallback", client.getTreatmentWithConfig("user2", "feature").treatment());
+ Assert.assertEquals("{\"prop1\", \"val1\"}", client.getTreatmentWithConfig("user2", "feature").config());
+ Assert.assertEquals("on-fallback", client.getTreatmentWithConfig("user2", "feature2").treatment());
+ Assert.assertEquals("{\"prop1\", \"val1\"}", client.getTreatmentWithConfig("user2", "feature2").config());
+
+ client.destroy();
+ boolean check1 = false;
+ for (int i=0; i < allRequests.size(); i++ ) {
+ if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) {
+ String body = allRequests.get(i).getBody().readUtf8();
+ if (body.contains("user1")) {
+ check1 = true;
+ Assert.assertTrue(body.contains("without_impression_toggle"));
+ }
+ }
+ }
+ server.shutdown();
+ Assert.assertTrue(check1);
+ }
+
+ @Test
+ public void FallbackTreatmentByFlagTest() throws Exception {
+ String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.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=1602796638344&rbSince=-1":
+ return new MockResponse().setResponseCode(200).setBody("{\"ff\":{\"d\":[], \"s\":1602796638344, \"t\":1602796638344}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-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 server = new MockWebServer();
+ server.setDispatcher(dispatcher);
+
+ server.start();
+ String serverURL = String.format("http://%s:%s", server.getHostName(), server.getPort());
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(null,
+ new HashMap() {{ put("feature", new FallbackTreatment("off-fallback", "{\"prop2\", \"val2\"}")); }});
+
+ 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)
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
+ .build();
+
+ SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config);
+ SplitClient client = factory.client();
+ client.blockUntilReady();
+
+ Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle"));
+ Assert.assertEquals("off-fallback", client.getTreatmentWithConfig("user2", "feature").treatment());
+ Assert.assertEquals("{\"prop2\", \"val2\"}", client.getTreatmentWithConfig("user2", "feature").config());
+ Assert.assertEquals("control", client.getTreatmentWithConfig("user2", "feature2").treatment());
+ Assert.assertEquals(null, client.getTreatmentWithConfig("user2", "feature2").config());
+
+ client.destroy();
+ boolean check1 = false;
+ for (int i=0; i < allRequests.size(); i++ ) {
+ if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) {
+ String body = allRequests.get(i).getBody().readUtf8();
+ if (body.contains("user1")) {
+ check1 = true;
+ Assert.assertTrue(body.contains("without_impression_toggle"));
+ }
+ }
+ }
+ server.shutdown();
+ Assert.assertTrue(check1);
+ }
+
+ @Test
+ public void FallbackTreatmentNotReadyTest() throws Exception {
+ String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.json")), StandardCharsets.UTF_8);
+ List allRequests = new ArrayList<>();
+ Dispatcher dispatcher = new Dispatcher() {
+ @Override
+ public MockResponse dispatch(RecordedRequest request) throws InterruptedException {
+ allRequests.add(request);
+ switch (request.getPath()) {
+ case "/api/splitChanges?s=1.3&since=-1&rbSince=-1":
+ Thread.sleep(1000);
+ return new MockResponse().setResponseCode(200).setBody(splits);
+ case "/api/splitChanges?s=1.3&since=1602796638344&rbSince=-1":
+ return new MockResponse().setResponseCode(200).setBody("{\"ff\":{\"d\":[], \"s\":1602796638344, \"t\":1602796638344}, \"rbs\":{\"d\":[],\"s\":-1,\"t\":-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 server = new MockWebServer();
+ server.setDispatcher(dispatcher);
+
+ server.start();
+ String serverURL = String.format("http://%s:%s", server.getHostName(), server.getPort());
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-fallback", "{\"prop1\", \"val1\"}"),
+ null);
+
+ 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)
+ .fallbackTreatments(fallbackTreatmentsConfiguration)
+ .build();
+
+ SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config);
+ SplitClient client = factory.client();
+
+ Assert.assertEquals("on-fallback", client.getTreatment("user1", "without_impression_toggle"));
+ Assert.assertEquals("on-fallback", client.getTreatment("user2", "feature"));
+ client.blockUntilReady();
+
+ client.destroy();
+ boolean check1 = false, check2 = false;
+ for (int i=0; i < allRequests.size(); i++ ) {
+ if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) {
+ String body = allRequests.get(i).getBody().readUtf8();
+ if (body.contains("user2")) {
+ check1 = true;
+ Assert.assertTrue(body.contains("feature"));
+ Assert.assertTrue(body.contains("fallback - not ready"));
+ }
+ if (body.contains("user1")) {
+ check2 = true;
+ Assert.assertTrue(body.contains("without_impression_toggle"));
+ Assert.assertTrue(body.contains("fallback - not ready"));
+ }
+ }
+ }
+ server.shutdown();
+ Assert.assertTrue(check1);
+ Assert.assertTrue(check2);
+ }
+
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/SplitFactoryImplTest.java b/client/src/test/java/io/split/client/SplitFactoryImplTest.java
index 9826b47e2..dcf51055c 100644
--- a/client/src/test/java/io/split/client/SplitFactoryImplTest.java
+++ b/client/src/test/java/io/split/client/SplitFactoryImplTest.java
@@ -1,8 +1,12 @@
package io.split.client;
+import io.split.client.dtos.FallbackTreatment;
+import io.split.client.dtos.FallbackTreatmentCalculatorImp;
+import io.split.client.dtos.FallbackTreatmentsConfiguration;
import io.split.client.dtos.ProxyConfiguration;
import io.split.client.impressions.ImpressionsManager;
import io.split.client.utils.FileTypeEnum;
+import io.split.engine.evaluator.EvaluatorImp;
import io.split.integrations.IntegrationsConfig;
import io.split.service.SplitHttpClientImpl;
import io.split.storages.enums.OperationMode;
@@ -56,11 +60,26 @@ public void testFactoryInstantiation() throws Exception {
.authServiceURL(AUTH_SERVICE)
.setBlockUntilReadyTimeout(10000)
.telemetryURL(SplitClientConfig.TELEMETRY_ENDPOINT)
+ .fallbackTreatments(new FallbackTreatmentsConfiguration(new FallbackTreatment("on"), null))
.build();
SplitFactoryImpl splitFactory = new SplitFactoryImpl(API_KEY, splitClientConfig);
assertNotNull(splitFactory.client());
assertNotNull(splitFactory.manager());
+
+ Field fallbackField = SplitClientImpl.class.getDeclaredField("_fallbackTreatmentCalculator");
+ fallbackField.setAccessible(true);
+ FallbackTreatmentCalculatorImp fallbackCalc = (FallbackTreatmentCalculatorImp) fallbackField.get(splitFactory.client());
+ assertNotNull(fallbackCalc);
+
+ Field evalField = SplitClientImpl.class.getDeclaredField("_evaluator");
+ evalField.setAccessible(true);
+ EvaluatorImp evaluatorImp = (EvaluatorImp) evalField.get(splitFactory.client());
+ assertNotNull(fallbackCalc);
+ fallbackField = EvaluatorImp.class.getDeclaredField("_fallbackTreatmentCalculator");
+ fallbackField.setAccessible(true);
+ fallbackCalc = (FallbackTreatmentCalculatorImp) fallbackField.get(evaluatorImp);
+ assertNotNull(fallbackCalc);
}
@Test
@@ -365,6 +384,20 @@ public void testFactoryConsumerInstantiation() throws Exception {
Thread.sleep(1500);
Mockito.verify(userStorageWrapper, Mockito.times(1)).connect();
Mockito.verify(telemetrySynchronizer, Mockito.times(1)).synchronizeConfig(Mockito.anyObject(), Mockito.anyLong(), Mockito.anyObject(), Mockito.anyObject());
+
+ Field fallbackField = SplitClientImpl.class.getDeclaredField("_fallbackTreatmentCalculator");
+ fallbackField.setAccessible(true);
+ FallbackTreatmentCalculatorImp fallbackCalc = (FallbackTreatmentCalculatorImp) fallbackField.get(splitFactory.client());
+ assertNotNull(fallbackCalc);
+
+ Field evalField = SplitClientImpl.class.getDeclaredField("_evaluator");
+ evalField.setAccessible(true);
+ EvaluatorImp evaluatorImp = (EvaluatorImp) evalField.get(splitFactory.client());
+ assertNotNull(fallbackCalc);
+ fallbackField = EvaluatorImp.class.getDeclaredField("_fallbackTreatmentCalculator");
+ fallbackField.setAccessible(true);
+ fallbackCalc = (FallbackTreatmentCalculatorImp) fallbackField.get(evaluatorImp);
+ assertNotNull(fallbackCalc);
}
@Test
diff --git a/client/src/test/java/io/split/client/dtos/FallbackTreatmentCalculationImpTest.java b/client/src/test/java/io/split/client/dtos/FallbackTreatmentCalculationImpTest.java
new file mode 100644
index 000000000..4e082e007
--- /dev/null
+++ b/client/src/test/java/io/split/client/dtos/FallbackTreatmentCalculationImpTest.java
@@ -0,0 +1,40 @@
+package io.split.client.dtos;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class FallbackTreatmentCalculationImpTest {
+
+ @Test
+ public void TestWorks() {
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on"), null);
+ FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ assertEquals("on", fallbackTreatmentCalculator.resolve("anyflag", "exception").getTreatment());
+ assertEquals("fallback - exception", fallbackTreatmentCalculator.resolve("anyflag", "exception").getLabel());
+
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on"),
+ new HashMap() {{ put("flag", new FallbackTreatment("off")); }} );
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ assertEquals("on", fallbackTreatmentCalculator.resolve("anyflag", "exception").getTreatment());
+ assertEquals("fallback - exception", fallbackTreatmentCalculator.resolve("anyflag", "exception").getLabel());
+ assertEquals("off", fallbackTreatmentCalculator.resolve("flag", "exception").getTreatment());
+ assertEquals("fallback - exception", fallbackTreatmentCalculator.resolve("flag", "exception").getLabel());
+
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(null,
+ new HashMap() {{ put("flag", new FallbackTreatment("off")); }} );
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ assertEquals("control", fallbackTreatmentCalculator.resolve("anyflag", "exception").getTreatment());
+ assertEquals("exception", fallbackTreatmentCalculator.resolve("anyflag", "exception").getLabel());
+ assertEquals("off", fallbackTreatmentCalculator.resolve("flag", "exception").getTreatment());
+ assertEquals("fallback - exception", fallbackTreatmentCalculator.resolve("flag", "exception").getLabel());
+ }
+}
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 5cc6d01d9..5b0a024a6 100644
--- a/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java
+++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java
@@ -2,6 +2,7 @@
import com.google.common.collect.Lists;
import io.split.client.dtos.ConditionType;
+import io.split.client.dtos.FallbackTreatmentCalculatorImp;
import io.split.client.dtos.MatcherCombiner;
import io.split.client.dtos.Partition;
import io.split.client.interceptors.FlagSetsFilter;
@@ -174,7 +175,8 @@ private Evaluator buildEvaluatorAndLoadCache(boolean killed, int trafficAllocati
SplitCache splitCache = new InMemoryCacheImp(flagSetsFilter);
SegmentCache segmentCache = new SegmentCacheInMemoryImpl();
RuleBasedSegmentCache ruleBasedSegmentCache = new RuleBasedSegmentCacheInMemoryImp();
- Evaluator evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache);
+ FallbackTreatmentCalculatorImp fallbackTreatmentCalculatorImp = new FallbackTreatmentCalculatorImp(null);
+ Evaluator evaluator = new EvaluatorImp(splitCache, segmentCache, ruleBasedSegmentCache, fallbackTreatmentCalculatorImp);
Partition partition = new Partition();
partition.treatment = ON_TREATMENT;
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 cf166bd2b..05a87a611 100644
--- a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java
+++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java
@@ -1,8 +1,6 @@
package io.split.engine.evaluator;
-import io.split.client.dtos.ConditionType;
-import io.split.client.dtos.Partition;
-import io.split.client.dtos.Prerequisites;
+import io.split.client.dtos.*;
import io.split.client.utils.Json;
import io.split.engine.experiments.ParsedCondition;
import io.split.engine.experiments.ParsedSplit;
@@ -50,7 +48,7 @@ public void before() {
_splitCacheConsumer = Mockito.mock(SplitCacheConsumer.class);
_segmentCacheConsumer = Mockito.mock(SegmentCacheConsumer.class);
_ruleBasedSegmentCacheConsumer = Mockito.mock(RuleBasedSegmentCacheConsumer.class);
- _evaluator = new EvaluatorImp(_splitCacheConsumer, _segmentCacheConsumer, _ruleBasedSegmentCacheConsumer);
+ _evaluator = new EvaluatorImp(_splitCacheConsumer, _segmentCacheConsumer, _ruleBasedSegmentCacheConsumer, new FallbackTreatmentCalculatorImp(null));
_matcher = Mockito.mock(CombiningMatcher.class);
_evaluationContext = Mockito.mock(EvaluationContext.class);
@@ -226,4 +224,76 @@ public void evaluateWithPrerequisites() {
assertEquals(Labels.KILLED, result.label);
assertEquals(CHANGE_NUMBER, result.changeNumber);
}
+
+ @Test
+ public void evaluateFallbackTreatmentWorks() {
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(null);
+ FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on"), null);
+ FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ _evaluator = new EvaluatorImp(_splitCacheConsumer, _segmentCacheConsumer, _ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator);
+
+ EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("on", result.treatment);
+ assertEquals("fallback - definition not found", result.label);
+
+ ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, null, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), false, null);
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("on", result.treatment);
+ assertEquals("fallback - exception", result.label);
+
+ // using byflag only
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(null);
+ Mockito.when(_splitCacheConsumer.get("another_name")).thenReturn(null);
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(null, new HashMap() {{ put(SPLIT_NAME, new FallbackTreatment("off")); }} );
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ _evaluator = new EvaluatorImp(_splitCacheConsumer, _segmentCacheConsumer, _ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator);
+
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("off", result.treatment);
+ assertEquals("fallback - definition not found", result.label);
+
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, "another_name", null);
+ assertEquals("control", result.treatment);
+ assertEquals("definition not found", result.label);
+
+ split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, null, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), false, null);
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("off", result.treatment);
+ assertEquals("fallback - exception", result.label);
+
+ split = new ParsedSplit("another_name", 0, false, DEFAULT_TREATMENT_VALUE, _conditions, null, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), false, null);
+ Mockito.when(_splitCacheConsumer.get("another_name")).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, "another_name", null);
+ assertEquals("control", result.treatment);
+ assertEquals("exception", result.label);
+
+ // with byflag
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(null);
+ Mockito.when(_splitCacheConsumer.get("another_name")).thenReturn(null);
+ fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on"), new HashMap() {{ put(SPLIT_NAME, new FallbackTreatment("off")); }} );
+ fallbackTreatmentCalculator = new FallbackTreatmentCalculatorImp(fallbackTreatmentsConfiguration);
+ _evaluator = new EvaluatorImp(_splitCacheConsumer, _segmentCacheConsumer, _ruleBasedSegmentCacheConsumer, fallbackTreatmentCalculator);
+
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("off", result.treatment);
+ assertEquals("fallback - definition not found", result.label);
+
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, "another_name", null);
+ assertEquals("on", result.treatment);
+ assertEquals("fallback - definition not found", result.label);
+
+ split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, null, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), false, null);
+ Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null);
+ assertEquals("off", result.treatment);
+ assertEquals("fallback - exception", result.label);
+
+ split = new ParsedSplit("another_name", 0, false, DEFAULT_TREATMENT_VALUE, _conditions, null, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), false, null);
+ Mockito.when(_splitCacheConsumer.get("another_name")).thenReturn(split);
+ result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, "another_name", null);
+ assertEquals("on", result.treatment);
+ assertEquals("fallback - exception", result.label);
+ }
}
\ No newline at end of file
diff --git a/client/src/test/java/io/split/engine/experiments/RuleBasedSegmentParserTest.java b/client/src/test/java/io/split/engine/experiments/RuleBasedSegmentParserTest.java
index 526e44491..add3eb2a5 100644
--- a/client/src/test/java/io/split/engine/experiments/RuleBasedSegmentParserTest.java
+++ b/client/src/test/java/io/split/engine/experiments/RuleBasedSegmentParserTest.java
@@ -63,7 +63,7 @@ public void works() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher employeesMatcherLogic = AttributeMatcher.vanilla(new UserDefinedSegmentMatcher(EMPLOYEES));
@@ -72,7 +72,7 @@ public void works() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -103,14 +103,14 @@ public void worksForTwoConditions() {
List conditions = Lists.newArrayList(c1, c2);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
ParsedCondition parsedCondition1 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), fullyRollout);
ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), turnOff);
List listOfParsedConditions = Lists.newArrayList(parsedCondition1, parsedCondition2);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfParsedConditions, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfParsedConditions, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -135,7 +135,7 @@ public void successForLongConditions() {
}
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
Assert.assertNotNull(parser.parse(ruleBasedSegment));
}
@@ -163,7 +163,7 @@ public void worksWithAttributes() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher employeesMatcherLogic = new AttributeMatcher("name", new UserDefinedSegmentMatcher(EMPLOYEES), false);
@@ -172,7 +172,7 @@ public void worksWithAttributes() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -191,7 +191,7 @@ public void lessThanOrEqualTo() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher ageLessThan10Logic = new AttributeMatcher("age", new LessThanOrEqualToMatcher(10, DataType.NUMBER), false);
@@ -199,7 +199,7 @@ public void lessThanOrEqualTo() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -217,7 +217,7 @@ public void equalTo() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher equalToMatcher = new AttributeMatcher("age", new EqualToMatcher(10, DataType.NUMBER), true);
@@ -225,7 +225,7 @@ public void equalTo() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -243,7 +243,7 @@ public void equalToNegativeNumber() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher ageEqualTo10Logic = new AttributeMatcher("age", new EqualToMatcher(-10, DataType.NUMBER), false);
@@ -251,7 +251,7 @@ public void equalToNegativeNumber() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -275,7 +275,7 @@ public void between() {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher ageBetween10And11Logic = new AttributeMatcher("age", new BetweenMatcher(10, 12, DataType.NUMBER), false);
@@ -283,7 +283,7 @@ public void between() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
@@ -530,7 +530,7 @@ public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) {
List conditions = Lists.newArrayList(c);
RuleBasedSegmentParser parser = new RuleBasedSegmentParser();
- RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first.name", conditions, 1);
+ RuleBasedSegment ruleBasedSegment = makeRuleBasedSegment("first-name", conditions, 1);
ParsedRuleBasedSegment actual = parser.parse(ruleBasedSegment);
AttributeMatcher attrMatcher = new AttributeMatcher("products", m, false);
@@ -538,7 +538,7 @@ public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, null);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first.name", listOfMatcherAndSplits, "user", 1,
+ ParsedRuleBasedSegment expected = ParsedRuleBasedSegment.createParsedRuleBasedSegmentForTests ("first-name", listOfMatcherAndSplits, "user", 1,
new ArrayList<>(), new ArrayList<>());
Assert.assertEquals(actual, expected);
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 4676a8c3b..d9e945bfa 100644
--- a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java
+++ b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java
@@ -85,7 +85,7 @@ public void works() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -95,7 +95,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
assertTrue(expected.hashCode() != 0);
@@ -128,7 +128,7 @@ public void worksWithConfig() {
Map configurations = new HashMap<>();
configurations.put("on", "{\"size\":15,\"test\":20}");
configurations.put("off", "{\"size\":10}");
- Split split = makeSplit("first.name", 123, conditions, 1, configurations);
+ Split split = makeSplit("first-name", 123, conditions, 1, configurations);
ParsedSplit actual = parser.parse(split);
@@ -138,7 +138,7 @@ public void worksWithConfig() {
ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions);
List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition);
- ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF,
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF,
listOfMatcherAndSplits, "user", 1, 1, configurations, new HashSet<>(), false, new PrerequisitesMatcher(null));
Assert.assertEquals(actual.parsedConditions(), expected.parsedConditions());
@@ -184,7 +184,7 @@ public void worksForTwoConditions() {
List conditions = Lists.newArrayList(c1, c2);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -192,7 +192,7 @@ public void worksForTwoConditions() {
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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfParsedConditions, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
@@ -218,7 +218,7 @@ public void successForLongConditions() {
conditions.add(c);
}
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
Assert.assertNotNull(parser.parse(split));
}
@@ -251,7 +251,7 @@ public void worksWithAttributes() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -261,7 +261,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
@@ -285,7 +285,7 @@ public void lessThanOrEqualTo() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -294,7 +294,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
@@ -317,7 +317,7 @@ public void equalTo() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -326,7 +326,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
@@ -348,7 +348,7 @@ public void equalToNegativeNumber() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -357,7 +357,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
@@ -384,7 +384,7 @@ public void between() {
List conditions = Lists.newArrayList(c);
- Split split = makeSplit("first.name", 123, conditions, 1);
+ Split split = makeSplit("first-name", 123, conditions, 1);
ParsedSplit actual = parser.parse(split);
@@ -393,7 +393,7 @@ 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, null, false, new PrerequisitesMatcher(null));
+ ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first-name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, null, false, new PrerequisitesMatcher(null));
compareParsed(actual, expected);
}
diff --git a/client/src/test/java/io/split/inputValidation/FallbackTreatmentValidatorTest.java b/client/src/test/java/io/split/inputValidation/FallbackTreatmentValidatorTest.java
new file mode 100644
index 000000000..6bfc4bd9d
--- /dev/null
+++ b/client/src/test/java/io/split/inputValidation/FallbackTreatmentValidatorTest.java
@@ -0,0 +1,50 @@
+package io.split.inputValidation;
+
+import io.split.client.dtos.FallbackTreatment;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+public class FallbackTreatmentValidatorTest {
+
+ @Test
+ public void isValidTreatmentWorks() {
+ Assert.assertEquals("123asHs_-sdf", FallbackTreatmentValidator.isValidTreatment("123asHs_-sdf", "test"));
+
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment(new String(new char[101]).replace('\0', 'w'), "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment("", "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment(null, "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment("12@3asHs_-sdf", "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment("12#3asHs_-sdf", "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment("12!3asHs_-sdf", "test"));
+ Assert.assertEquals(null, FallbackTreatmentValidator.isValidTreatment("12^3asHs_-sdf", "test"));
+ }
+
+ @Test
+ public void isValidByFlagTreatmentWorks() {
+ HashMap byRef = new HashMap() {{ put("flag", new FallbackTreatment("12#2")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("flag", new FallbackTreatment("12%2")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("flag", new FallbackTreatment(new String(new char[101]).replace('\0', 'w'))); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("flag", new FallbackTreatment("12&2")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("", new FallbackTreatment("on")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("12#dd", new FallbackTreatment("on")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put(new String(new char[101]).replace('\0', 'w'), new FallbackTreatment("on")); }};
+ Assert.assertEquals(new HashMap<>(), FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test"));
+
+ byRef = new HashMap() {{ put("flag", new FallbackTreatment("123asHs_-sdf")); }};
+ Assert.assertEquals("123asHs_-sdf", FallbackTreatmentValidator.isValidByFlagTreatment(byRef, "test").get("flag").getTreatment());
+ }
+}
diff --git a/client/src/test/java/io/split/inputValidation/SplitNameValidatorTest.java b/client/src/test/java/io/split/inputValidation/SplitNameValidatorTest.java
index d8db6567c..cb325dfc6 100644
--- a/client/src/test/java/io/split/inputValidation/SplitNameValidatorTest.java
+++ b/client/src/test/java/io/split/inputValidation/SplitNameValidatorTest.java
@@ -22,9 +22,29 @@ public void isValidWorks() {
result = SplitNameValidator.isValid("", "test");
Assert.assertFalse(result.isPresent());
+ // test regex
+ result = SplitNameValidator.isValid("te#fg", "test");
+ Assert.assertFalse(result.isPresent());
+
+ // test regex
+ result = SplitNameValidator.isValid("te@fg", "test");
+ Assert.assertFalse(result.isPresent());
+
+ // test regex
+ result = SplitNameValidator.isValid("te&fg", "test");
+ Assert.assertFalse(result.isPresent());
+
+ // test regex
+ result = SplitNameValidator.isValid("te)fg", "test");
+ Assert.assertFalse(result.isPresent());
+
+ // test length
+ result = SplitNameValidator.isValid(new String(new char[101]).replace('\0', 'w'), "test");
+ Assert.assertFalse(result.isPresent());
+
// when split name have empty spaces
- result = SplitNameValidator.isValid(" split name test ", "test");
+ result = SplitNameValidator.isValid(" split-name-test ", "test");
Assert.assertTrue(result.isPresent());
- Assert.assertEquals("split name test", result.get());
+ Assert.assertEquals("split-name-test", result.get());
}
}
diff --git a/client/src/test/java/io/split/storages/pluggable/CustomStorageWrapperImp.java b/client/src/test/java/io/split/storages/pluggable/CustomStorageWrapperImp.java
index 728ffec78..8733f3d12 100644
--- a/client/src/test/java/io/split/storages/pluggable/CustomStorageWrapperImp.java
+++ b/client/src/test/java/io/split/storages/pluggable/CustomStorageWrapperImp.java
@@ -271,8 +271,8 @@ else if(key.startsWith(FLAG_SET))
private void updateCache(){
Condition condition = ConditionsTestUtil.makeUserDefinedSegmentCondition(ConditionType.WHITELIST,"segmentName" , Lists.newArrayList(ConditionsTestUtil.partition("on", 100)));
segmentStorage.put(PrefixAdapter.buildSegment("segmentName"), new SegmentImp(9874654L, "segmentName", Lists.newArrayList("key", "key2")));
- splitsStorage.put(PrefixAdapter.buildSplitKey("first.name"), makeSplit("first.name", 123, Lists.newArrayList(condition), 456478976L));
- splitsStorage.put(PrefixAdapter.buildSplitKey("second.name"), makeSplit("second.name", 321, Lists.newArrayList(), 568613L));
+ splitsStorage.put(PrefixAdapter.buildSplitKey("first-name"), makeSplit("first-name", 123, Lists.newArrayList(condition), 456478976L));
+ splitsStorage.put(PrefixAdapter.buildSplitKey("second-name"), makeSplit("second-name", 321, Lists.newArrayList(), 568613L));
splitsStorage.put(PrefixAdapter.buildSplitKey("rbs_flag"), Json.fromJson("{\"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}", Split.class));
ruleBasedSegmentStorage.put(PrefixAdapter.buildRuleBasedSegmentKey("sample_rule_based_segment"), Json.fromJson( "{\"changeNumber\":5,\"name\":\"sample_rule_based_segment\",\"status\":\"ACTIVE\",\"trafficTypeName\":\"user\",\"excluded\":{\"keys\":[\"mauro@split.io\"],\"segments\":[]},\"conditions\":[{\"conditionType\":\"ROLLOUT\",\"matcherGroup\":{\"combiner\":\"AND\",\"matchers\":[{\"keySelector\":{\"trafficType\":\"user\",\"attribute\":\"email\"},\"matcherType\":\"ENDS_WITH\",\"negate\":false,\"whitelistMatcherData\":{\"whitelist\":[\"@split.io\"]}}]}}]}", RuleBasedSegment.class));
_flagSets.put("SPLITIO.flagSet.set1", new HashSet<>(new ArrayList<>(Arrays.asList("flag1", "flag2"))));
diff --git a/okhttp-modules/pom.xml b/okhttp-modules/pom.xml
index fc646f3d7..ec03d10dd 100644
--- a/okhttp-modules/pom.xml
+++ b/okhttp-modules/pom.xml
@@ -5,10 +5,10 @@
java-client-parent
io.split.client
- 4.17.0
+ 4.18.0
4.0.0
- 4.17.0
+ 4.18.0
okhttp-modules
jar
http-modules
diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml
index 4b7e01562..94604cfdc 100644
--- a/pluggable-storage/pom.xml
+++ b/pluggable-storage/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.17.0
+ 4.18.0
2.1.0
diff --git a/pom.xml b/pom.xml
index c20814b19..90b70d29b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
io.split.client
java-client-parent
- 4.17.0
+ 4.18.0
diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml
index 8bf6c4246..c39bc2cd4 100644
--- a/redis-wrapper/pom.xml
+++ b/redis-wrapper/pom.xml
@@ -6,7 +6,7 @@
java-client-parent
io.split.client
- 4.17.0
+ 4.18.0
redis-wrapper
3.1.1
diff --git a/testing/pom.xml b/testing/pom.xml
index b7f0bf906..cd4ae5504 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -5,11 +5,11 @@
io.split.client
java-client-parent
- 4.17.0
+ 4.18.0
java-client-testing
jar
- 4.17.0
+ 4.18.0
Java Client For Testing
Testing suite for Java SDK for Split