From 490cb27ac8f01e8ca41a185c09f202a0d820edc3 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Wed, 11 Dec 2024 12:22:12 -0800 Subject: [PATCH 1/9] impression toggle feature --- .../io/split/client/CacheUpdaterService.java | 2 +- .../split/client/HttpSplitChangeFetcher.java | 1 - .../java/io/split/client/SplitClientImpl.java | 26 ++- .../io/split/client/SplitFactoryImpl.java | 15 +- .../client/dtos/DecoratedImpression.java | 14 ++ .../main/java/io/split/client/dtos/Split.java | 1 + .../impressions/ImpressionsManager.java | 6 +- .../impressions/ImpressionsManagerImpl.java | 43 ++++- .../split/engine/evaluator/EvaluatorImp.java | 31 +++- .../split/engine/experiments/ParsedSplit.java | 27 ++- .../split/engine/experiments/SplitParser.java | 22 ++- .../storages/memory/InMemoryCacheImp.java | 3 +- .../io/split/client/SplitClientImplTest.java | 115 ++++++------ .../io/split/client/SplitManagerImplTest.java | 10 +- .../ImpressionsManagerImplTest.java | 175 ++++++++++-------- .../evaluator/EvaluatorIntegrationTest.java | 8 +- .../split/engine/evaluator/EvaluatorTest.java | 14 +- .../engine/experiments/SplitFetcherTest.java | 2 +- .../engine/experiments/SplitParserTest.java | 18 +- .../storages/memory/InMemoryCacheTest.java | 36 ++-- 20 files changed, 341 insertions(+), 228 deletions(-) create mode 100644 client/src/main/java/io/split/client/dtos/DecoratedImpression.java diff --git a/client/src/main/java/io/split/client/CacheUpdaterService.java b/client/src/main/java/io/split/client/CacheUpdaterService.java index 231757ae7..d69c66d58 100644 --- a/client/src/main/java/io/split/client/CacheUpdaterService.java +++ b/client/src/main/java/io/split/client/CacheUpdaterService.java @@ -52,7 +52,7 @@ public void updateCache(Map map) { String treatment = conditions.size() > 0 ? Treatments.CONTROL : localhostSplit.treatment; configurations.put(localhostSplit.treatment, localhostSplit.config); - split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations, new HashSet<>()); + split = new ParsedSplit(splitName, 0, false, treatment,conditions, LOCALHOST, 0, 100, 0, 0, configurations, new HashSet<>(), true); parsedSplits.removeIf(parsedSplit -> parsedSplit.feature().equals(splitName)); parsedSplits.add(split); } diff --git a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java index 9f8d2036b..a3e234a3e 100644 --- a/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java +++ b/client/src/main/java/io/split/client/HttpSplitChangeFetcher.java @@ -82,7 +82,6 @@ public SplitChange fetch(long since, FetchOptions options) { String.format("Could not retrieve splitChanges since %s; http return code %s", since, response.statusCode()) ); } - return Json.fromJson(response.body(), SplitChange.class); } catch (Exception e) { throw new IllegalStateException(String.format("Problem fetching splitChanges since %s: %s", since, e), e); diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index e876871e3..83bf0c66b 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -2,6 +2,7 @@ import io.split.client.api.Key; import io.split.client.api.SplitResult; +import io.split.client.dtos.DecoratedImpression; import io.split.client.dtos.Event; import io.split.client.events.EventsStorageProducer; import io.split.client.impressions.Impression; @@ -356,7 +357,8 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu String.format("sdk.%s", methodEnum.getMethod()), _config.labelsEnabled() ? result.label : null, result.changeNumber, - attributes + attributes, + result.track ); _telemetryEvaluationProducer.recordLatency(methodEnum, System.currentTimeMillis() - initTime); return new SplitResult(result.treatment, result.configurations); @@ -435,7 +437,7 @@ private Map getTreatmentsBySetsWithConfigInternal(String ma private Map processEvaluatorResult(Map evaluatorResult, MethodEnum methodEnum, String matchingKey, String bucketingKey, Map attributes, long initTime){ - List impressions = new ArrayList<>(); + List decoratedImpressions = new ArrayList<>(); Map result = new HashMap<>(); evaluatorResult.keySet().forEach(t -> { if (evaluatorResult.get(t).treatment.equals(Treatments.CONTROL) && evaluatorResult.get(t).label. @@ -445,13 +447,16 @@ private Map processEvaluatorResult(Map 0) { - _impressionManager.track(impressions); + if (decoratedImpressions.size() > 0) { + _impressionManager.track(decoratedImpressions); } return result; } @@ -501,10 +506,13 @@ private Set filterSetsAreInConfig(Set sets, MethodEnum methodEnu return setsToReturn; } private void recordStats(String matchingKey, String bucketingKey, String featureFlagName, long start, String result, - String operation, String label, Long changeNumber, Map attributes) { + String operation, String label, Long changeNumber, Map attributes, boolean track) { try { - _impressionManager.track(Stream.of(new Impression(matchingKey, bucketingKey, featureFlagName, result, System.currentTimeMillis(), - label, changeNumber, attributes)).collect(Collectors.toList())); + _impressionManager.track(Stream.of( + new DecoratedImpression( + new Impression(matchingKey, bucketingKey, featureFlagName, result, System.currentTimeMillis(), + label, changeNumber, attributes), + track)).collect(Collectors.toList())); } catch (Throwable t) { _log.error("Exception", t); } diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 3102d3e17..41a78463b 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -634,9 +634,11 @@ private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config, ImpressionListener listener = !impressionListeners.isEmpty() ? new ImpressionListener.FederatedImpressionListener(impressionListeners) : null; + counter = new ImpressionCounter(); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(listener != null, _uniqueKeysTracker, counter); + switch (config.impressionsMode()) { case OPTIMIZED: - counter = new ImpressionCounter(); ImpressionObserver impressionObserver = new ImpressionObserver(config.getLastSeenCacheSize()); processImpressionStrategy = new ProcessImpressionOptimized(listener != null, impressionObserver, counter, _telemetryStorageProducer); @@ -646,13 +648,12 @@ private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config, processImpressionStrategy = new ProcessImpressionDebug(listener != null, impressionObserver); break; case NONE: - counter = new ImpressionCounter(); - processImpressionStrategy = new ProcessImpressionNone(listener != null, _uniqueKeysTracker, counter); + processImpressionStrategy = processImpressionNone; break; } return ImpressionsManagerImpl.instance(config, _telemetryStorageProducer, impressionsStorageConsumer, impressionsStorageProducer, - _impressionsSender, processImpressionStrategy, counter, listener); + _impressionsSender, processImpressionNone, processImpressionStrategy, counter, listener); } private SDKMetadata createSdkMetadata(boolean ipAddressEnabled, String splitSdkVersion) { @@ -690,15 +691,15 @@ private void manageSdkReady(SplitClientConfig config) { } private UniqueKeysTracker createUniqueKeysTracker(SplitClientConfig config) { - if (config.impressionsMode().equals(ImpressionsManager.Mode.NONE)) { +// if (config.impressionsMode().equals(ImpressionsManager.Mode.NONE)) { int uniqueKeysRefreshRate = config.operationMode().equals(OperationMode.STANDALONE) ? config.uniqueKeysRefreshRateInMemory() : config.uniqueKeysRefreshRateRedis(); return new UniqueKeysTrackerImp(_telemetrySynchronizer, uniqueKeysRefreshRate, config.filterUniqueKeysRefreshRate(), config.getThreadFactory()); - } - return null; +// } +// return null; } private SplitChangeFetcher createSplitChangeFetcher(SplitClientConfig splitClientConfig) { diff --git a/client/src/main/java/io/split/client/dtos/DecoratedImpression.java b/client/src/main/java/io/split/client/dtos/DecoratedImpression.java new file mode 100644 index 000000000..9ba55c60a --- /dev/null +++ b/client/src/main/java/io/split/client/dtos/DecoratedImpression.java @@ -0,0 +1,14 @@ +package io.split.client.dtos; + +import io.split.client.impressions.Impression; + +public class DecoratedImpression { + public Impression impression; + public boolean track; + + public DecoratedImpression(Impression impression, boolean track) { + this.impression = impression; + this.track = track; + } +} + diff --git a/client/src/main/java/io/split/client/dtos/Split.java b/client/src/main/java/io/split/client/dtos/Split.java index 825c36718..0f2147a95 100644 --- a/client/src/main/java/io/split/client/dtos/Split.java +++ b/client/src/main/java/io/split/client/dtos/Split.java @@ -18,6 +18,7 @@ public class Split { public int algo; public Map configurations; public HashSet sets; + public Boolean trackImpression = null; @Override public String toString() { diff --git a/client/src/main/java/io/split/client/impressions/ImpressionsManager.java b/client/src/main/java/io/split/client/impressions/ImpressionsManager.java index acadaaf8f..ce7c62011 100644 --- a/client/src/main/java/io/split/client/impressions/ImpressionsManager.java +++ b/client/src/main/java/io/split/client/impressions/ImpressionsManager.java @@ -1,5 +1,7 @@ package io.split.client.impressions; +import io.split.client.dtos.DecoratedImpression; + import java.util.List; public interface ImpressionsManager { @@ -10,14 +12,14 @@ public enum Mode { NONE } - void track(List impressions); + void track(List decoratedImpressions); void start(); void close(); final class NoOpImpressionsManager implements ImpressionsManager { @Override - public void track(List impressions) { /* do nothing */ } + public void track(List decoratedImpressions) { /* do nothing */ } @Override public void start(){ diff --git a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java index 384264332..e79efb6be 100644 --- a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java +++ b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java @@ -2,8 +2,10 @@ import com.google.common.annotations.VisibleForTesting; import io.split.client.SplitClientConfig; +import io.split.client.dtos.DecoratedImpression; import io.split.client.dtos.KeyImpression; import io.split.client.dtos.TestImpressions; +import io.split.client.impressions.strategy.ProcessImpressionNone; import io.split.client.impressions.strategy.ProcessImpressionStrategy; import io.split.client.utils.SplitExecutorFactory; import io.split.telemetry.domain.enums.ImpressionsDataTypeEnum; @@ -13,10 +15,13 @@ import java.io.Closeable; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.util.stream.Stream; import static com.google.common.base.Preconditions.checkNotNull; @@ -40,6 +45,8 @@ public class ImpressionsManagerImpl implements ImpressionsManager, Closeable { private TelemetryRuntimeProducer _telemetryRuntimeProducer; private ImpressionCounter _counter; private ProcessImpressionStrategy _processImpressionStrategy; + private ProcessImpressionNone _processImpressionNone; + private final int _impressionsRefreshRate; public static ImpressionsManagerImpl instance(SplitClientConfig config, @@ -47,11 +54,12 @@ public static ImpressionsManagerImpl instance(SplitClientConfig config, ImpressionsStorageConsumer impressionsStorageConsumer, ImpressionsStorageProducer impressionsStorageProducer, ImpressionsSender impressionsSender, + ProcessImpressionNone processImpressionNone, ProcessImpressionStrategy processImpressionStrategy, ImpressionCounter counter, ImpressionListener listener) throws URISyntaxException { return new ImpressionsManagerImpl(config, impressionsSender, telemetryRuntimeProducer, impressionsStorageConsumer, - impressionsStorageProducer, processImpressionStrategy, counter, listener); + impressionsStorageProducer, processImpressionNone, processImpressionStrategy, counter, listener); } public static ImpressionsManagerImpl instanceForTest(SplitClientConfig config, @@ -59,11 +67,12 @@ public static ImpressionsManagerImpl instanceForTest(SplitClientConfig config, TelemetryRuntimeProducer telemetryRuntimeProducer, ImpressionsStorageConsumer impressionsStorageConsumer, ImpressionsStorageProducer impressionsStorageProducer, + ProcessImpressionNone processImpressionNone, ProcessImpressionStrategy processImpressionStrategy, ImpressionCounter counter, ImpressionListener listener) { return new ImpressionsManagerImpl(config, impressionsSender, telemetryRuntimeProducer, impressionsStorageConsumer, - impressionsStorageProducer, processImpressionStrategy, counter, listener); + impressionsStorageProducer, processImpressionNone, processImpressionStrategy, counter, listener); } private ImpressionsManagerImpl(SplitClientConfig config, @@ -71,6 +80,7 @@ private ImpressionsManagerImpl(SplitClientConfig config, TelemetryRuntimeProducer telemetryRuntimeProducer, ImpressionsStorageConsumer impressionsStorageConsumer, ImpressionsStorageProducer impressionsStorageProducer, + ProcessImpressionNone processImpressionNone, ProcessImpressionStrategy processImpressionStrategy, ImpressionCounter impressionCounter, ImpressionListener impressionListener) { @@ -81,6 +91,7 @@ private ImpressionsManagerImpl(SplitClientConfig config, _impressionsStorageConsumer = checkNotNull(impressionsStorageConsumer); _impressionsStorageProducer = checkNotNull(impressionsStorageProducer); _telemetryRuntimeProducer = checkNotNull(telemetryRuntimeProducer); + _processImpressionNone = checkNotNull(processImpressionNone); _processImpressionStrategy = checkNotNull(processImpressionStrategy); _impressionsSender = impressionsSender; _counter = impressionCounter; @@ -110,15 +121,29 @@ public void start(){ } @Override - public void track(List impressions) { - if (null == impressions) { + public void track(List decoratedImpressions) { + if (null == decoratedImpressions) { return; } - - ImpressionsResult impressionsResult = _processImpressionStrategy.process(impressions); - List impressionsForLogs = impressionsResult.getImpressionsToQueue(); - List impressionsToListener = impressionsResult.getImpressionsToListener(); - + List impressionsForLogs = new ArrayList<>(); + List impressionsToListener = new ArrayList<>(); + + for (int i = 0; i < decoratedImpressions.size(); i++) { + ImpressionsResult impressionsResult; + if (decoratedImpressions.get(i).track) { + impressionsResult = _processImpressionStrategy.process(Stream.of( + decoratedImpressions.get(i).impression).collect(Collectors.toList())); + } else { + impressionsResult = _processImpressionNone.process(Stream.of( + decoratedImpressions.get(i).impression).collect(Collectors.toList())); + } + if (!Objects.isNull(impressionsResult.getImpressionsToQueue())) { + _log.info("Adding impression to queue"); + impressionsForLogs.addAll(impressionsResult.getImpressionsToQueue()); + } + if (!Objects.isNull(impressionsResult.getImpressionsToListener())) + impressionsToListener.addAll(impressionsResult.getImpressionsToListener()); + } int totalImpressions = impressionsForLogs.size(); long queued = _impressionsStorageProducer.put(impressionsForLogs.stream().map(KeyImpression::fromImpression).collect(Collectors.toList())); if (queued < totalImpressions) { 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 eb56009f9..5188b0dc3 100644 --- a/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java +++ b/client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java @@ -86,7 +86,12 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu try { if (parsedSplit.killed()) { String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null; - return new TreatmentLabelAndChangeNumber(parsedSplit.defaultTreatment(), Labels.KILLED, parsedSplit.changeNumber(), config); + return new TreatmentLabelAndChangeNumber( + parsedSplit.defaultTreatment(), + Labels.KILLED, + parsedSplit.changeNumber(), + config, + parsedSplit.trackImpression()); } /* @@ -112,7 +117,7 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null; return new TreatmentLabelAndChangeNumber(parsedSplit.defaultTreatment(), Labels.NOT_IN_SPLIT, - parsedSplit.changeNumber(), config); + parsedSplit.changeNumber(), config, parsedSplit.trackImpression()); } } @@ -122,12 +127,22 @@ private TreatmentLabelAndChangeNumber getTreatment(String matchingKey, String bu if (parsedCondition.matcher().match(matchingKey, bucketingKey, attributes, _evaluationContext)) { String treatment = Splitter.getTreatment(bk, parsedSplit.seed(), parsedCondition.partitions(), parsedSplit.algo()); String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(treatment) : null; - return new TreatmentLabelAndChangeNumber(treatment, parsedCondition.label(), parsedSplit.changeNumber(), config); + return new TreatmentLabelAndChangeNumber( + treatment, + parsedCondition.label(), + parsedSplit.changeNumber(), + config, + parsedSplit.trackImpression()); } } String config = parsedSplit.configurations() != null ? parsedSplit.configurations().get(parsedSplit.defaultTreatment()) : null; - return new TreatmentLabelAndChangeNumber(parsedSplit.defaultTreatment(), Labels.DEFAULT_RULE, parsedSplit.changeNumber(), config); + return new TreatmentLabelAndChangeNumber( + parsedSplit.defaultTreatment(), + Labels.DEFAULT_RULE, + parsedSplit.changeNumber(), + config, + parsedSplit.trackImpression()); } catch (Exception e) { throw new ChangeNumberExceptionWrapper(e, parsedSplit.changeNumber()); } @@ -155,20 +170,22 @@ public static final class TreatmentLabelAndChangeNumber { public final String label; public final Long changeNumber; public final String configurations; + public final boolean track; public TreatmentLabelAndChangeNumber(String treatment, String label) { - this(treatment, label, null, null); + this(treatment, label, null, null, true); } public TreatmentLabelAndChangeNumber(String treatment, String label, Long changeNumber) { - this(treatment, label, changeNumber, null); + this(treatment, label, changeNumber, null, true); } - public TreatmentLabelAndChangeNumber(String treatment, String label, Long changeNumber, String configurations) { + public TreatmentLabelAndChangeNumber(String treatment, String label, Long changeNumber, String configurations, boolean track) { this.treatment = treatment; this.label = label; this.changeNumber = changeNumber; this.configurations = configurations; + this.track = track; } } } \ No newline at end of file diff --git a/client/src/main/java/io/split/engine/experiments/ParsedSplit.java b/client/src/main/java/io/split/engine/experiments/ParsedSplit.java index 67855dfbd..da45b5923 100644 --- a/client/src/main/java/io/split/engine/experiments/ParsedSplit.java +++ b/client/src/main/java/io/split/engine/experiments/ParsedSplit.java @@ -32,6 +32,7 @@ public class ParsedSplit { private final int _algo; private final Map _configurations; private final HashSet _flagSets; + private final boolean _trackImpression; public static ParsedSplit createParsedSplitForTests( String feature, @@ -42,7 +43,8 @@ public static ParsedSplit createParsedSplitForTests( String trafficTypeName, long changeNumber, int algo, - HashSet flagSets + HashSet flagSets, + boolean trackImpression ) { return new ParsedSplit( feature, @@ -56,7 +58,8 @@ public static ParsedSplit createParsedSplitForTests( seed, algo, null, - flagSets + flagSets, + trackImpression ); } @@ -70,7 +73,8 @@ public static ParsedSplit createParsedSplitForTests( long changeNumber, int algo, Map configurations, - HashSet flagSets + HashSet flagSets, + boolean trackImpression ) { return new ParsedSplit( feature, @@ -84,7 +88,8 @@ public static ParsedSplit createParsedSplitForTests( seed, algo, configurations, - flagSets + flagSets, + trackImpression ); } @@ -100,7 +105,8 @@ public ParsedSplit( int trafficAllocationSeed, int algo, Map configurations, - HashSet flagSets + HashSet flagSets, + boolean trackImpression ) { _split = feature; _seed = seed; @@ -117,6 +123,7 @@ public ParsedSplit( _trafficAllocationSeed = trafficAllocationSeed; _configurations = configurations; _flagSets = flagSets; + _trackImpression = trackImpression; } public String feature() { @@ -160,6 +167,10 @@ public Map configurations() { return _configurations; } + public boolean trackImpression() { + return _trackImpression; + } + @Override public int hashCode() { int result = 17; @@ -172,6 +183,7 @@ public int hashCode() { result = 31 * result + (int)(_changeNumber ^ (_changeNumber >>> 32)); result = 31 * result + (_algo ^ (_algo >>> 32)); result = 31 * result + (_configurations == null? 0 : _configurations.hashCode()); + result = 31 * result + (_trackImpression ? 1 : 0); return result; } @@ -191,7 +203,8 @@ public boolean equals(Object obj) { && _trafficTypeName == null ? other._trafficTypeName == null : _trafficTypeName.equals(other._trafficTypeName) && _changeNumber == other._changeNumber && _algo == other._algo - && _configurations == null ? other._configurations == null : _configurations.equals(other._configurations); + && _configurations == null ? other._configurations == null : _configurations.equals(other._configurations) + && _trackImpression == other._trackImpression; } @Override @@ -215,6 +228,8 @@ public String toString() { bldr.append(_algo); bldr.append(", config:"); bldr.append(_configurations); + bldr.append(", trackImpression:"); + bldr.append(_trackImpression); return bldr.toString(); } diff --git a/client/src/main/java/io/split/engine/experiments/SplitParser.java b/client/src/main/java/io/split/engine/experiments/SplitParser.java index b320dff66..7b70a2e24 100644 --- a/client/src/main/java/io/split/engine/experiments/SplitParser.java +++ b/client/src/main/java/io/split/engine/experiments/SplitParser.java @@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory; import java.util.List; +import java.util.Objects; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -65,7 +66,10 @@ public ParsedSplit parse(Split split) { private ParsedSplit parseWithoutExceptionHandling(Split split) { List parsedConditionList = Lists.newArrayList(); - + if (Objects.isNull(split.trackImpression)) { + _log.debug("trackImpression field not detected for Feature flag `" + split.name + "`, setting it to `true`."); + split.trackImpression = true; + } for (Condition condition : split.conditions) { List partitions = condition.partitions; if (checkUnsupportedMatcherExist(condition.matcherGroup.matchers)) { @@ -78,8 +82,20 @@ private ParsedSplit parseWithoutExceptionHandling(Split split) { parsedConditionList.add(new ParsedCondition(condition.conditionType, matcher, partitions, condition.label)); } - return new ParsedSplit(split.name, split.seed, split.killed, split.defaultTreatment, parsedConditionList, split.trafficTypeName, - split.changeNumber, split.trafficAllocation, split.trafficAllocationSeed, split.algo, split.configurations, split.sets); + return new ParsedSplit( + split.name, + split.seed, + split.killed, + split.defaultTreatment, + parsedConditionList, + split.trafficTypeName, + split.changeNumber, + split.trafficAllocation, + split.trafficAllocationSeed, + split.algo, + split.configurations, + split.sets, + split.trackImpression); } private boolean checkUnsupportedMatcherExist(List matchers) { diff --git a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java index 62baaf44b..944fffee6 100644 --- a/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java +++ b/client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java @@ -130,7 +130,8 @@ public void kill(String splitName, String defaultTreatment, long changeNumber) { parsedSplit.trafficAllocationSeed(), parsedSplit.algo(), parsedSplit.configurations(), - parsedSplit.flagSets() + parsedSplit.flagSets(), + parsedSplit.trackImpression() ); _concurrentMap.put(splitName, updatedSplit); diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java index 4210b9782..a586ed5ee 100644 --- a/client/src/test/java/io/split/client/SplitClientImplTest.java +++ b/client/src/test/java/io/split/client/SplitClientImplTest.java @@ -4,10 +4,7 @@ import com.google.common.collect.Lists; import io.split.client.api.Key; import io.split.client.api.SplitResult; -import io.split.client.dtos.ConditionType; -import io.split.client.dtos.DataType; -import io.split.client.dtos.Event; -import io.split.client.dtos.Partition; +import io.split.client.dtos.*; import io.split.client.events.EventsStorageProducer; import io.split.client.events.NoopEventsStorageImp; import io.split.client.impressions.Impression; @@ -85,7 +82,7 @@ public void nullKeyResultsInControl() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -114,7 +111,7 @@ public void nullTestResultsInControl() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -166,7 +163,7 @@ public void works() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -204,7 +201,7 @@ public void worksNullConfig() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -239,7 +236,7 @@ public void worksAndHasConfig() { Map configurations = new HashMap<>(); configurations.put(Treatments.ON, "{\"size\" : 30}"); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, configurations, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, configurations, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -275,7 +272,7 @@ public void lastConditionIsAlwaysDefault() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("adil@codigo.com"))), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -314,7 +311,7 @@ public void lastConditionIsAlwaysDefaultButWithTreatment() { configurations.put(Treatments.OFF, "{\"size\" : 30}"); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - "user", 1, 1, configurations, new HashSet<>()); + "user", 1, 1, configurations, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -348,7 +345,7 @@ public void multipleConditionsWork() { ParsedCondition trevor_is_always_shown = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("trevor@codigo.com"))), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(adil_is_always_on, pato_is_never_shown, trevor_is_always_shown); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -382,7 +379,7 @@ public void killedTestAlwaysGoesToDefault() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(Lists.newArrayList("adil@codigo.com"))), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -421,7 +418,7 @@ public void killedTestAlwaysGoesToDefaultHasConfig() { configurations.put(Treatments.OFF, "{\"size\" : 30}"); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, true, Treatments.OFF, conditions, - "user", 1, 1, configurations, new HashSet<>()); + "user", 1, 1, configurations, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -453,11 +450,11 @@ public void dependencyMatcherOn() { ParsedCondition parent_is_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition(Treatments.ON, 100))); List parent_conditions = Lists.newArrayList(parent_is_on); - ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true); ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher(parent, Lists.newArrayList(Treatments.ON))), Lists.newArrayList(partition(Treatments.ON, 100))); List dependent_conditions = Lists.newArrayList(dependent_needs_parent); - ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>()); + ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -487,11 +484,11 @@ public void dependencyMatcherOff() { ParsedCondition parent_is_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition(Treatments.ON, 100))); List parent_conditions = Lists.newArrayList(parent_is_on); - ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parentSplit = ParsedSplit.createParsedSplitForTests(parent, 123, false, Treatments.OFF, parent_conditions, null, 1, 1, new HashSet<>(), true); ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher(parent, Lists.newArrayList(Treatments.OFF))), Lists.newArrayList(partition(Treatments.ON, 100))); List dependent_conditions = Lists.newArrayList(dependent_needs_parent); - ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>()); + ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.OFF, dependent_conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -520,7 +517,7 @@ public void dependencyMatcherControl() { ParsedCondition dependent_needs_parent = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new DependencyMatcher("not-exists", Lists.newArrayList(Treatments.OFF))), Lists.newArrayList(partition(Treatments.OFF, 100))); List dependent_conditions = Lists.newArrayList(dependent_needs_parent); - ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.ON, dependent_conditions, null, 1, 1, new HashSet<>()); + ParsedSplit dependentSplit = ParsedSplit.createParsedSplitForTests(dependent, 123, false, Treatments.ON, dependent_conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -549,7 +546,7 @@ public void attributesWork() { ParsedCondition users_with_age_greater_than_10_are_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new GreaterThanOrEqualToMatcher(10, DataType.NUMBER)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(adil_is_always_on, users_with_age_greater_than_10_are_on); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -583,7 +580,7 @@ public void attributesWork2() { ParsedCondition age_equal_to_0_should_be_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new EqualToMatcher(0, DataType.NUMBER)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(age_equal_to_0_should_be_on); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -618,7 +615,7 @@ public void attributesGreaterThanNegativeNumber() { ParsedCondition age_equal_to_0_should_be_on = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("age", new EqualToMatcher(-20, DataType.NUMBER)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(age_equal_to_0_should_be_on); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -655,7 +652,7 @@ public void attributesForSets() { ParsedCondition any_of_set = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of("products", new ContainsAnyOfSetMatcher(Lists.newArrayList("sms", "video"))), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(any_of_set); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -698,7 +695,7 @@ public void labelsArePopulated() { ); List conditions = Lists.newArrayList(age_equal_to_0_should_be_on); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class); @@ -724,10 +721,10 @@ public void labelsArePopulated() { verify(impressionsManager).track(impressionCaptor.capture()); - List impressions = impressionCaptor.getValue(); + List impressions = impressionCaptor.getValue(); assertNotNull(impressions); assertEquals(1, impressions.size()); - Impression impression = impressions.get(0); + Impression impression = impressions.get(0).impression; assertEquals("foolabel", impression.appliedRule()); @@ -800,7 +797,7 @@ private void trafficAllocation(String key, int trafficAllocation, int trafficAll List conditions = Lists.newArrayList(whitelistCondition, rollOutToEveryone); ParsedSplit parsedSplit = new ParsedSplit(test, 123, false, Treatments.OFF, conditions, null, 1, - trafficAllocation, trafficAllocationSeed, 1, null, new HashSet<>()); + trafficAllocation, trafficAllocationSeed, 1, null, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -826,8 +823,8 @@ private void trafficAllocation(String key, int trafficAllocation, int trafficAll verify(impressionsManager).track(impressionCaptor.capture()); assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); - Impression impression = (Impression) impressionCaptor.getValue().get(0); - assertEquals(label, impression.appliedRule()); + DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); + assertEquals(label, impression.impression.appliedRule()); } /** @@ -851,7 +848,7 @@ public void notInTrafficAllocationDefaultConfig() { List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = new ParsedSplit(test, 123, false, Treatments.OFF, conditions, null, - 1, trafficAllocation, trafficAllocationSeed, 1, configurations, new HashSet<>()); + 1, trafficAllocation, trafficAllocationSeed, 1, configurations, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -882,8 +879,8 @@ public void notInTrafficAllocationDefaultConfig() { assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); - Impression impression = (Impression) impressionCaptor.getValue().get(0); - assertEquals("not in split", impression.appliedRule()); + DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); + assertEquals("not in split", impression.impression.appliedRule()); } @@ -897,7 +894,7 @@ public void matchingBucketingKeysWork() { ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(aijaz_should_match); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -933,7 +930,7 @@ public void matchingBucketingKeysByFlagSetWork() { ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(aijaz_should_match); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1"))); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -973,7 +970,7 @@ public void matchingBucketingKeysByFlagSetsWork() { ParsedCondition aijaz_should_match = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new WhitelistMatcher(whitelist)), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(aijaz_should_match); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1"))); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, "user", 1, 1, new HashSet<>(Arrays.asList("set1")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1015,7 +1012,7 @@ public void impressionMetadataIsPropagated() { ); List conditions = Lists.newArrayList(age_equal_to_0_should_be_on); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1045,10 +1042,10 @@ public void impressionMetadataIsPropagated() { assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); - Impression impression = (Impression) impressionCaptor.getValue().get(0); + DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); - assertEquals("foolabel", impression.appliedRule()); - assertEquals(attributes, impression.attributes()); + assertEquals("foolabel", impression.impression.appliedRule()); + assertEquals(attributes, impression.impression.attributes()); } private Partition partition(String treatment, int size) { @@ -1200,7 +1197,7 @@ public void getTreatmentWithInvalidKeys() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1357,7 +1354,7 @@ public void clientCannotPerformActionsWhenDestroyed() throws InterruptedExceptio ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1413,7 +1410,7 @@ public void worksAndHasConfigTryKetTreatmentWithKey() { configurations.put(Treatments.ON, "{\"size\" : 30}"); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>()); + null, 1, 1, configurations, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1457,7 +1454,7 @@ public void worksAndHasConfigByFlagSetTryKetTreatmentWithKey() { configurations.put(Treatments.ON, "{\"size\" : 30}"); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1504,7 +1501,7 @@ public void worksAndHasConfigByFlagSetsTryKetTreatmentWithKey() { configurations.put(Treatments.ON, "{\"size\" : 30}"); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1546,7 +1543,7 @@ public void blockUntilReadyException() throws TimeoutException, InterruptedExcep Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1575,7 +1572,7 @@ public void nullKeyResultsInControlGetTreatments() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); Map splits = new HashMap<>(); splits.put(test, parsedSplit); SDKReadinessGates gates = mock(SDKReadinessGates.class); @@ -1605,7 +1602,7 @@ public void nullSplitsResultsInEmptyGetTreatments() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); Map splits = new HashMap<>(); splits.put(test, parsedSplit); SDKReadinessGates gates = mock(SDKReadinessGates.class); @@ -1659,7 +1656,7 @@ public void getTreatmentsWorks() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); Map splits = new HashMap<>(); splits.put(test, parsedSplit); SDKReadinessGates gates = mock(SDKReadinessGates.class); @@ -1690,7 +1687,7 @@ public void emptySplitsResultsInNullGetTreatments() { String test = "test1"; ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); Map splits = new HashMap<>(); splits.put(test, parsedSplit); SDKReadinessGates gates = mock(SDKReadinessGates.class); @@ -1746,9 +1743,9 @@ public void worksTreatments() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); ParsedSplit parsedSplit2 = ParsedSplit.createParsedSplitForTests(test2, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>()); + null, 1, 1, new HashSet<>(), true); Map parsedSplits = new HashMap<>(); parsedSplits.put(test, parsedSplit); parsedSplits.put(test2, parsedSplit2); @@ -1786,7 +1783,7 @@ public void worksOneControlTreatments() { ParsedCondition rollOutToEveryone = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); - ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>()); + ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(), true); Map parsedSplits = new HashMap<>(); parsedSplits.put(test, parsedSplit); @@ -1832,7 +1829,7 @@ public void treatmentsWorksAndHasConfig() { ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>()); + null, 1, 1, configurations, new HashSet<>(), true); Map parsedSplits = new HashMap<>(); parsedSplits.put(test, parsedSplit); SDKReadinessGates gates = mock(SDKReadinessGates.class); @@ -1868,7 +1865,7 @@ public void testTreatmentsByFlagSet() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1912,7 +1909,7 @@ public void testTreatmentsByFlagSetInvalid() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -1942,9 +1939,9 @@ public void testTreatmentsByFlagSets() { Lists.newArrayList(partition("on", 100))); List conditions = Lists.newArrayList(rollOutToEveryone); ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2"))); + null, 1, 1, new HashSet<>(Arrays.asList("set1", "set2")), true); ParsedSplit parsedSplit2 = ParsedSplit.createParsedSplitForTests(test2, 123, false, Treatments.OFF, conditions, - null, 1, 1, new HashSet<>(Arrays.asList("set3", "set4"))); + null, 1, 1, new HashSet<>(Arrays.asList("set3", "set4")), true); SDKReadinessGates gates = mock(SDKReadinessGates.class); SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); @@ -2000,7 +1997,7 @@ public void treatmentsWorksAndHasConfigFlagSet() { ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true); Map parsedSplits = new HashMap<>(); parsedSplits.put(test, parsedSplit); @@ -2050,7 +2047,7 @@ public void treatmentsWorksAndHasConfigFlagSets() { ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, - null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1"))); + null, 1, 1, configurations, new HashSet<>(Arrays.asList("set1")), true); Map parsedSplits = new HashMap<>(); parsedSplits.put(test, parsedSplit); diff --git a/client/src/test/java/io/split/client/SplitManagerImplTest.java b/client/src/test/java/io/split/client/SplitManagerImplTest.java index d4a5c6a87..c0e60a31c 100644 --- a/client/src/test/java/io/split/client/SplitManagerImplTest.java +++ b/client/src/test/java/io/split/client/SplitManagerImplTest.java @@ -55,7 +55,7 @@ public void splitCallWithExistentSplit() { String existent = "existent"; SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); - ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>()); + ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), true); when(splitCacheConsumer.get(existent)).thenReturn(response); SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer, @@ -81,7 +81,7 @@ public void splitCallWithExistentSplitAndConfigs() { Map configurations = new HashMap<>(); configurations.put(Treatments.OFF, "{\"size\" : 30}"); - ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, configurations, new HashSet<>()); + ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, configurations, new HashSet<>(), true); when(splitCacheConsumer.get(existent)).thenReturn(response); SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer, @@ -117,7 +117,7 @@ public void splitsCallWithSplit() { List parsedSplits = Lists.newArrayList(); SDKReadinessGates gates = mock(SDKReadinessGates.class); when(gates.isSDKReady()).thenReturn(false); - ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>()); + ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(), true); parsedSplits.add(response); when(splitCacheConsumer.getAll()).thenReturn(parsedSplits); @@ -192,7 +192,7 @@ public void splitCallWithExistentSets() { String existent = "existent"; SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", - Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(Arrays.asList("set1", "set2", "set3"))); + Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, new HashSet<>(Arrays.asList("set1", "set2", "set3")), true); when(splitCacheConsumer.get(existent)).thenReturn(response); SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer, @@ -207,7 +207,7 @@ public void splitCallWithEmptySets() { String existent = "existent"; SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); ParsedSplit response = ParsedSplit.createParsedSplitForTests("FeatureName", 123, true, "off", - Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, null); + Lists.newArrayList(getTestCondition("off")), "traffic", 456L, 1, null, true); when(splitCacheConsumer.get(existent)).thenReturn(response); SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer, diff --git a/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java b/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java index f066f1d81..6d0f42f41 100644 --- a/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java +++ b/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java @@ -1,6 +1,7 @@ package io.split.client.impressions; import io.split.client.SplitClientConfig; +import io.split.client.dtos.DecoratedImpression; import io.split.client.dtos.KeyImpression; import io.split.client.dtos.TestImpressions; @@ -79,8 +80,9 @@ public void works() throws URISyntaxException { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, null); @@ -88,10 +90,10 @@ public void works() throws URISyntaxException { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 2L); KeyImpression ki4 = keyImpression("test2", "pato", "on", 4L, 3L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null), true)).collect(Collectors.toList())); // Do what the scheduler would do. treatmentLog.sendImpressions(); @@ -118,10 +120,11 @@ public void testImpressionListenerOptimize() { TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized(true, impressionObserver, impressionCounter, telemetryStorageProducer); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); ImpressionListener impressionListener = Mockito.mock(AsynchronousImpressionListener.class); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, impressionListener); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, impressionListener); treatmentLog.start(); KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); @@ -129,11 +132,11 @@ public void testImpressionListenerOptimize() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 2L); KeyImpression ki4 = keyImpression("test2", "pato", "on", 4L, 3L); - List impressionList = new ArrayList<>(); - impressionList.add(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null)); - impressionList.add(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null)); - impressionList.add(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null)); - impressionList.add(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null)); + List impressionList = new ArrayList<>(); + impressionList.add(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null), true)); treatmentLog.track(impressionList); verify(impressionListener, times(4)).log(Mockito.anyObject()); @@ -159,10 +162,11 @@ public void testImpressionListenerDebug() { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(true, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); ImpressionListener impressionListener = Mockito.mock(AsynchronousImpressionListener.class); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, impressionListener); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, impressionListener); treatmentLog.start(); KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); @@ -170,11 +174,11 @@ public void testImpressionListenerDebug() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 2L); KeyImpression ki4 = keyImpression("test2", "pato", "on", 4L, 3L); - List impressionList = new ArrayList<>(); - impressionList.add(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null)); - impressionList.add(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null)); - impressionList.add(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null)); - impressionList.add(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null)); + List impressionList = new ArrayList<>(); + impressionList.add(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null), true)); treatmentLog.track(impressionList); verify(impressionListener, times(4)).log(Mockito.anyObject()); @@ -202,10 +206,11 @@ public void testImpressionListenerNone() { uniqueKeysTracker.start(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionNone(true, uniqueKeysTracker, impressionCounter); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); ImpressionListener impressionListener = Mockito.mock(AsynchronousImpressionListener.class); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, impressionListener); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, impressionListener); treatmentLog.start(); KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); @@ -213,11 +218,11 @@ public void testImpressionListenerNone() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 2L); KeyImpression ki4 = keyImpression("test2", "pato", "on", 4L, 3L); - List impressionList = new ArrayList<>(); - impressionList.add(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null)); - impressionList.add(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null)); - impressionList.add(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null)); - impressionList.add(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null)); + List impressionList = new ArrayList<>(); + impressionList.add(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, ki1.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, ki2.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, ki3.changeNumber, null), true)); + impressionList.add(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, ki4.changeNumber, null), true)); treatmentLog.track(impressionList); verify(impressionListener, times(4)).log(Mockito.anyObject()); @@ -244,8 +249,9 @@ public void worksButDropsImpressions() { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -254,10 +260,10 @@ public void worksButDropsImpressions() { KeyImpression ki3 = keyImpression("test3", "pato", "on", 3L, null); KeyImpression ki4 = keyImpression("test4", "pato", "on", 4L, null); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, null, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, null, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, null, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, null, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, null, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, null, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, null, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, null, null), true)).collect(Collectors.toList())); // Do what the scheduler would do. treatmentLog.sendImpressions(); @@ -285,8 +291,9 @@ public void works4ImpressionsInOneTest() { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -295,10 +302,10 @@ public void works4ImpressionsInOneTest() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); // Do what the scheduler would do. treatmentLog.sendImpressions(); @@ -328,8 +335,9 @@ public void worksNoImpressions() { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); // There are no impressions to post. @@ -353,7 +361,8 @@ public void alreadySeenImpressionsAreMarked() { ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -362,10 +371,10 @@ public void alreadySeenImpressionsAreMarked() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato2", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -379,10 +388,10 @@ public void alreadySeenImpressionsAreMarked() { // Do it again. Now they should all have a `seenAt` value Mockito.reset(senderMock); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -410,8 +419,9 @@ public void testImpressionsStandaloneModeOptimizedMode() { TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized(false, impressionObserver, impressionCounter, telemetryStorageProducer); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -420,10 +430,10 @@ public void testImpressionsStandaloneModeOptimizedMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -464,8 +474,9 @@ public void testImpressionsStandaloneModeDebugMode() { ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -474,10 +485,10 @@ public void testImpressionsStandaloneModeDebugMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -515,8 +526,9 @@ public void testImpressionsStandaloneModeNoneMode() { uniqueKeysTracker.start(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionNone(false, uniqueKeysTracker, impressionCounter); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -525,10 +537,10 @@ public void testImpressionsStandaloneModeNoneMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.close(); uniqueKeysTracker.stop(); @@ -572,7 +584,8 @@ public void testImpressionsConsumerModeOptimizedMode() { TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized(false, impressionObserver, impressionCounter, telemetryStorageProducer); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -581,10 +594,10 @@ public void testImpressionsConsumerModeOptimizedMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -629,8 +642,9 @@ public void testImpressionsConsumerModeNoneMode() { UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp(telemetrySynchronizer, 1000, 1000, null); uniqueKeysTracker.start(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionNone(false, uniqueKeysTracker, impressionCounter); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -639,10 +653,10 @@ public void testImpressionsConsumerModeNoneMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); uniqueKeysTracker.stop(); treatmentLog.close(); @@ -684,8 +698,9 @@ public void testImpressionsConsumerModeDebugMode() { ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); treatmentLog.start(); // These 4 unique test name will cause 4 entries but we are caping at the first 3. @@ -694,10 +709,10 @@ public void testImpressionsConsumerModeDebugMode() { KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); KeyImpression ki4 = keyImpression("test1", "pato", "on", 4L, 1L); - treatmentLog.track(Stream.of(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null)).collect(Collectors.toList())); - treatmentLog.track(Stream.of(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), true)).collect(Collectors.toList())); treatmentLog.sendImpressions(); verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); @@ -734,7 +749,8 @@ public void testCounterStandaloneModeOptimizedMode() { TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage(); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized(false, impressionObserver, impressionCounter, telemetryStorageProducer); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); manager.start(); Assert.assertNotNull(manager.getCounter()); } @@ -750,8 +766,9 @@ public void testCounterStandaloneModeDebugMode() { ImpressionsSender senderMock = Mockito.mock(ImpressionsSender.class); ImpressionObserver impressionObserver = new ImpressionObserver(200); ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, null, null); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, null, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, null, null); manager.start(); Assert.assertNull(manager.getCounter()); } @@ -769,7 +786,7 @@ public void testCounterStandaloneModeNoneMode() { ProcessImpressionStrategy processImpressionStrategy = Mockito.mock(ProcessImpressionNone.class); ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, Mockito.mock(ProcessImpressionNone.class), processImpressionStrategy, impressionCounter, null); manager.start(); Assert.assertNotNull(manager.getCounter()); } @@ -789,7 +806,7 @@ public void testCounterConsumerModeOptimizedMode() { ProcessImpressionStrategy processImpressionStrategy = Mockito.mock(ProcessImpressionOptimized.class); ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, Mockito.mock(ProcessImpressionNone.class), processImpressionStrategy, impressionCounter, null); manager.start(); Assert.assertNotNull(manager.getCounter()); } @@ -808,7 +825,7 @@ public void testCounterConsumerModeDebugMode() { ImpressionsSender senderMock = Mockito.mock(ImpressionsSender.class); ProcessImpressionStrategy processImpressionStrategy = Mockito.mock(ProcessImpressionDebug.class); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, null, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, Mockito.mock(ProcessImpressionNone.class), processImpressionStrategy, null, null); manager.start(); Assert.assertNull(manager.getCounter()); } @@ -829,7 +846,7 @@ public void testCounterConsumerModeNoneMode() { ProcessImpressionStrategy processImpressionStrategy = Mockito.mock(ProcessImpressionNone.class); ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); - ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionStrategy, impressionCounter, null); + ImpressionsManagerImpl manager = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, Mockito.mock(ProcessImpressionNone.class), processImpressionStrategy, impressionCounter, null); manager.start(); Assert.assertNotNull(manager.getCounter()); } 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 2d583e942..a58a22194 100644 --- a/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java +++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorIntegrationTest.java @@ -175,10 +175,10 @@ private Evaluator buildEvaluatorAndLoadCache(boolean killed, int trafficAllocati List conditions = Lists.newArrayList(whitelistCondition, rollOutCondition); - ParsedSplit parsedSplit1 = new ParsedSplit("split_1", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366551, 100, 0, 2, null, new HashSet<>()); - ParsedSplit parsedSplit2 = new ParsedSplit("split_2", 0, true, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366552, 100, 0, 2, null, new HashSet<>()); - ParsedSplit parsedSplit3 = new ParsedSplit("split_3", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>()); - ParsedSplit parsedSplit4 = new ParsedSplit("split_test", 0, killed, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366555, trafficAllocation, 0, 2, null, new HashSet<>()); + ParsedSplit parsedSplit1 = new ParsedSplit("split_1", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366551, 100, 0, 2, null, new HashSet<>(), true); + ParsedSplit parsedSplit2 = new ParsedSplit("split_2", 0, true, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366552, 100, 0, 2, null, new HashSet<>(), true); + ParsedSplit parsedSplit3 = new ParsedSplit("split_3", 0, false, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366554, 100, 0, 2, null, new HashSet<>(), true); + ParsedSplit parsedSplit4 = new ParsedSplit("split_test", 0, killed, DEFAULT_TREATMENT_VALUE, conditions, TRAFFIC_TYPE_VALUE, 223366555, trafficAllocation, 0, 2, null, new HashSet<>(), true); splitCache.putMany(Stream.of(parsedSplit1, parsedSplit2, parsedSplit3, parsedSplit4).collect(Collectors.toList())); return evaluator; 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 e6598071b..5be942bf1 100644 --- a/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java +++ b/client/src/test/java/io/split/engine/evaluator/EvaluatorTest.java @@ -65,7 +65,7 @@ public void evaluateWhenSplitNameDoesNotExistReturnControl() { @Test public void evaluateWhenSplitIsKilledReturnDefaultTreatment() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, true, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>()); + ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, true, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true); Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split); EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null); @@ -77,7 +77,7 @@ public void evaluateWhenSplitIsKilledReturnDefaultTreatment() { @Test public void evaluateWithoutConditionsReturnDefaultTreatment() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>()); + ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(), true); Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split); EvaluatorImp.TreatmentLabelAndChangeNumber result = _evaluator.evaluateFeature(MATCHING_KEY, BUCKETING_KEY, SPLIT_NAME, null); @@ -96,7 +96,7 @@ public void evaluateWithRollOutConditionBucketIsBiggerTrafficAllocationReturnDef ParsedCondition condition = new ParsedCondition(ConditionType.ROLLOUT, _matcher,_partitions, TEST_LABEL_VALUE); _conditions.add(condition); - ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 10, 12, 2, _configurations, new HashSet<>()); + ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 10, 12, 2, _configurations, new HashSet<>(), true); Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split); Mockito.when(condition.matcher().match(MATCHING_KEY, BUCKETING_KEY, null, _evaluationContext)).thenReturn(true); @@ -117,7 +117,7 @@ public void evaluateWithRollOutConditionTrafficAllocationIsBiggerBucketReturnTre ParsedCondition condition = new ParsedCondition(ConditionType.ROLLOUT, _matcher, _partitions, TEST_LABEL_VALUE); _conditions.add(condition); - ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>()); + ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true); Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split); Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(true); @@ -138,7 +138,7 @@ public void evaluateWithWhitelistConditionReturnTreatment() { ParsedCondition condition = new ParsedCondition(ConditionType.WHITELIST, _matcher, _partitions, "test whitelist label"); _conditions.add(condition); - ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>()); + ParsedSplit split = new ParsedSplit(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 60, 18, 2, _configurations, new HashSet<>(), true); Mockito.when(_splitCacheConsumer.get(SPLIT_NAME)).thenReturn(split); Mockito.when(condition.matcher().match(Mockito.anyString(), Mockito.anyString(), Mockito.anyObject(), Mockito.anyObject())).thenReturn(true); @@ -152,7 +152,7 @@ public void evaluateWithWhitelistConditionReturnTreatment() { @Test public void evaluateWithSets() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2"))); + ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true); List sets = new ArrayList<>(Arrays.asList("set1", "empty_set")); Map> flagSets = new HashMap<>(); flagSets.put("set1", new HashSet<>(Arrays.asList(SPLIT_NAME))); @@ -173,7 +173,7 @@ public void evaluateWithSets() { @Test public void evaluateWithSetsNotHaveFlags() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2"))); + ParsedSplit split = ParsedSplit.createParsedSplitForTests(SPLIT_NAME, 0, false, DEFAULT_TREATMENT_VALUE, _conditions, TRAFFIC_TYPE_VALUE, CHANGE_NUMBER, 2, new HashSet<>(Arrays.asList("set1", "set2")), true); List sets = new ArrayList<>(Arrays.asList("set2")); Map> flagSets = new HashMap<>(); Mockito.when(_splitCacheConsumer.getNamesByFlagSets(sets)).thenReturn(flagSets); diff --git a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java index 858f7044f..00078bb9b 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitFetcherTest.java @@ -86,7 +86,7 @@ private void works(long startingChangeNumber) throws InterruptedException { ParsedCondition expectedParsedCondition = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(ConditionsTestUtil.partition("on", 10))); List expectedListOfMatcherAndSplits = Lists.newArrayList(expectedParsedCondition); - ParsedSplit expected = ParsedSplit.createParsedSplitForTests("" + cache.getChangeNumber(), (int) cache.getChangeNumber(), false, Treatments.OFF, expectedListOfMatcherAndSplits, null, cache.getChangeNumber(), 1, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("" + cache.getChangeNumber(), (int) cache.getChangeNumber(), false, Treatments.OFF, expectedListOfMatcherAndSplits, null, cache.getChangeNumber(), 1, new HashSet<>(), true); ParsedSplit actual = cache.get("" + cache.getChangeNumber()); Thread.sleep(1000); diff --git a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java index e9c0e63a5..6c5c699a1 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java @@ -93,7 +93,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -134,7 +134,7 @@ public void worksWithConfig() { List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition); ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, - listOfMatcherAndSplits, "user", 1, 1, configurations, new HashSet<>()); + listOfMatcherAndSplits, "user", 1, 1, configurations, new HashSet<>(), true); Assert.assertEquals(actual, expected); Assert.assertEquals(actual.configurations().get("on"), configurations.get("on")); @@ -173,7 +173,7 @@ public void worksForTwoConditions() { ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), turnOff); List listOfParsedConditions = Lists.newArrayList(parsedCondition1, parsedCondition2); - ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfParsedConditions, "user", 1, 1, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfParsedConditions, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -242,7 +242,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -275,7 +275,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -307,7 +307,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -338,7 +338,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -374,7 +374,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, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("first.name", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } @@ -664,7 +664,7 @@ public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) { ParsedCondition parsedCondition = ParsedCondition.createParsedConditionForTests(combiningMatcher, partitions); List listOfMatcherAndSplits = Lists.newArrayList(parsedCondition); - ParsedSplit expected = ParsedSplit.createParsedSplitForTests("splitName", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>()); + ParsedSplit expected = ParsedSplit.createParsedSplitForTests("splitName", 123, false, Treatments.OFF, listOfMatcherAndSplits, "user", 1, 1, new HashSet<>(), true); Assert.assertEquals(actual, expected); } diff --git a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java index 374f734c9..d2079f1bb 100644 --- a/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java +++ b/client/src/test/java/io/split/storages/memory/InMemoryCacheTest.java @@ -139,10 +139,10 @@ public void getMany() { @Test public void trafficTypesExist() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null); - ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null); - ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, null); - ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, null); + ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true); + ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true); + ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, null, true); + ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, null, true); _cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList())); assertTrue(_cache.trafficTypeExists("tt_2")); @@ -163,10 +163,10 @@ public void testSegmentNames() { ParsedCondition parsedCondition1 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES)), fullyRollout); ParsedCondition parsedCondition2 = ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new UserDefinedSegmentMatcher(EMPLOYEES+"2")), turnOff); - ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt", 123, 2, null); - ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt", 123, 2, null); - ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt_2", 123, 2, null); - ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt_3", 123, 2, null); + ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt", 123, 2, null, true); + ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt", 123, 2, null, true); + ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", Stream.of(parsedCondition1).collect(Collectors.toList()), "tt_2", 123, 2, null, true); + ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", Stream.of(parsedCondition2).collect(Collectors.toList()), "tt_3", 123, 2, null, true); _cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList())); @@ -178,19 +178,19 @@ public void testSegmentNames() { } private ParsedSplit getParsedSplitWithFlagSetsSameStorage(String splitName) { - return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2"))); + return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2")), true); } private ParsedSplit getParsedSplitWithFlagSetsNotSameStorage(String splitName) { - return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set3"))); + return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set3")), true); } private ParsedSplit getParsedSplitFlagSetsNull(String splitName) { - return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null); + return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, null, true); } private ParsedSplit getParsedSplitFlagSetsEmpty(String splitName) { - return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>()); + return ParsedSplit.createParsedSplitForTests(splitName, 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true); } @Test @@ -204,7 +204,7 @@ public void testPutMany() { @Test public void testIncreaseTrafficType() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>()); + ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true); _cache.putMany(Stream.of(split).collect(Collectors.toList())); _cache.increaseTrafficType("tt_2"); assertTrue(_cache.trafficTypeExists("tt_2")); @@ -212,7 +212,7 @@ public void testIncreaseTrafficType() { @Test public void testDecreaseTrafficType() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>()); + ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(), true); _cache.putMany(Stream.of(split).collect(Collectors.toList())); _cache.decreaseTrafficType("tt"); assertFalse(_cache.trafficTypeExists("tt_2")); @@ -220,10 +220,10 @@ public void testDecreaseTrafficType() { @Test public void testGetNamesByFlagSets() { - ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2", "set3"))); - ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1"))); - ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, new HashSet<>(Arrays.asList("set4"))); - ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, new HashSet<>(Arrays.asList("set2"))); + ParsedSplit split = ParsedSplit.createParsedSplitForTests("splitName_1", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1", "set2", "set3")), true); + ParsedSplit split2 = ParsedSplit.createParsedSplitForTests("splitName_2", 0, false, "default_treatment", new ArrayList<>(), "tt", 123, 2, new HashSet<>(Arrays.asList("set1")), true); + ParsedSplit split3 = ParsedSplit.createParsedSplitForTests("splitName_3", 0, false, "default_treatment", new ArrayList<>(), "tt_2", 123, 2, new HashSet<>(Arrays.asList("set4")), true); + ParsedSplit split4 = ParsedSplit.createParsedSplitForTests("splitName_4", 0, false, "default_treatment", new ArrayList<>(), "tt_3", 123, 2, new HashSet<>(Arrays.asList("set2")), true); _cache.putMany(Stream.of(split, split2, split3, split4).collect(Collectors.toList())); Map> namesByFlagSets = _cache.getNamesByFlagSets(new ArrayList<>(Arrays.asList("set1", "set2", "set3"))); From 4d8dec822625a7bea08352ebe1c96589752dc53b Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Thu, 12 Dec 2024 10:16:57 -0800 Subject: [PATCH 2/9] polish --- .../java/io/split/client/SplitFactoryImpl.java | 15 ++++++--------- .../impressions/ImpressionsManagerImpl.java | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 41a78463b..2791d4578 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -691,15 +691,12 @@ private void manageSdkReady(SplitClientConfig config) { } private UniqueKeysTracker createUniqueKeysTracker(SplitClientConfig config) { -// if (config.impressionsMode().equals(ImpressionsManager.Mode.NONE)) { - int uniqueKeysRefreshRate = config.operationMode().equals(OperationMode.STANDALONE) - ? config.uniqueKeysRefreshRateInMemory() - : config.uniqueKeysRefreshRateRedis(); - return new UniqueKeysTrackerImp(_telemetrySynchronizer, uniqueKeysRefreshRate, - config.filterUniqueKeysRefreshRate(), - config.getThreadFactory()); -// } -// return null; + int uniqueKeysRefreshRate = config.operationMode().equals(OperationMode.STANDALONE) + ? config.uniqueKeysRefreshRateInMemory() + : config.uniqueKeysRefreshRateRedis(); + return new UniqueKeysTrackerImp(_telemetrySynchronizer, uniqueKeysRefreshRate, + config.filterUniqueKeysRefreshRate(), + config.getThreadFactory()); } private SplitChangeFetcher createSplitChangeFetcher(SplitClientConfig splitClientConfig) { diff --git a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java index e79efb6be..95ed56943 100644 --- a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java +++ b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java @@ -138,7 +138,6 @@ public void track(List decoratedImpressions) { decoratedImpressions.get(i).impression).collect(Collectors.toList())); } if (!Objects.isNull(impressionsResult.getImpressionsToQueue())) { - _log.info("Adding impression to queue"); impressionsForLogs.addAll(impressionsResult.getImpressionsToQueue()); } if (!Objects.isNull(impressionsResult.getImpressionsToListener())) From 117eb918dc506131aae188b68efddd195a68142d Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Thu, 12 Dec 2024 14:19:05 -0800 Subject: [PATCH 3/9] added tests --- .../ImpressionsManagerImplTest.java | 183 +++++++++++++++++- .../engine/experiments/SplitParserTest.java | 21 ++ .../src/test/resources/splits_imp_toggle.json | 155 +++++++++++++++ 3 files changed, 354 insertions(+), 5 deletions(-) create mode 100644 client/src/test/resources/splits_imp_toggle.json diff --git a/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java b/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java index 6d0f42f41..27cbf0401 100644 --- a/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java +++ b/client/src/test/java/io/split/client/impressions/ImpressionsManagerImplTest.java @@ -28,11 +28,7 @@ import pluggable.CustomStorageWrapper; import java.net.URISyntaxException; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -850,4 +846,181 @@ public void testCounterConsumerModeNoneMode() { manager.start(); Assert.assertNotNull(manager.getCounter()); } + + @Test + public void testImpressionToggleStandaloneOptimizedMode() { + SplitClientConfig config = SplitClientConfig.builder() + .impressionsQueueSize(10) + .endpoint("nowhere.com", "nowhere.com") + .impressionsMode(ImpressionsManager.Mode.OPTIMIZED) + .build(); + ImpressionsStorage storage = new InMemoryImpressionsStorage(config.impressionsQueueSize()); + + ImpressionsSender senderMock = Mockito.mock(ImpressionsSender.class); + ImpressionCounter impressionCounter = new ImpressionCounter(); + ImpressionObserver impressionObserver = new ImpressionObserver(200); + TelemetryStorageProducer telemetryStorageProducer = new InMemoryTelemetryStorage(); + TelemetrySynchronizer telemetrySynchronizer = Mockito.mock(TelemetryInMemorySubmitter.class); + UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp(telemetrySynchronizer, 1000, 1000, null); + uniqueKeysTracker.start(); + + ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionOptimized(false, impressionObserver, impressionCounter, telemetryStorageProducer); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, uniqueKeysTracker, impressionCounter); + + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); + treatmentLog.start(); + + // These 4 unique test name will cause 4 entries but we are caping at the first 3. + KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); + KeyImpression ki2 = keyImpression("test1", "mati", "on", 2L, 1L); + KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); + KeyImpression ki4 = keyImpression("test1", "bilal", "on", 4L, 1L); + + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.sendImpressions(); + + verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); + + List captured = impressionsCaptor.getValue(); + Assert.assertEquals(2, captured.get(0).keyImpressions.size()); + for (TestImpressions testImpressions : captured) { + for (KeyImpression keyImpression : testImpressions.keyImpressions) { + Assert.assertEquals(null, keyImpression.previousTime); + } + } + // Only the first 2 impressions make it to the server + Assert.assertTrue(captured.get(0).keyImpressions.contains(keyImpression("test1", "adil", "on", 1L, 1L))); + Assert.assertTrue(captured.get(0).keyImpressions.contains(keyImpression("test1", "pato", "on", 3L, 1L))); + + HashMap> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll(); + HashSet keys = new HashSet<>(); + keys.add("mati"); + keys.add("bilal"); + Assert.assertEquals(1, trackedKeys.size()); + Assert.assertEquals(keys, trackedKeys.get("test1")); + + treatmentLog.sendImpressionCounters(); + verify(senderMock).postCounters(impressionCountCaptor.capture()); + HashMap capturedCounts = impressionCountCaptor.getValue(); + Assert.assertEquals(1, capturedCounts.size()); + Assert.assertTrue(capturedCounts.entrySet().contains(new AbstractMap.SimpleEntry<>(new ImpressionCounter.Key("test1", 0), 2))); + + // Assert that the sender is never called if the counters are empty. + Mockito.reset(senderMock); + treatmentLog.sendImpressionCounters(); + verify(senderMock, times(0)).postCounters(Mockito.any()); + } + + @Test + public void testImpressionToggleStandaloneModeDebugMode() { + SplitClientConfig config = SplitClientConfig.builder() + .impressionsQueueSize(10) + .endpoint("nowhere.com", "nowhere.com") + .impressionsMode(ImpressionsManager.Mode.DEBUG) + .build(); + ImpressionsStorage storage = new InMemoryImpressionsStorage(config.impressionsQueueSize()); + + ImpressionsSender senderMock = Mockito.mock(ImpressionsSender.class); + ImpressionCounter impressionCounter = Mockito.mock(ImpressionCounter.class); + ImpressionObserver impressionObserver = new ImpressionObserver(200); + ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionDebug(false, impressionObserver); + TelemetrySynchronizer telemetrySynchronizer = Mockito.mock(TelemetryInMemorySubmitter.class); + UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp(telemetrySynchronizer, 1000, 1000, null); + uniqueKeysTracker.start(); + ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(false, uniqueKeysTracker, impressionCounter); + + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); + treatmentLog.start(); + + // These 4 unique test name will cause 4 entries but we are caping at the first 3. + KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); + KeyImpression ki2 = keyImpression("test1", "mati", "on", 2L, 1L); + KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); + KeyImpression ki4 = keyImpression("test1", "bilal", "on", 4L, 1L); + + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.sendImpressions(); + + HashMap> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll(); + HashSet keys = new HashSet<>(); + keys.add("mati"); + keys.add("bilal"); + Assert.assertEquals(1, trackedKeys.size()); + Assert.assertEquals(keys, trackedKeys.get("test1")); + + verify(senderMock).postImpressionsBulk(impressionsCaptor.capture()); + + List captured = impressionsCaptor.getValue(); + Assert.assertEquals(2, captured.get(0).keyImpressions.size()); + for (TestImpressions testImpressions : captured) { + KeyImpression keyImpression1 = testImpressions.keyImpressions.get(0); + KeyImpression keyImpression3 = testImpressions.keyImpressions.get(1); + Assert.assertEquals(null, keyImpression1.previousTime); + Assert.assertEquals(null, keyImpression3.previousTime); + } + // Only the first 2 impressions make it to the server + Assert.assertTrue(captured.get(0).keyImpressions.contains(keyImpression("test1", "adil", "on", 1L, 1L))); + Assert.assertTrue(captured.get(0).keyImpressions.contains(keyImpression("test1", "pato", "on", 3L, 1L))); + } + + @Test + public void testImpressionToggleStandaloneModeNoneMode() { + SplitClientConfig config = SplitClientConfig.builder() + .impressionsQueueSize(10) + .endpoint("nowhere.com", "nowhere.com") + .impressionsMode(ImpressionsManager.Mode.NONE) + .build(); + ImpressionsStorage storage = new InMemoryImpressionsStorage(config.impressionsQueueSize()); + + ImpressionsSender senderMock = Mockito.mock(ImpressionsSender.class); + TelemetrySynchronizer telemetrySynchronizer = Mockito.mock(TelemetryInMemorySubmitter.class); + ImpressionCounter impressionCounter = new ImpressionCounter(); + UniqueKeysTracker uniqueKeysTracker = new UniqueKeysTrackerImp(telemetrySynchronizer, 1000, 1000, null); + uniqueKeysTracker.start(); + + ProcessImpressionStrategy processImpressionStrategy = new ProcessImpressionNone(false, uniqueKeysTracker, impressionCounter); + ProcessImpressionNone processImpressionNone = (ProcessImpressionNone) processImpressionStrategy; + + ImpressionsManagerImpl treatmentLog = ImpressionsManagerImpl.instanceForTest(config, senderMock, TELEMETRY_STORAGE, storage, storage, processImpressionNone, processImpressionStrategy, impressionCounter, null); + treatmentLog.start(); + + // These 4 unique test name will cause 4 entries but we are caping at the first 3. + KeyImpression ki1 = keyImpression("test1", "adil", "on", 1L, 1L); + KeyImpression ki2 = keyImpression("test1", "mati", "on", 2L, 1L); + KeyImpression ki3 = keyImpression("test1", "pato", "on", 3L, 1L); + KeyImpression ki4 = keyImpression("test1", "bilal", "on", 4L, 1L); + + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki1.keyName, null, ki1.feature, ki1.treatment, ki1.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki2.keyName, null, ki2.feature, ki2.treatment, ki2.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki3.keyName, null, ki3.feature, ki3.treatment, ki3.time, null, 1L, null), true)).collect(Collectors.toList())); + treatmentLog.track(Stream.of(new DecoratedImpression(new Impression(ki4.keyName, null, ki4.feature, ki4.treatment, ki4.time, null, 1L, null), false)).collect(Collectors.toList())); + treatmentLog.close(); + HashMap> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll(); + uniqueKeysTracker.stop(); + + HashSet keys = new HashSet<>(); + keys.add("adil"); + keys.add("mati"); + keys.add("pato"); + keys.add("bilal"); + Assert.assertEquals(1, trackedKeys.size()); + Assert.assertEquals(keys, trackedKeys.get("test1")); + + //treatmentLog.sendImpressionCounters(); + verify(senderMock).postCounters(impressionCountCaptor.capture()); + HashMap capturedCounts = impressionCountCaptor.getValue(); + Assert.assertEquals(1, capturedCounts.size()); + Assert.assertTrue(capturedCounts.entrySet().contains(new AbstractMap.SimpleEntry<>(new ImpressionCounter.Key("test1", 0), 4))); + + // Assert that the sender is never called if the counters are empty. + Mockito.reset(senderMock); + treatmentLog.sendImpressionCounters(); + verify(senderMock, times(0)).postCounters(Mockito.any()); + } } \ No newline at end of file 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 6c5c699a1..2958106da 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java @@ -48,6 +48,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** @@ -639,6 +640,26 @@ public void InListSemverMatcher() throws IOException { assertTrue(false); } + @Test + public void ImpressionToggleParseTest() throws IOException { + SplitParser parser = new SplitParser(); + String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.json")), StandardCharsets.UTF_8); + SplitChange change = Json.fromJson(splits, SplitChange.class); + for (Split split : change.splits) { + // should not cause exception + ParsedSplit parsedSplit = parser.parse(split); + if (split.name.equals("without_impression_toggle")) { + assertTrue(split.trackImpression); + } + if (split.name.equals("impression_toggle_on")) { + assertTrue(split.trackImpression); + } + if (split.name.equals("impression_toggle_off")) { + assertFalse(split.trackImpression); + } + } + } + public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) { SegmentChangeFetcher segmentChangeFetcher = Mockito.mock(SegmentChangeFetcher.class); diff --git a/client/src/test/resources/splits_imp_toggle.json b/client/src/test/resources/splits_imp_toggle.json new file mode 100644 index 000000000..4bd499ac2 --- /dev/null +++ b/client/src/test/resources/splits_imp_toggle.json @@ -0,0 +1,155 @@ +{ + "splits": [ + { + "trafficTypeName": "user", + "name": "without_impression_toggle", + "trafficAllocation": 24, + "trafficAllocationSeed": -172559061, + "seed": -906334215, + "status": "ACTIVE", + "killed": true, + "defaultTreatment": "off", + "changeNumber": 1585948717645, + "algo": 2, + "configurations": {}, + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "user", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + } + ], + "label": "default rule" + } + ] + }, + { + "trafficTypeName": "user", + "name": "impression_toggle_on", + "trafficAllocation": 24, + "trafficAllocationSeed": -172559061, + "seed": -906334215, + "status": "ACTIVE", + "killed": true, + "defaultTreatment": "off", + "changeNumber": 1585948717645, + "algo": 2, + "configurations": {}, + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "user", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + } + ], + "label": "default rule" + } + ], + "trackImpression": true + }, + { + "trafficTypeName": "user", + "name": "impression_toggle_off", + "trafficAllocation": 24, + "trafficAllocationSeed": -172559061, + "seed": -906334215, + "status": "ACTIVE", + "killed": true, + "defaultTreatment": "off", + "changeNumber": 1585948717645, + "algo": 2, + "configurations": {}, + "conditions": [ + { + "conditionType": "ROLLOUT", + "matcherGroup": { + "combiner": "AND", + "matchers": [ + { + "keySelector": { + "trafficType": "user", + "attribute": null + }, + "matcherType": "ALL_KEYS", + "negate": false, + "userDefinedSegmentMatcherData": null, + "whitelistMatcherData": null, + "unaryNumericMatcherData": null, + "betweenMatcherData": null, + "booleanMatcherData": null, + "dependencyMatcherData": null, + "stringMatcherData": null + } + ] + }, + "partitions": [ + { + "treatment": "on", + "size": 100 + }, + { + "treatment": "off", + "size": 0 + } + ], + "label": "default rule" + } + ], + "trackImpression": false + } + ], + "since": -1, + "till": 1585948850109 +} From 2dc15dfbd0df0d314480767c202e0fb8dec29a9e Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Thu, 12 Dec 2024 14:34:53 -0800 Subject: [PATCH 4/9] added track to split view --- client/src/main/java/io/split/client/api/SplitView.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/main/java/io/split/client/api/SplitView.java b/client/src/main/java/io/split/client/api/SplitView.java index fe89dbf1d..b9ba3fbc4 100644 --- a/client/src/main/java/io/split/client/api/SplitView.java +++ b/client/src/main/java/io/split/client/api/SplitView.java @@ -26,6 +26,7 @@ public class SplitView { public Map configs; public List sets; public String defaultTreatment; + public boolean trackImpression; public static SplitView fromParsedSplit(ParsedSplit parsedSplit) { SplitView splitView = new SplitView(); @@ -46,6 +47,7 @@ public static SplitView fromParsedSplit(ParsedSplit parsedSplit) { splitView.treatments = new ArrayList(treatments); splitView.configs = parsedSplit.configurations() == null? Collections.emptyMap() : parsedSplit.configurations() ; + splitView.trackImpression = parsedSplit.trackImpression(); return splitView; } From 249ab0373fc47f3c9cf6990cfbefc477da8f8074 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Fri, 13 Dec 2024 14:30:42 -0800 Subject: [PATCH 5/9] added integration tests --- .../client/SplitClientIntegrationTest.java | 237 ++++++++++++++++++ .../io/split/client/SplitManagerImplTest.java | 32 +++ .../engine/experiments/SplitParserTest.java | 15 +- .../src/test/resources/splits_imp_toggle.json | 2 +- 4 files changed, 281 insertions(+), 5 deletions(-) diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java index 2f77415b3..1f7078e80 100644 --- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java +++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java @@ -10,7 +10,11 @@ import io.split.storages.pluggable.CustomStorageWrapperImp; import io.split.storages.pluggable.domain.EventConsumer; import io.split.storages.pluggable.domain.ImpressionConsumer; + +import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; import org.awaitility.Awaitility; import org.glassfish.grizzly.utils.Pair; import org.glassfish.jersey.media.sse.OutboundEvent; @@ -21,6 +25,10 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.nio.Buffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -771,6 +779,235 @@ public void getTreatmentFlagSetWithPolling() throws Exception { splitServer.stop(); } + @Test + public void ImpressionToggleOptimizedModeTest() 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.1&since=-1": + return new MockResponse().setResponseCode(200).setBody(splits); + case "/api/splitChanges?s=1.1&since=1602796638344": + return new MockResponse().setResponseCode(200).setBody("{\"splits\": [], \"since\":1602796638344, \"till\":1602796638344}"); + 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()); + SplitClientConfig config = SplitClientConfig.builder() + .setBlockUntilReadyTimeout(10000) + .endpoint(serverURL, serverURL) + .authServiceURL(String.format("%s/api/auth/enabled", serverURL)) + .telemetryURL(serverURL + "/v1") + .streamingEnabled(false) + .featuresRefreshRate(5) + .impressionsMode(ImpressionsManager.Mode.OPTIMIZED) + .build(); + + SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config); + SplitClient client = factory.client(); + client.blockUntilReady(); + + Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); + Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); + Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); + Thread.sleep(1000); + client.destroy(); + boolean check1 = false, check2 = false; + for (int i=0; i < allRequests.size(); i++ ) { + if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) { + check1 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertTrue(body.contains("without_impression_toggle")); + Assert.assertTrue(body.contains("impression_toggle_on")); + Assert.assertFalse(body.contains("impression_toggle_off")); + } + if (allRequests.get(i).getPath().equals("/v1/keys/ss")) { + check2 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertFalse(body.contains("without_impression_toggle")); + Assert.assertFalse(body.contains("impression_toggle_on")); + Assert.assertTrue(body.contains("impression_toggle_off")); + } + } + server.shutdown(); + Assert.assertTrue(check1); + Assert.assertTrue(check2); + } + + @Test + public void ImpressionToggleDebugModeTest() 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.1&since=-1": + return new MockResponse().setResponseCode(200).setBody(splits); + case "/api/splitChanges?s=1.1&since=1602796638344": + return new MockResponse().setResponseCode(200).setBody("{\"splits\": [], \"since\":1602796638344, \"till\":1602796638344}"); + 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()); + SplitClientConfig config = SplitClientConfig.builder() + .setBlockUntilReadyTimeout(10000) + .endpoint(serverURL, serverURL) + .telemetryURL(serverURL + "/v1") + .authServiceURL(String.format("%s/api/auth/enabled", serverURL)) + .streamingEnabled(false) + .featuresRefreshRate(5) + .impressionsMode(ImpressionsManager.Mode.DEBUG) + .build(); + + SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config); + SplitClient client = factory.client(); + client.blockUntilReady(); + + Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); + Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); + Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); + Thread.sleep(1000); + client.destroy(); + boolean check1 = false, check2 = false; + for (int i=0; i < allRequests.size(); i++ ) { + if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) { + check1 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertTrue(body.contains("without_impression_toggle")); + Assert.assertTrue(body.contains("impression_toggle_on")); + Assert.assertFalse(body.contains("impression_toggle_off")); + } + if (allRequests.get(i).getPath().equals("/v1/keys/ss")) { + check2 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertFalse(body.contains("without_impression_toggle")); + Assert.assertFalse(body.contains("impression_toggle_on")); + Assert.assertTrue(body.contains("impression_toggle_off")); + } + } + server.shutdown(); + Assert.assertTrue(check1); + Assert.assertTrue(check2); + } + + @Test + public void ImpressionToggleNoneModeTest() 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.1&since=-1": + return new MockResponse().setResponseCode(200).setBody(splits); + case "/api/splitChanges?s=1.1&since=1602796638344": + return new MockResponse().setResponseCode(200).setBody("{\"splits\": [], \"since\":1602796638344, \"till\":1602796638344}"); + 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()); + 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.NONE) + .build(); + + SplitFactory factory = SplitFactoryBuilder.build("fake-api-token", config); + SplitClient client = factory.client(); + client.blockUntilReady(); + + Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); + Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); + Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); + Thread.sleep(1000); + client.destroy(); + boolean check1 = false, check2 = false, check3 = false; + for (int i=0; i < allRequests.size(); i++ ) { + if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) { + check1 = true; + } + if (allRequests.get(i).getPath().equals("/v1/keys/ss")) { + check2 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertTrue(body.contains("without_impression_toggle")); + Assert.assertTrue(body.contains("impression_toggle_on")); + Assert.assertTrue(body.contains("impression_toggle_off")); + } + if (allRequests.get(i).getPath().equals("/api/testImpressions/count")) { + check3 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertTrue(body.contains("without_impression_toggle")); + Assert.assertTrue(body.contains("impression_toggle_on")); + Assert.assertTrue(body.contains("impression_toggle_off")); + } + } + server.shutdown(); + Assert.assertFalse(check1); + Assert.assertTrue(check2); + Assert.assertTrue(check3); + } + private SSEMockServer buildSSEMockServer(SSEMockServer.SseEventQueue eventQueue) { return new SSEMockServer(eventQueue, (token, version, channel) -> { if (!"1.1".equals(version)) { diff --git a/client/src/test/java/io/split/client/SplitManagerImplTest.java b/client/src/test/java/io/split/client/SplitManagerImplTest.java index c0e60a31c..0eadd45b5 100644 --- a/client/src/test/java/io/split/client/SplitManagerImplTest.java +++ b/client/src/test/java/io/split/client/SplitManagerImplTest.java @@ -2,10 +2,14 @@ import com.google.common.collect.Lists; import io.split.client.api.SplitView; +import io.split.client.dtos.Split; +import io.split.client.dtos.SplitChange; +import io.split.client.utils.Json; import io.split.engine.ConditionsTestUtil; import io.split.engine.SDKReadinessGates; import io.split.engine.experiments.ParsedCondition; import io.split.engine.experiments.ParsedSplit; +import io.split.engine.experiments.SplitParser; import io.split.engine.matchers.AllKeysMatcher; import io.split.engine.matchers.CombiningMatcher; import io.split.grammar.Treatments; @@ -16,6 +20,10 @@ import org.junit.Before; import org.junit.Test; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -24,6 +32,8 @@ import java.util.Map; import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -220,4 +230,26 @@ public void splitCallWithEmptySets() { private ParsedCondition getTestCondition(String treatment) { return ParsedCondition.createParsedConditionForTests(CombiningMatcher.of(new AllKeysMatcher()), Lists.newArrayList(ConditionsTestUtil.partition(treatment, 10))); } + + @Test + public void ImpressionToggleParseTest() throws IOException { + SplitParser parser = new SplitParser(); + String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.json")), StandardCharsets.UTF_8); + SplitChange change = Json.fromJson(splits, SplitChange.class); + SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class); + for (Split split : change.splits) { + ParsedSplit parsedSplit = parser.parse(split); + when(splitCacheConsumer.get(split.name)).thenReturn(parsedSplit); + } + SplitManagerImpl splitManager = new SplitManagerImpl(splitCacheConsumer, + mock(SplitClientConfig.class), + mock(SDKReadinessGates.class), TELEMETRY_STORAGE); + + SplitView splitView = splitManager.split("without_impression_toggle"); + assertTrue(splitView.trackImpression); + splitView = splitManager.split("impression_toggle_on"); + assertTrue(splitView.trackImpression); + splitView = splitManager.split("impression_toggle_off"); + assertFalse(splitView.trackImpression); + } } \ No newline at end of file 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 2958106da..03b3cc2ff 100644 --- a/client/src/test/java/io/split/engine/experiments/SplitParserTest.java +++ b/client/src/test/java/io/split/engine/experiments/SplitParserTest.java @@ -36,6 +36,7 @@ import org.junit.Test; import org.mockito.Mockito; +import javax.validation.constraints.AssertTrue; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -645,19 +646,25 @@ public void ImpressionToggleParseTest() throws IOException { SplitParser parser = new SplitParser(); String splits = new String(Files.readAllBytes(Paths.get("src/test/resources/splits_imp_toggle.json")), StandardCharsets.UTF_8); SplitChange change = Json.fromJson(splits, SplitChange.class); + boolean check1 = false, check2 = false, check3 = false; for (Split split : change.splits) { - // should not cause exception ParsedSplit parsedSplit = parser.parse(split); if (split.name.equals("without_impression_toggle")) { - assertTrue(split.trackImpression); + assertTrue(parsedSplit.trackImpression()); + check1 = true; } if (split.name.equals("impression_toggle_on")) { - assertTrue(split.trackImpression); + assertTrue(parsedSplit.trackImpression()); + check2 = true; } if (split.name.equals("impression_toggle_off")) { - assertFalse(split.trackImpression); + assertFalse(parsedSplit.trackImpression()); + check3 = true; } } + assertTrue(check1); + assertTrue(check2); + assertTrue(check3); } public void setMatcherTest(Condition c, io.split.engine.matchers.Matcher m) { diff --git a/client/src/test/resources/splits_imp_toggle.json b/client/src/test/resources/splits_imp_toggle.json index 4bd499ac2..0c940ff8e 100644 --- a/client/src/test/resources/splits_imp_toggle.json +++ b/client/src/test/resources/splits_imp_toggle.json @@ -151,5 +151,5 @@ } ], "since": -1, - "till": 1585948850109 + "till": 1602796638344 } From ccea626d0319ba3c78eb24cf5dd0775d5586f036 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Fri, 13 Dec 2024 21:30:53 -0800 Subject: [PATCH 6/9] enabled posting impressionCount in debug mode --- .../io/split/client/SplitFactoryImpl.java | 3 +-- .../impressions/HttpImpressionsSender.java | 5 ----- .../impressions/ImpressionsManagerImpl.java | 2 ++ .../client/SplitClientIntegrationTest.java | 10 ++++++++- .../HttpImpressionsSenderTest.java | 22 ------------------- 5 files changed, 12 insertions(+), 30 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitFactoryImpl.java b/client/src/main/java/io/split/client/SplitFactoryImpl.java index 2791d4578..848b50e86 100644 --- a/client/src/main/java/io/split/client/SplitFactoryImpl.java +++ b/client/src/main/java/io/split/client/SplitFactoryImpl.java @@ -630,11 +630,10 @@ private ImpressionsManagerImpl buildImpressionsManager(SplitClientConfig config, .collect(Collectors.toCollection(() -> impressionListeners)); } ProcessImpressionStrategy processImpressionStrategy = null; - ImpressionCounter counter = null; + ImpressionCounter counter = new ImpressionCounter(); ImpressionListener listener = !impressionListeners.isEmpty() ? new ImpressionListener.FederatedImpressionListener(impressionListeners) : null; - counter = new ImpressionCounter(); ProcessImpressionNone processImpressionNone = new ProcessImpressionNone(listener != null, _uniqueKeysTracker, counter); switch (config.impressionsMode()) { diff --git a/client/src/main/java/io/split/client/impressions/HttpImpressionsSender.java b/client/src/main/java/io/split/client/impressions/HttpImpressionsSender.java index 35c0f57f2..7c346a904 100644 --- a/client/src/main/java/io/split/client/impressions/HttpImpressionsSender.java +++ b/client/src/main/java/io/split/client/impressions/HttpImpressionsSender.java @@ -91,11 +91,6 @@ public void postImpressionsBulk(List impressions) { @Override public void postCounters(HashMap raw) { long initTime = System.currentTimeMillis(); - if (_mode.equals(ImpressionsManager.Mode.DEBUG)) { - _logger.warn("Attempted to submit counters in impressions debugging mode. Ignoring"); - return; - } - try { Map> additionalHeaders = new HashMap<>(); diff --git a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java index 95ed56943..1602a9be2 100644 --- a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java +++ b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java @@ -112,6 +112,8 @@ public void start(){ break; case DEBUG: _scheduler.scheduleAtFixedRate(this::sendImpressions, BULK_INITIAL_DELAY_SECONDS, _impressionsRefreshRate, TimeUnit.SECONDS); + _scheduler.scheduleAtFixedRate(this::sendImpressionCounters, COUNT_INITIAL_DELAY_SECONDS, COUNT_REFRESH_RATE_SECONDS, + TimeUnit.SECONDS); break; case NONE: _scheduler.scheduleAtFixedRate(this::sendImpressionCounters, COUNT_INITIAL_DELAY_SECONDS, COUNT_REFRESH_RATE_SECONDS, diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java index 1f7078e80..f44ac5344 100644 --- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java +++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java @@ -907,7 +907,7 @@ public MockResponse dispatch(RecordedRequest request) { Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); Thread.sleep(1000); client.destroy(); - boolean check1 = false, check2 = false; + boolean check1 = false, check2 = false, check3 = false; for (int i=0; i < allRequests.size(); i++ ) { if (allRequests.get(i).getPath().equals("/api/testImpressions/bulk") ) { check1 = true; @@ -923,10 +923,18 @@ public MockResponse dispatch(RecordedRequest request) { Assert.assertFalse(body.contains("impression_toggle_on")); Assert.assertTrue(body.contains("impression_toggle_off")); } + if (allRequests.get(i).getPath().equals("/api/testImpressions/count")) { + check3 = true; + String body = allRequests.get(i).getBody().readUtf8(); + Assert.assertFalse(body.contains("without_impression_toggle")); + Assert.assertFalse(body.contains("impression_toggle_on")); + Assert.assertTrue(body.contains("impression_toggle_off")); + } } server.shutdown(); Assert.assertTrue(check1); Assert.assertTrue(check2); + Assert.assertTrue(check3); } @Test diff --git a/client/src/test/java/io/split/client/impressions/HttpImpressionsSenderTest.java b/client/src/test/java/io/split/client/impressions/HttpImpressionsSenderTest.java index 18a4141cb..604f7a900 100644 --- a/client/src/test/java/io/split/client/impressions/HttpImpressionsSenderTest.java +++ b/client/src/test/java/io/split/client/impressions/HttpImpressionsSenderTest.java @@ -125,28 +125,6 @@ public void testImpressionCountsEndpointOptimized() throws URISyntaxException, I new ImpressionCount.CountPerFeature("test2", 0, 5))); } - @Test - public void testImpressionCountsEndpointDebug() throws URISyntaxException, IOException, IllegalAccessException, - NoSuchMethodException, InvocationTargetException { - URI rootTarget = URI.create("https://kubernetesturl.com/split"); - - // Setup response mock - CloseableHttpClient httpClient = TestHelper.mockHttpClient("", HttpStatus.SC_OK); - SplitHttpClient splitHtpClient = SplitHttpClientImpl.create(httpClient, new RequestDecorator(null), "qwerty", - metadata()); - - // Send counters - HttpImpressionsSender sender = HttpImpressionsSender.create(splitHtpClient, rootTarget, - ImpressionsManager.Mode.DEBUG, TELEMETRY_STORAGE); - HashMap toSend = new HashMap<>(); - toSend.put(new ImpressionCounter.Key("test1", 0), 4); - toSend.put(new ImpressionCounter.Key("test2", 0), 5); - sender.postCounters(toSend); - - // Assert that the HTTP client was not called - verify(httpClient, Mockito.never()).execute(Mockito.any()); - } - @Test public void testImpressionBulksEndpoint() throws URISyntaxException, IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { From 6551209860cf510483a8dbe1a46cf1b73a020067 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Sat, 14 Dec 2024 18:54:17 -0800 Subject: [PATCH 7/9] polish --- .../src/main/java/io/split/client/SplitClientImpl.java | 2 +- .../java/io/split/client/dtos/DecoratedImpression.java | 8 ++++++-- .../client/impressions/ImpressionsManagerImpl.java | 6 +++--- .../test/java/io/split/client/SplitClientImplTest.java | 10 +++++----- .../io/split/client/SplitClientIntegrationTest.java | 3 --- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/client/src/main/java/io/split/client/SplitClientImpl.java b/client/src/main/java/io/split/client/SplitClientImpl.java index 83bf0c66b..1ff143ed2 100644 --- a/client/src/main/java/io/split/client/SplitClientImpl.java +++ b/client/src/main/java/io/split/client/SplitClientImpl.java @@ -455,7 +455,7 @@ private Map processEvaluatorResult(Map 0) { + if (!decoratedImpressions.isEmpty()) { _impressionManager.track(decoratedImpressions); } return result; diff --git a/client/src/main/java/io/split/client/dtos/DecoratedImpression.java b/client/src/main/java/io/split/client/dtos/DecoratedImpression.java index 9ba55c60a..67f594edb 100644 --- a/client/src/main/java/io/split/client/dtos/DecoratedImpression.java +++ b/client/src/main/java/io/split/client/dtos/DecoratedImpression.java @@ -3,12 +3,16 @@ import io.split.client.impressions.Impression; public class DecoratedImpression { - public Impression impression; - public boolean track; + private Impression impression; + private boolean track; public DecoratedImpression(Impression impression, boolean track) { this.impression = impression; this.track = track; } + + public Impression impression() { return this.impression;} + + public boolean track() { return this.track;} } diff --git a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java index 1602a9be2..7951005f9 100644 --- a/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java +++ b/client/src/main/java/io/split/client/impressions/ImpressionsManagerImpl.java @@ -132,12 +132,12 @@ public void track(List decoratedImpressions) { for (int i = 0; i < decoratedImpressions.size(); i++) { ImpressionsResult impressionsResult; - if (decoratedImpressions.get(i).track) { + if (decoratedImpressions.get(i).track()) { impressionsResult = _processImpressionStrategy.process(Stream.of( - decoratedImpressions.get(i).impression).collect(Collectors.toList())); + decoratedImpressions.get(i).impression()).collect(Collectors.toList())); } else { impressionsResult = _processImpressionNone.process(Stream.of( - decoratedImpressions.get(i).impression).collect(Collectors.toList())); + decoratedImpressions.get(i).impression()).collect(Collectors.toList())); } if (!Objects.isNull(impressionsResult.getImpressionsToQueue())) { impressionsForLogs.addAll(impressionsResult.getImpressionsToQueue()); diff --git a/client/src/test/java/io/split/client/SplitClientImplTest.java b/client/src/test/java/io/split/client/SplitClientImplTest.java index a586ed5ee..c35ecb988 100644 --- a/client/src/test/java/io/split/client/SplitClientImplTest.java +++ b/client/src/test/java/io/split/client/SplitClientImplTest.java @@ -724,7 +724,7 @@ public void labelsArePopulated() { List impressions = impressionCaptor.getValue(); assertNotNull(impressions); assertEquals(1, impressions.size()); - Impression impression = impressions.get(0).impression; + Impression impression = impressions.get(0).impression(); assertEquals("foolabel", impression.appliedRule()); @@ -824,7 +824,7 @@ private void trafficAllocation(String key, int trafficAllocation, int trafficAll assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); - assertEquals(label, impression.impression.appliedRule()); + assertEquals(label, impression.impression().appliedRule()); } /** @@ -880,7 +880,7 @@ public void notInTrafficAllocationDefaultConfig() { assertNotNull(impressionCaptor.getValue()); assertEquals(1, impressionCaptor.getValue().size()); DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); - assertEquals("not in split", impression.impression.appliedRule()); + assertEquals("not in split", impression.impression().appliedRule()); } @@ -1044,8 +1044,8 @@ public void impressionMetadataIsPropagated() { assertEquals(1, impressionCaptor.getValue().size()); DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getValue().get(0); - assertEquals("foolabel", impression.impression.appliedRule()); - assertEquals(attributes, impression.impression.attributes()); + assertEquals("foolabel", impression.impression().appliedRule()); + assertEquals(attributes, impression.impression().attributes()); } private Partition partition(String treatment, int size) { diff --git a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java index f44ac5344..01636d68d 100644 --- a/client/src/test/java/io/split/client/SplitClientIntegrationTest.java +++ b/client/src/test/java/io/split/client/SplitClientIntegrationTest.java @@ -830,7 +830,6 @@ public MockResponse dispatch(RecordedRequest request) { Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); - Thread.sleep(1000); client.destroy(); boolean check1 = false, check2 = false; for (int i=0; i < allRequests.size(); i++ ) { @@ -905,7 +904,6 @@ public MockResponse dispatch(RecordedRequest request) { Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); - Thread.sleep(1000); client.destroy(); boolean check1 = false, check2 = false, check3 = false; for (int i=0; i < allRequests.size(); i++ ) { @@ -988,7 +986,6 @@ public MockResponse dispatch(RecordedRequest request) { Assert.assertEquals("off", client.getTreatment("user1", "without_impression_toggle", null)); Assert.assertEquals("off", client.getTreatment("user2", "impression_toggle_on", null)); Assert.assertEquals("off", client.getTreatment("user3", "impression_toggle_off", null)); - Thread.sleep(1000); client.destroy(); boolean check1 = false, check2 = false, check3 = false; for (int i=0; i < allRequests.size(); i++ ) { From 29515eb641e6da6bbf694753765b778c6907eef8 Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Mon, 16 Dec 2024 09:01:47 -0800 Subject: [PATCH 8/9] updated version to 4.14.0-rc1 --- client/pom.xml | 4 ++-- okhttp-modules/pom.xml | 6 +++--- pluggable-storage/pom.xml | 2 +- pom.xml | 2 +- redis-wrapper/pom.xml | 2 +- testing/pom.xml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 5758862b2..7bd8119d5 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -5,9 +5,9 @@ io.split.client java-client-parent - 4.13.1 + 4.14.0-rc1 - 4.13.1 + 4.14.0-rc1 java-client jar Java Client diff --git a/okhttp-modules/pom.xml b/okhttp-modules/pom.xml index a62c4e1c5..869f275c5 100644 --- a/okhttp-modules/pom.xml +++ b/okhttp-modules/pom.xml @@ -5,10 +5,10 @@ java-client-parent io.split.client - 4.13.1 + 4.14.0-rc1 4.0.0 - 4.13.1 + 4.14.0-rc1 okhttp-modules jar http-modules @@ -46,7 +46,7 @@ io.split.client java-client - 4.13.1 + 4.14.0-rc1 compile diff --git a/pluggable-storage/pom.xml b/pluggable-storage/pom.xml index aba55f0d7..21554068d 100644 --- a/pluggable-storage/pom.xml +++ b/pluggable-storage/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.13.1 + 4.14.0-rc1 2.1.0 diff --git a/pom.xml b/pom.xml index 5ff9c29e1..f8ed0de06 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 io.split.client java-client-parent - 4.13.1 + 4.14.0-rc1 diff --git a/redis-wrapper/pom.xml b/redis-wrapper/pom.xml index 8ea6657ad..f7b34b633 100644 --- a/redis-wrapper/pom.xml +++ b/redis-wrapper/pom.xml @@ -6,7 +6,7 @@ java-client-parent io.split.client - 4.13.1 + 4.14.0-rc1 redis-wrapper 4.13.1 diff --git a/testing/pom.xml b/testing/pom.xml index 67f75a951..177da8fa7 100644 --- a/testing/pom.xml +++ b/testing/pom.xml @@ -5,7 +5,7 @@ io.split.client java-client-parent - 4.13.1 + 4.14.0-rc1 java-client-testing jar From 18d050cf64a5bd218f2bcda55296b826e95c52ff Mon Sep 17 00:00:00 2001 From: Bilal Al Date: Mon, 16 Dec 2024 09:03:43 -0800 Subject: [PATCH 9/9] updated changes --- CHANGES.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index dcda41f11..55f11e4bf 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,6 @@ +4.14.0 (Dec X, 2024) +- Added support for Impression Toggle in feature flags + 4.13.1 (Dec 5, 2024) - Updated `org.apache.httpcomponents.client5` dependency to 5.4.1 to fix vulnerabilities. - Updated `redis.clients` dependency to 4.4.8 to fix vulnerabilities.