Skip to content

Imp pr client #537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
519 changes: 501 additions & 18 deletions client/src/main/java/io/split/client/SplitClient.java

Large diffs are not rendered by default.

258 changes: 225 additions & 33 deletions client/src/main/java/io/split/client/SplitClientImpl.java

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions client/src/main/java/io/split/client/dtos/EvaluationOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.split.client.dtos;

import java.util.Map;

public class EvaluationOptions {
private Map<String, Object> _properties;

public EvaluationOptions(Map<String, Object> properties) {
_properties = properties;
}
public Map<String, Object> getProperties() {
return _properties;
};
}
8 changes: 8 additions & 0 deletions client/src/main/java/io/split/client/dtos/KeyImpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ public class KeyImpression {
/* package private */ static final String FIELD_TIME = "m";
/* package private */ static final String FIELD_CHANGE_NUMBER = "c";
/* package private */ static final String FIELD_PREVIOUS_TIME = "pt";
/* package private */ static final String FIELD_PROPERTIES = "properties";

public static int MAX_PROPERTIES_LENGTH_BYTES = 32 * 1024;

public transient String feature; // Non-serializable

Expand All @@ -39,6 +42,9 @@ public class KeyImpression {
@SerializedName(FIELD_PREVIOUS_TIME)
public Long previousTime;

@SerializedName(FIELD_PROPERTIES)
public String properties;

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -50,6 +56,7 @@ public boolean equals(Object o) {
if (!Objects.equals(feature, that.feature)) return false;
if (!keyName.equals(that.keyName)) return false;
if (!treatment.equals(that.treatment)) return false;
if (properties != null && !properties.equals(that.properties)) return false;

if (bucketingKey == null) {
return that.bucketingKey == null;
Expand Down Expand Up @@ -78,6 +85,7 @@ public static KeyImpression fromImpression(Impression i) {
ki.treatment = i.treatment();
ki.label = i.appliedRule();
ki.previousTime = i.pt();
ki.properties = i.properties();
return ki;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ public class Impression {
private final Long _changeNumber;
private Long _pt;
private final Map<String, Object> _attributes;
private final String _properties;


public Impression(String key, String bucketingKey, String featureFlag, String treatment, long time, String appliedRule,
Long changeNumber, Map<String, Object> atributes) {
Long changeNumber, Map<String, Object> atributes, String properties) {
_key = key;
_bucketingKey = bucketingKey;
_split = featureFlag;
Expand All @@ -28,6 +29,7 @@ public Impression(String key, String bucketingKey, String featureFlag, String tr
_appliedRule = appliedRule;
_changeNumber = changeNumber;
_attributes = atributes;
_properties = properties;
}

public String key() {
Expand Down Expand Up @@ -67,4 +69,8 @@ public Long pt() {
}

public Impression withPreviousTime(Long pt) { _pt = pt; return this; }

public String properties() {
return _properties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public ProcessImpressionDebug(boolean listenerEnabled, ImpressionObserver impres
@Override
public ImpressionsResult process(List<Impression> impressions) {
for(Impression impression : impressions) {
if (impression.properties() != null) {
continue;
}
impression.withPreviousTime(_impressionObserver.testAndSet(impression));
}
List<Impression> impressionForListener = this._listenerEnabled ? impressions : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public ProcessImpressionOptimized(boolean listenerEnabled, ImpressionObserver im
public ImpressionsResult process(List<Impression> impressions) {
List<Impression> impressionsToQueue = new ArrayList<>();
for(Impression impression : impressions) {
if (impression.properties() != null) {
impressionsToQueue.add(impression);
continue;
}
impression = impression.withPreviousTime(_impressionObserver.testAndSet(impression));
if(!Objects.isNull(impression.pt()) && impression.pt() != 0){
_impressionCounter.inc(impression.split(), impression.time(), 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.split.inputValidation;

import java.util.Map;

public class ImpressionPropertiesValidator {

public static ImpressionPropertiesValidatorResult propertiesAreValid(Map<String, Object> properties) {
EventsValidator.EventValidatorResult result = EventsValidator.propertiesAreValid(properties);
return new ImpressionPropertiesValidatorResult(result.getSuccess(), result.getEventSize(), result.getValue());
}

public static class ImpressionPropertiesValidatorResult extends EventsValidator.EventValidatorResult {
public ImpressionPropertiesValidatorResult(boolean success, int eventSize, Map<String, Object> value) {
super(success, eventSize, value);
}
}
}

91 changes: 84 additions & 7 deletions client/src/test/java/io/split/client/SplitClientImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ public void attributesWork() {
);

assertEquals("on", client.getTreatment("adil@codigo.com", test));
assertEquals("on", client.getTreatment("adil@codigo.com", test, null));
assertEquals("on", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
assertEquals("on", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 10)));
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 9)));
Expand Down Expand Up @@ -599,7 +599,7 @@ public void attributesWork2() {
);

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

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

assertEquals("off", client.getTreatment("adil@codigo.com", test));
assertEquals("off", client.getTreatment("adil@codigo.com", test, null));
assertEquals("off", client.getTreatment("adil@codigo.com", test, new HashMap<>()));
assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", 10)));
assertEquals("on", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("age", -20)));
Expand Down Expand Up @@ -671,7 +671,7 @@ public void attributesForSets() {
);

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

assertEquals("off", client.getTreatment("adil@codigo.com", test, ImmutableMap.<String, Object>of()));
assertEquals("off", client.getTreatment("pato@codigo.com", test, ImmutableMap.<String, Object>of("products", Lists.newArrayList())));
Expand Down Expand Up @@ -1894,7 +1894,7 @@ public void testTreatmentsByFlagSet() {
Map<String, String> getTreatmentResult;
for (int i = 0; i < numKeys; i++) {
String randomKey = RandomStringUtils.random(10);
getTreatmentResult = client.getTreatmentsByFlagSet(randomKey, "set1", null);
getTreatmentResult = client.getTreatmentsByFlagSet(randomKey, "set1", new HashMap<>());
assertEquals("on", getTreatmentResult.get(test));
}
verify(splitCacheConsumer, times(numKeys)).fetchMany(new ArrayList<>(Arrays.asList(test)));
Expand Down Expand Up @@ -1927,7 +1927,7 @@ public void testTreatmentsByFlagSetInvalid() {
new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
flagSetsFilter
);
assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", null).isEmpty());
assertTrue(client.getTreatmentsByFlagSet(RandomStringUtils.random(10), "", new HashMap<>()).isEmpty());
}

@Test
Expand Down Expand Up @@ -1974,7 +1974,7 @@ public void testTreatmentsByFlagSets() {
Map<String, String> getTreatmentResult;
for (int i = 0; i < numKeys; i++) {
String randomKey = RandomStringUtils.random(10);
getTreatmentResult = client.getTreatmentsByFlagSets(randomKey, Arrays.asList("set1", "set3"), null);
getTreatmentResult = client.getTreatmentsByFlagSets(randomKey, Arrays.asList("set1", "set3"), new HashMap<>());
assertEquals("on", getTreatmentResult.get(test));
assertEquals("on", getTreatmentResult.get(test2));
}
Expand Down Expand Up @@ -2081,4 +2081,81 @@ public void treatmentsWorksAndHasConfigFlagSets() {

verify(splitCacheConsumer, times(1)).fetchMany(anyList());
}

@Test
public void impressionPropertiesTest() {
String test = "test1";

ParsedCondition age_equal_to_0_should_be_on = new ParsedCondition(ConditionType.ROLLOUT,
CombiningMatcher.of("age", new EqualToMatcher(-20, DataType.NUMBER)),
Lists.newArrayList(partition("on", 100)),
"foolabel"
);

List<ParsedCondition> conditions = Lists.newArrayList(age_equal_to_0_should_be_on);
ParsedSplit parsedSplit = ParsedSplit.createParsedSplitForTests(test, 123, false, Treatments.OFF, conditions, null, 1, 1, new HashSet<>(Arrays.asList("set")), true);
Map<String, ParsedSplit> parsedSplits = new HashMap<>();
parsedSplits.put(test, parsedSplit);

SplitCacheConsumer splitCacheConsumer = mock(SplitCacheConsumer.class);
SegmentCacheConsumer segmentCacheConsumer = mock(SegmentCacheConsumer.class);
when(splitCacheConsumer.get(test)).thenReturn(parsedSplit);
when(splitCacheConsumer.fetchMany(Arrays.asList(test))).thenReturn(parsedSplits);
Map<String, HashSet<String>> splits = new HashMap<>();
splits.put("set", new HashSet<>(Arrays.asList(test)));
when(splitCacheConsumer.getNamesByFlagSets(Arrays.asList("set"))).thenReturn(splits);

SDKReadinessGates gates = mock(SDKReadinessGates.class);
ImpressionsManager impressionsManager = mock(ImpressionsManager.class);
SplitClientImpl client = new SplitClientImpl(
mock(SplitFactory.class),
splitCacheConsumer,
impressionsManager,
NoopEventsStorageImp.create(),
config,
gates,
new EvaluatorImp(splitCacheConsumer, segmentCacheConsumer), TELEMETRY_STORAGE, TELEMETRY_STORAGE,
new FlagSetsFilterImpl(new HashSet<>())
);
Map<String, Object> attributes = ImmutableMap.<String, Object>of("age", -20, "acv", "1000000");
EvaluationOptions properties = new EvaluationOptions(new HashMap<String, Object>()
{{
put("prop2", "val2");
put("prop1", "val1");
}});
Map<String, String> result = new HashMap<>();
result.put(test, Treatments.ON);
List<String> split_names = Arrays.asList(test);

assertEquals("on", client.getTreatment("pato@codigo.com", test, attributes, properties));
assertEquals("on", client.getTreatmentWithConfig("bilal1@codigo.com", test, attributes, properties).treatment());
assertEquals("on", client.getTreatments("bilal2@codigo.com", Arrays.asList(test), attributes, properties).get(test));
assertEquals("on", client.getTreatmentsWithConfig("bilal3@codigo.com", Arrays.asList(test), attributes, properties).get(test).treatment());
assertEquals("on", client.getTreatmentsByFlagSet("bilal4@codigo.com", "set", attributes, properties).get(test));
assertEquals("on", client.getTreatmentsByFlagSets("bilal5@codigo.com", Arrays.asList("set"), attributes, properties).get(test));
assertEquals("on", client.getTreatmentsWithConfigByFlagSet("bilal6@codigo.com", "set", attributes, properties).get(test).treatment());
assertEquals("on", client.getTreatmentsWithConfigByFlagSets("bilal7@codigo.com", Arrays.asList("set"), attributes, properties).get(test).treatment());
assertEquals("on", client.getTreatment(new Key("bilal8@codigo.com", "bilal8@codigo.com"), test, attributes, properties));
assertEquals("on", client.getTreatmentWithConfig(new Key("bilal9@codigo.com", "bilal9@codigo.com"), test, attributes, properties).treatment());
assertEquals("on", client.getTreatments(new Key("bilal10@codigo.com", "bilal10@codigo.com"), Arrays.asList(test), attributes, properties).get(test));
assertEquals("on", client.getTreatmentsWithConfig(new Key("bilal11@codigo.com", "bilal11@codigo.com"), Arrays.asList(test), attributes, properties).get(test).treatment());
assertEquals("on", client.getTreatmentsByFlagSet(new Key("bilal12@codigo.com", "bilal12@codigo.com"), "set", attributes, properties).get(test));
assertEquals("on", client.getTreatmentsByFlagSets(new Key("bilal13@codigo.com", "bilal13@codigo.com"), Arrays.asList("set"), attributes, properties).get(test));
assertEquals("on", client.getTreatmentsWithConfigByFlagSet(new Key("bilal14@codigo.com", "bilal14@codigo.com"), "set", attributes, properties).get(test).treatment());
assertEquals("on", client.getTreatmentsWithConfigByFlagSets(new Key("bilal15@codigo.com", "bilal15@codigo.com"), Arrays.asList("set"), attributes, properties).get(test).treatment());

ArgumentCaptor<List> impressionCaptor = ArgumentCaptor.forClass(List.class);
verify(impressionsManager, times(16)).track(impressionCaptor.capture());
assertNotNull(impressionCaptor.getValue());

DecoratedImpression impression = (DecoratedImpression) impressionCaptor.getAllValues().get(0).get(0);
assertEquals("pato@codigo.com", impression.impression().key());
assertEquals("{\"prop2\":\"val2\",\"prop1\":\"val1\"}", impression.impression().properties());

for (int i=1; i<=15; i++) {
impression = (DecoratedImpression) impressionCaptor.getAllValues().get(i).get(0);
assertEquals("bilal" + i + "@codigo.com", impression.impression().key());
assertEquals("{\"prop2\":\"val2\",\"prop1\":\"val1\"}", impression.impression().properties());
}
}
}
Loading