Skip to content

Commit 0bfe5cf

Browse files
authored
Merge pull request #542 from splitio/feature/impression-properties
Feature/impression properties
2 parents 69e44f8 + db60cec commit 0bfe5cf

25 files changed

+1549
-293
lines changed

client/src/main/java/io/split/client/SplitClient.java

Lines changed: 501 additions & 18 deletions
Large diffs are not rendered by default.

client/src/main/java/io/split/client/SplitClientImpl.java

Lines changed: 222 additions & 33 deletions
Large diffs are not rendered by default.

client/src/main/java/io/split/client/SplitFactoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public class SplitFactoryImpl implements SplitFactory {
124124
private static final org.slf4j.Logger _log = LoggerFactory.getLogger(SplitFactoryImpl.class);
125125
private static final String LEGACY_LOG_MESSAGE = "The sdk initialize in localhost mode using Legacy file. The splitFile or "
126126
+
127-
"inputStream doesn't add it to the config.";
127+
"inputStream are not added to the config.";
128128
private final static long SSE_CONNECT_TIMEOUT = 30000;
129129
private final static long SSE_SOCKET_TIMEOUT = 70000;
130130

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.split.client.dtos;
2+
3+
import java.util.Map;
4+
5+
public class EvaluationOptions {
6+
private Map<String, Object> _properties;
7+
8+
public EvaluationOptions(Map<String, Object> properties) {
9+
_properties = properties;
10+
}
11+
public Map<String, Object> getProperties() {
12+
return _properties;
13+
}
14+
}

client/src/main/java/io/split/client/dtos/KeyImpression.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class KeyImpression {
1515
/* package private */ static final String FIELD_TIME = "m";
1616
/* package private */ static final String FIELD_CHANGE_NUMBER = "c";
1717
/* package private */ static final String FIELD_PREVIOUS_TIME = "pt";
18+
/* package private */ static final String FIELD_PROPERTIES = "properties";
1819

1920
public transient String feature; // Non-serializable
2021

@@ -39,6 +40,9 @@ public class KeyImpression {
3940
@SerializedName(FIELD_PREVIOUS_TIME)
4041
public Long previousTime;
4142

43+
@SerializedName(FIELD_PROPERTIES)
44+
public String properties;
45+
4246
@Override
4347
public boolean equals(Object o) {
4448
if (this == o) return true;
@@ -50,6 +54,7 @@ public boolean equals(Object o) {
5054
if (!Objects.equals(feature, that.feature)) return false;
5155
if (!keyName.equals(that.keyName)) return false;
5256
if (!treatment.equals(that.treatment)) return false;
57+
if (properties != null && !properties.equals(that.properties)) return false;
5358

5459
if (bucketingKey == null) {
5560
return that.bucketingKey == null;
@@ -78,6 +83,7 @@ public static KeyImpression fromImpression(Impression i) {
7883
ki.treatment = i.treatment();
7984
ki.label = i.appliedRule();
8085
ki.previousTime = i.pt();
86+
ki.properties = i.properties();
8187
return ki;
8288
}
8389
}

client/src/main/java/io/split/client/impressions/Impression.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ public class Impression {
1616
private final Long _changeNumber;
1717
private Long _pt;
1818
private final Map<String, Object> _attributes;
19+
private final String _properties;
1920

2021

2122
public Impression(String key, String bucketingKey, String featureFlag, String treatment, long time, String appliedRule,
22-
Long changeNumber, Map<String, Object> atributes) {
23+
Long changeNumber, Map<String, Object> atributes, String properties) {
2324
_key = key;
2425
_bucketingKey = bucketingKey;
2526
_split = featureFlag;
@@ -28,6 +29,7 @@ public Impression(String key, String bucketingKey, String featureFlag, String tr
2829
_appliedRule = appliedRule;
2930
_changeNumber = changeNumber;
3031
_attributes = atributes;
32+
_properties = properties;
3133
}
3234

3335
public String key() {
@@ -67,4 +69,8 @@ public Long pt() {
6769
}
6870

6971
public Impression withPreviousTime(Long pt) { _pt = pt; return this; }
72+
73+
public String properties() {
74+
return _properties;
75+
}
7076
}

client/src/main/java/io/split/client/impressions/strategy/ProcessImpressionDebug.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ public ProcessImpressionDebug(boolean listenerEnabled, ImpressionObserver impres
1919
@Override
2020
public ImpressionsResult process(List<Impression> impressions) {
2121
for(Impression impression : impressions) {
22+
if (impression.properties() != null) {
23+
continue;
24+
}
2225
impression.withPreviousTime(_impressionObserver.testAndSet(impression));
2326
}
2427
List<Impression> impressionForListener = this._listenerEnabled ? impressions : null;

client/src/main/java/io/split/client/impressions/strategy/ProcessImpressionOptimized.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ public ProcessImpressionOptimized(boolean listenerEnabled, ImpressionObserver im
3232
public ImpressionsResult process(List<Impression> impressions) {
3333
List<Impression> impressionsToQueue = new ArrayList<>();
3434
for(Impression impression : impressions) {
35-
impression = impression.withPreviousTime(_impressionObserver.testAndSet(impression));
36-
if(!Objects.isNull(impression.pt()) && impression.pt() != 0){
37-
_impressionCounter.inc(impression.split(), impression.time(), 1);
38-
}
39-
if(shouldntQueueImpression(impression)) {
40-
continue;
35+
if (impression.properties() == null) {
36+
impression = impression.withPreviousTime(_impressionObserver.testAndSet(impression));
37+
if (!Objects.isNull(impression.pt()) && impression.pt() != 0) {
38+
_impressionCounter.inc(impression.split(), impression.time(), 1);
39+
}
40+
if (shouldntQueueImpression(impression)) {
41+
continue;
42+
}
4143
}
4244
impressionsToQueue.add(impression);
4345
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.split.inputValidation;
2+
3+
import java.util.Map;
4+
5+
public class ImpressionPropertiesValidator {
6+
ImpressionPropertiesValidator() {
7+
throw new IllegalStateException("Utility class");
8+
}
9+
10+
public static ImpressionPropertiesValidatorResult propertiesAreValid(Map<String, Object> properties) {
11+
EventsValidator.EventValidatorResult result = EventsValidator.propertiesAreValid(properties);
12+
return new ImpressionPropertiesValidatorResult(result.getSuccess(), result.getEventSize(), result.getValue());
13+
}
14+
15+
public static class ImpressionPropertiesValidatorResult extends EventsValidator.EventValidatorResult {
16+
public ImpressionPropertiesValidatorResult(boolean success, int eventSize, Map<String, Object> value) {
17+
super(success, eventSize, value);
18+
}
19+
}
20+
}
21+

client/src/test/java/io/split/client/SplitClientImplTest.java

Lines changed: 104 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ public void attributesWork() {
565565
);
566566

567567
assertEquals("on", client.getTreatment("adil@codigo.com", test));
568-
assertEquals("on", client.getTreatment("adil@codigo.com", test, null));
568+
assertEquals("on", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
569569
assertEquals("on", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
570570
assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 10)));
571571
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 9)));
@@ -599,7 +599,7 @@ public void attributesWork2() {
599599
);
600600

601601
assertEquals("off", client.getTreatment("adil@codigo.com", test));
602-
assertEquals("off", client.getTreatment("adil@codigo.com", test, null));
602+
assertEquals("off", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
603603
assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
604604

605605
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 10)));
@@ -634,7 +634,7 @@ public void attributesGreaterThanNegativeNumber() {
634634
);
635635

636636
assertEquals("off", client.getTreatment("adil@codigo.com", test));
637-
assertEquals("off", client.getTreatment("adil@codigo.com", test, null));
637+
assertEquals("off", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
638638
assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
639639
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 10)));
640640
assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", -20)));
@@ -671,7 +671,7 @@ public void attributesForSets() {
671671
);
672672

673673
assertEquals("off", client.getTreatment("adil@codigo.com", test));
674-
assertEquals("off", client.getTreatment("adil@codigo.com", test, null));
674+
assertEquals("off", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
675675

676676
assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
677677
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("products", Lists.newArrayList())));
@@ -1486,6 +1486,7 @@ public void worksAndHasConfigByFlagSetTryKetTreatmentWithKey() {
14861486
assertEquals("on", client.getTreatmentsByFlagSet(randomKey, "set1", new HashMap<>()).get(test));
14871487
assertEquals("{\"size\" : 30}", client.getTreatmentsWithConfigByFlagSet(key, "set1", attributes).get(test).config());
14881488
}
1489+
assertEquals("on", client.getTreatmentsByFlagSet("randomKey", "set1").get(test));
14891490
}
14901491

14911492
@Test
@@ -1894,11 +1895,13 @@ public void testTreatmentsByFlagSet() {
18941895
Map<String, String> getTreatmentResult;
18951896
for (int i = 0; i < numKeys; i++) {
18961897
String randomKey = RandomStringUtils.random(10);
1897-
getTreatmentResult = client.getTreatmentsByFlagSet(randomKey, "set1", null);
1898+
getTreatmentResult = client.getTreatmentsByFlagSet(randomKey, "set1", new HashMap<>());
18981899
assertEquals("on", getTreatmentResult.get(test));
18991900
}
19001901
verify(splitCacheConsumer, times(numKeys)).fetchMany(new ArrayList<>(Arrays.asList(test)));
19011902
verify(TELEMETRY_STORAGE, times(5)).recordLatency(Mockito.anyObject(), Mockito.anyLong());
1903+
getTreatmentResult = client.getTreatmentsByFlagSet("randomKey", "set1");
1904+
assertEquals("on", getTreatmentResult.get(test));
19021905
}
19031906

19041907
@Test
@@ -1927,7 +1930,7 @@ public void testTreatmentsByFlagSetInvalid() {
19271930
new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
19281931
flagSetsFilter
19291932
);
1930-
assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", null).isEmpty());
1933+
assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", new HashMap<>()).isEmpty());
19311934
}
19321935

19331936
@Test
@@ -1974,12 +1977,15 @@ public void testTreatmentsByFlagSets() {
19741977
Map<String, String> getTreatmentResult;
19751978
for (int i = 0; i < numKeys; i++) {
19761979
String randomKey = RandomStringUtils.random(10);
1977-
getTreatmentResult = client.getTreatmentsByFlagSets(randomKey, Arrays.asList("set1", "set3"), null);
1980+
getTreatmentResult = client.getTreatmentsByFlagSets(randomKey, Arrays.asList("set1", "set3"), new HashMap<>());
19781981
assertEquals("on", getTreatmentResult.get(test));
19791982
assertEquals("on", getTreatmentResult.get(test2));
19801983
}
19811984
verify(splitCacheConsumer, times(numKeys)).fetchMany(new ArrayList<>(Arrays.asList(test2, test)));
19821985
verify(TELEMETRY_STORAGE, times(5)).recordLatency(Mockito.anyObject(), Mockito.anyLong());
1986+
getTreatmentResult = client.getTreatmentsByFlagSets("key", Arrays.asList("set1", "set3"));
1987+
assertEquals("on", getTreatmentResult.get(test));
1988+
assertEquals("on", getTreatmentResult.get(test2));
19831989
}
19841990

19851991
@Test
@@ -2030,6 +2036,12 @@ public void treatmentsWorksAndHasConfigFlagSet() {
20302036
assertEquals("control", result.get(test2).treatment());
20312037

20322038
verify(splitCacheConsumer, times(1)).fetchMany(anyList());
2039+
2040+
result = client.getTreatmentsWithConfigByFlagSet("randomKey", "set1");
2041+
assertEquals(2, result.size());
2042+
assertEquals(configurations.get("on"), result.get(test).config());
2043+
assertNull(result.get(test2).config());
2044+
assertEquals("control", result.get(test2).treatment());
20332045
}
20342046

20352047
@Test
@@ -2081,4 +2093,89 @@ public void treatmentsWorksAndHasConfigFlagSets() {
20812093

20822094
verify(splitCacheConsumer, times(1)).fetchMany(anyList());
20832095
}
2096+
2097+
@Test
2098+
public void impressionPropertiesTest() {
2099+
String test = "test1";
2100+
2101+
ParsedCondition age_equal_to_0_should_be_on = new ParsedCondition(ConditionType.ROLLOUT,
2102+
CombiningMatcher.of("age", new EqualToMatcher(-20, DataType.NUMBER)),
2103+
Lists.newArrayList(partition("on", 100)),
2104+
"foolabel"
2105+
);
2106+
2107+
List<ParsedCondition> conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
2108+
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(Arrays.asList("set")), true);
2109+
Map<String, ParsedSplit> parsedSplits = new HashMap<>();
2110+
parsedSplits.put(test, parsedSplit);
2111+
2112+
SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
2113+
SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
2114+
when(splitCacheConsumer.get(test)).thenReturn(parsedSplit);
2115+
when(splitCacheConsumer.fetchMany(Arrays.asList(test))).thenReturn(parsedSplits);
2116+
Map<String, HashSet<String>> splits = new HashMap<>();
2117+
splits.put("set", new HashSet<>(Arrays.asList(test)));
2118+
when(splitCacheConsumer.getNamesByFlagSets(Arrays.asList("set"))).thenReturn(splits);
2119+
2120+
SDKReadinessGates gates = mock(SDKReadinessGates.class);
2121+
ImpressionsManager impressionsManager = mock(ImpressionsManager.class);
2122+
SplitClientImpl client = new SplitClientImpl(
2123+
mock(SplitFactory.class),
2124+
splitCacheConsumer,
2125+
impressionsManager,
2126+
NoopEventsStorageImp.create(),
2127+
config,
2128+
gates,
2129+
new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
2130+
new FlagSetsFilterImpl(new HashSet<>())
2131+
);
2132+
Map<String, Object> attributes = ImmutableMap.<String, Object>of("age", -20, "acv", "1000000");
2133+
EvaluationOptions properties = new EvaluationOptions(new HashMap<String, Object>()
2134+
{{
2135+
put("prop2", "val2");
2136+
put("prop1", "val1");
2137+
}});
2138+
Map<String, String> result = new HashMap<>();
2139+
result.put(test, Treatments.ON);
2140+
List<String> split_names = Arrays.asList(test);
2141+
2142+
assertEquals("on", client.getTreatment("pato@codigo.com", test, attributes, properties));
2143+
assertEquals("on", client.getTreatmentWithConfig("bilal1@codigo.com", test, attributes, properties).treatment());
2144+
assertEquals("on", client.getTreatments("bilal2@codigo.com", Arrays.asList(test), attributes, properties).get(test));
2145+
assertEquals("on", client.getTreatmentsWithConfig("bilal3@codigo.com", Arrays.asList(test), attributes, properties).get(test).treatment());
2146+
assertEquals("on", client.getTreatmentsByFlagSet("bilal4@codigo.com", "set", attributes, properties).get(test));
2147+
assertEquals("on", client.getTreatmentsByFlagSets("bilal5@codigo.com", Arrays.asList("set"), attributes, properties).get(test));
2148+
assertEquals("on", client.getTreatmentsWithConfigByFlagSet("bilal6@codigo.com", "set", attributes, properties).get(test).treatment());
2149+
assertEquals("on", client.getTreatmentsWithConfigByFlagSets("bilal7@codigo.com", Arrays.asList("set"), attributes, properties).get(test).treatment());
2150+
assertEquals("on", client.getTreatment(new Key("bilal8@codigo.com", "bilal8@codigo.com"), test, attributes, properties));
2151+
assertEquals("on", client.getTreatmentWithConfig(new Key("bilal9@codigo.com", "bilal9@codigo.com"), test, attributes, properties).treatment());
2152+
assertEquals("on", client.getTreatments(new Key("bilal10@codigo.com", "bilal10@codigo.com"), Arrays.asList(test), attributes, properties).get(test));
2153+
assertEquals("on", client.getTreatmentsWithConfig(new Key("bilal11@codigo.com", "bilal11@codigo.com"), Arrays.asList(test), attributes, properties).get(test).treatment());
2154+
assertEquals("on", client.getTreatmentsByFlagSet(new Key("bilal12@codigo.com", "bilal12@codigo.com"), "set", attributes, properties).get(test));
2155+
assertEquals("on", client.getTreatmentsByFlagSets(new Key("bilal13@codigo.com", "bilal13@codigo.com"), Arrays.asList("set"), attributes, properties).get(test));
2156+
assertEquals("on", client.getTreatmentsWithConfigByFlagSet(new Key("bilal14@codigo.com", "bilal14@codigo.com"), "set", attributes, properties).get(test).treatment());
2157+
assertEquals("on", client.getTreatmentsWithConfigByFlagSets(new Key("bilal15@codigo.com", "bilal15@codigo.com"), Arrays.asList("set"), attributes, properties).get(test).treatment());
2158+
assertEquals("off", client.getTreatment("bilal16@codigo.com", test, properties));
2159+
assertEquals("off", client.getTreatmentWithConfig("bilal17@codigo.com", test, properties).treatment());
2160+
assertEquals("off", client.getTreatments("bilal18@codigo.com", Arrays.asList(test), properties).get(test));
2161+
assertEquals("off", client.getTreatmentsWithConfig("bilal19@codigo.com", Arrays.asList(test), properties).get(test).treatment());
2162+
assertEquals("off", client.getTreatmentsByFlagSet("bilal20@codigo.com", "set", properties).get(test));
2163+
assertEquals("off", client.getTreatmentsByFlagSets("bilal21@codigo.com", Arrays.asList("set"), properties).get(test));
2164+
assertEquals("off", client.getTreatmentsWithConfigByFlagSet("bilal22@codigo.com", "set", properties).get(test).treatment());
2165+
assertEquals("off", client.getTreatmentsWithConfigByFlagSets("bilal23@codigo.com", Arrays.asList("set"), properties).get(test).treatment());
2166+
2167+
ArgumentCaptor<List> impressionCaptor = ArgumentCaptor.forClass(List.class);
2168+
verify(impressionsManager, times(24)).track(impressionCaptor.capture());
2169+
assertNotNull(impressionCaptor.getValue());
2170+
2171+
DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getAllValues().get(0).get(0);
2172+
assertEquals("pato@codigo.com", impression.impression().key());
2173+
assertEquals("{\"prop2\":\"val2\",\"prop1\":\"val1\"}", impression.impression().properties());
2174+
2175+
for (int i=1; i<=23; i++) {
2176+
impression = (DecoratedImpression) impressionCaptor.getAllValues().get(i).get(0);
2177+
assertEquals("bilal" + i + "@codigo.com", impression.impression().key());
2178+
assertEquals("{\"prop2\":\"val2\",\"prop1\":\"val1\"}", impression.impression().properties());
2179+
}
2180+
}
20842181
}

0 commit comments

Comments
 (0)