Skip to content

Commit

Permalink
added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Bilal Al committed Dec 12, 2024
1 parent 4d8dec8 commit 117eb91
Show file tree
Hide file tree
Showing 3 changed files with 354 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<TestImpressions> 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<String, HashSet<String>> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll();
HashSet<String> 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<ImpressionCounter.Key, Integer> 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<String, HashSet<String>> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll();
HashSet<String> 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<TestImpressions> 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<String, HashSet<String>> trackedKeys = ((UniqueKeysTrackerImp) uniqueKeysTracker).popAll();
uniqueKeysTracker.stop();

HashSet<String> 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<ImpressionCounter.Key, Integer> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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);
Expand Down
155 changes: 155 additions & 0 deletions client/src/test/resources/splits_imp_toggle.json
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 117eb91

Please sign in to comment.