Skip to content

Commit b768213

Browse files
committed
add tests
1 parent 2666274 commit b768213

File tree

8 files changed

+333
-42
lines changed

8 files changed

+333
-42
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public static final class Builder {
256256
private boolean _eventsEndpointSet = false;
257257
private int _featuresRefreshRate = 60;
258258
private int _segmentsRefreshRate = 60;
259-
private int _impressionsRefreshRate = 30;
259+
private int _impressionsRefreshRate = -1; // use -1 to identify lack of a user submitted value & handle in build()
260260
private int _impressionsQueueSize = 30000;
261261
private ImpressionsManager.Mode _impressionsMode = ImpressionsManager.Mode.OPTIMIZED;
262262
private int _connectionTimeout = 15000;
@@ -683,8 +683,13 @@ public SplitClientConfig build() {
683683
throw new IllegalArgumentException("segmentsRefreshRate must be >= 30: " + _segmentsRefreshRate);
684684
}
685685

686-
if (_impressionsRefreshRate <= 0) {
687-
throw new IllegalArgumentException("impressionsRefreshRate must be > 0: " + _impressionsRefreshRate);
686+
switch (_impressionsMode) {
687+
case OPTIMIZED:
688+
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 300 : Math.max(60, _impressionsRefreshRate);
689+
break;
690+
case DEBUG:
691+
_impressionsRefreshRate = (_impressionsRefreshRate <= 0) ? 30 : _impressionsRefreshRate;
692+
break;
688693
}
689694

690695
if (_eventFlushIntervalInMillis < 1000) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public SplitFactoryImpl(String apiToken, SplitClientConfig config) throws URISyn
183183
}
184184

185185
// Impressions
186-
final ImpressionsManagerImpl impressionsManager = ImpressionsManagerImpl.instance(httpclient, config, impressionListeners, config.impressionsMode());
186+
final ImpressionsManagerImpl impressionsManager = ImpressionsManagerImpl.instance(httpclient, config, impressionListeners);
187187

188188
CachedMetrics cachedMetrics = new CachedMetrics(httpMetrics, TimeUnit.SECONDS.toMillis(config.metricsRefreshRate()));
189189
final FireAndForgetMetrics cachedFireAndForgetMetrics = FireAndForgetMetrics.instance(cachedMetrics, 2, 1000);
Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
package io.split.client.dtos;
22

3+
import com.google.gson.annotations.SerializedName;
34
import io.split.client.impressions.ImpressionCounter;
45
import java.util.List;
56
import java.util.Map;
7+
import java.util.Objects;
68
import java.util.stream.Collectors;
79

810
public class ImpressionCount {
911

10-
public final List<CountPerFeature> counts;
12+
private static final String FIELD_PER_FEATURE_COUNTS = "pf";
13+
14+
@SerializedName(FIELD_PER_FEATURE_COUNTS)
15+
public final List<CountPerFeature> perFeature;
1116

1217
public ImpressionCount(List<CountPerFeature> cs) {
13-
counts = cs;
18+
perFeature = cs;
1419
}
1520

1621
public static ImpressionCount fromImpressionCounterData(Map<ImpressionCounter.Key, Integer> raw) {
@@ -19,15 +24,54 @@ public static ImpressionCount fromImpressionCounterData(Map<ImpressionCounter.Ke
1924
.collect(Collectors.toList()));
2025
}
2126

27+
@Override
28+
public int hashCode() {
29+
return Objects.hash(perFeature);
30+
}
31+
32+
@Override
33+
public boolean equals(Object o) {
34+
if (this == o) return true;
35+
if (o == null || getClass() != o.getClass()) return false;
36+
37+
ImpressionCount c = (ImpressionCount) o;
38+
return Objects.equals(perFeature, c.perFeature);
39+
}
40+
2241
public static class CountPerFeature {
42+
43+
private static final String FIELD_FEATURE = "f";
44+
private static final String FIELD_TIMEFRAME = "t";
45+
private static final String FIELD_COUNT = "c";
46+
47+
@SerializedName(FIELD_FEATURE)
2348
public final String feature;
49+
50+
@SerializedName(FIELD_TIMEFRAME)
2451
public final long timeframe;
52+
53+
@SerializedName(FIELD_COUNT)
2554
public final int count;
2655

2756
public CountPerFeature(String f, long t, int c) {
2857
feature = f;
2958
timeframe = t;
3059
count = c;
3160
}
61+
62+
@Override
63+
public int hashCode() {
64+
return Objects.hash(feature, timeframe, count);
65+
}
66+
67+
@Override
68+
public boolean equals(Object o) {
69+
if (this == o) return true;
70+
if (o == null || getClass() != o.getClass()) return false;
71+
72+
CountPerFeature c = (CountPerFeature) o;
73+
return Objects.equals(feature, c.feature) && Objects.equals(timeframe, c.timeframe) &&
74+
Objects.equals(count, c.count);
75+
}
3276
}
3377
}

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,25 @@ public class HttpImpressionsSender implements ImpressionsSender {
2525

2626
private static final String BULK_ENDPOINT_PATH = "api/testImpressions/bulk";
2727
private static final String COUNT_ENDPOINT_PATH = "api/testImpressions/count";
28+
private static final String IMPRESSIONS_MODE_HEADER = "SplitImpressionsMode";
2829

2930
private static final Logger _logger = LoggerFactory.getLogger(HttpImpressionsSender.class);
3031

3132
private final CloseableHttpClient _client;
3233
private final URI _impressionBulkTarget;
3334
private final URI _impressionCountTarget;
35+
private final ImpressionsManager.Mode _mode;
3436

35-
36-
public static HttpImpressionsSender create(CloseableHttpClient client, URI eventsRootEndpoint) throws URISyntaxException {
37+
public static HttpImpressionsSender create(CloseableHttpClient client, URI eventsRootEndpoint, ImpressionsManager.Mode mode) throws URISyntaxException {
3738
return new HttpImpressionsSender(client,
3839
Utils.appendPath(eventsRootEndpoint, BULK_ENDPOINT_PATH),
39-
Utils.appendPath(eventsRootEndpoint, COUNT_ENDPOINT_PATH));
40+
Utils.appendPath(eventsRootEndpoint, COUNT_ENDPOINT_PATH),
41+
mode);
4042
}
4143

42-
private HttpImpressionsSender(CloseableHttpClient client, URI impressionBulkTarget, URI impressionCountTarget) {
44+
private HttpImpressionsSender(CloseableHttpClient client, URI impressionBulkTarget, URI impressionCountTarget, ImpressionsManager.Mode mode) {
4345
_client = client;
46+
_mode = mode;
4447
_impressionBulkTarget = impressionBulkTarget;
4548
_impressionCountTarget = impressionCountTarget;
4649
}
@@ -54,6 +57,7 @@ public void postImpressionsBulk(List<TestImpressions> impressions) {
5457
StringEntity entity = Utils.toJsonEntity(impressions);
5558

5659
HttpPost request = new HttpPost(_impressionBulkTarget);
60+
request.addHeader(IMPRESSIONS_MODE_HEADER, _mode.toString());
5761
request.setEntity(entity);
5862

5963
response = _client.execute(request);
@@ -74,11 +78,15 @@ public void postImpressionsBulk(List<TestImpressions> impressions) {
7478

7579
@Override
7680
public void postCounters(HashMap<ImpressionCounter.Key, Integer> raw) {
81+
if (_mode.equals(ImpressionsManager.Mode.DEBUG)) {
82+
_logger.warn("Attempted to submit counters in impressions debugging mode. Ignoring");
83+
return;
84+
}
85+
7786
HttpPost request = new HttpPost(_impressionCountTarget);
7887
request.setEntity(Utils.toJsonEntity(ImpressionCount.fromImpressionCounterData(raw)));
7988
try (CloseableHttpResponse response = _client.execute(request)) {
8089
int status = response.getStatusLine().getStatusCode();
81-
8290
if (status < 200 || status >= 300) {
8391
_logger.warn("Response status was: " + status);
8492
}

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
public class ImpressionsManagerImpl implements ImpressionsManager, Closeable {
2828

2929
private static final Logger _log = LoggerFactory.getLogger(ImpressionsManagerImpl.class);
30+
31+
private static final long BULK_INITIAL_DELAY_SECONDS = 10L;
32+
private static final long COUNT_INITIAL_DELAY_SECONDS = 100L;
3033
private static final long LAST_SEEN_CACHE_SIZE = 500000; // cache up to 500k impression hashes
3134

3235
private final SplitClientConfig _config;
@@ -40,35 +43,36 @@ public class ImpressionsManagerImpl implements ImpressionsManager, Closeable {
4043

4144
public static ImpressionsManagerImpl instance(CloseableHttpClient client,
4245
SplitClientConfig config,
43-
List<ImpressionListener> listeners,
44-
Mode mode) throws URISyntaxException {
45-
return new ImpressionsManagerImpl(client, config, null, listeners, mode);
46+
List<ImpressionListener> listeners) throws URISyntaxException {
47+
return new ImpressionsManagerImpl(client, config, null, listeners);
4648
}
4749

4850
public static ImpressionsManagerImpl instanceForTest(CloseableHttpClient client,
4951
SplitClientConfig config,
5052
ImpressionsSender impressionsSender,
5153
List<ImpressionListener> listeners) throws URISyntaxException {
52-
return new ImpressionsManagerImpl(client, config, impressionsSender, listeners, Mode.DEBUG);
54+
return new ImpressionsManagerImpl(client, config, impressionsSender, listeners);
5355
}
5456

5557
private ImpressionsManagerImpl(CloseableHttpClient client,
5658
SplitClientConfig config,
5759
ImpressionsSender impressionsSender,
58-
List<ImpressionListener> listeners,
59-
Mode mode) throws URISyntaxException {
60+
List<ImpressionListener> listeners) throws URISyntaxException {
61+
6062

61-
_mode = checkNotNull(mode);
62-
_config = config;
63+
_config = checkNotNull(config);
64+
_mode = checkNotNull(config.impressionsMode());
6365
_storage = new InMemoryImpressionsStorage(config.impressionsQueueSize());
6466
_impressionObserver = new ImpressionObserver(LAST_SEEN_CACHE_SIZE);
6567
_counter = new ImpressionCounter();
6668
_impressionsSender = (null != impressionsSender) ? impressionsSender
67-
: HttpImpressionsSender.create(client, URI.create(config.eventsEndpoint()));
69+
: HttpImpressionsSender.create(client, URI.create(config.eventsEndpoint()), _mode);
6870

6971
_scheduler = buildExecutor();
70-
_scheduler.scheduleAtFixedRate(this::sendImpressions, 10, config.impressionsRefreshRate(), TimeUnit.SECONDS);
71-
_scheduler.scheduleAtFixedRate(this::sendImpressionCounters, 100, config.impressionsRefreshRate(), TimeUnit.SECONDS);
72+
_scheduler.scheduleAtFixedRate(this::sendImpressions, BULK_INITIAL_DELAY_SECONDS,config.impressionsRefreshRate(), TimeUnit.SECONDS);
73+
if (Mode.OPTIMIZED.equals(_mode)) {
74+
_scheduler.scheduleAtFixedRate(this::sendImpressionCounters, COUNT_INITIAL_DELAY_SECONDS, config.impressionsRefreshRate(), TimeUnit.SECONDS);
75+
}
7276

7377
_listener = (null != listeners && !listeners.isEmpty()) ? new ImpressionListener.FederatedImpressionListener(listeners)
7478
: new ImpressionListener.NoopImpressionListener();
@@ -130,7 +134,8 @@ public void close() {
130134
}
131135
}
132136

133-
private void sendImpressionCounters() {
137+
@VisibleForTesting
138+
/* package private */ void sendImpressionCounters() {
134139
if (!_counter.isEmpty()) {
135140
_impressionsSender.postCounters(_counter.popAll());
136141
}

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

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import io.split.client.impressions.Impression;
44
import io.split.client.impressions.ImpressionListener;
5+
import io.split.client.impressions.ImpressionsManager;
56
import io.split.integrations.IntegrationsConfig;
67
import org.hamcrest.Matchers;
78
import org.junit.Assert;
89
import org.junit.Test;
910

11+
import static org.hamcrest.MatcherAssert.assertThat;
1012
import static org.hamcrest.Matchers.equalTo;
1113
import static org.hamcrest.Matchers.is;
1214

@@ -26,18 +28,52 @@ public void cannot_set_segment_refresh_rate_to_less_than_30() {
2628
.build();
2729
}
2830

29-
@Test(expected = IllegalArgumentException.class)
30-
public void cannot_set_impression_refresh_rate_to_equal_to_0() {
31-
SplitClientConfig.builder()
31+
@Test
32+
public void testImpressionRefreshRateConstraints() {
33+
SplitClientConfig cfg = SplitClientConfig.builder()
34+
.impressionsRefreshRate(-1)
35+
.build(); // OPTIMIZED BY DEFAULT
36+
37+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.OPTIMIZED)));
38+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(5 * 60))); // 5 minutes
39+
40+
cfg = SplitClientConfig.builder()
3241
.impressionsRefreshRate(0)
33-
.build();
34-
}
42+
.build(); // OPTIMIZED BY DEFAULT
3543

36-
@Test(expected = IllegalArgumentException.class)
37-
public void cannot_set_impression_refresh_rate_to_less_than_0() {
38-
SplitClientConfig.builder()
44+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.OPTIMIZED)));
45+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(5 * 60))); // 5 minutes
46+
47+
cfg = SplitClientConfig.builder()
48+
.impressionsRefreshRate(1) // default value
49+
.build(); // OPTIMIZED BY DEFAULT
50+
51+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.OPTIMIZED)));
52+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(60))); // 5 minutes
53+
54+
cfg = SplitClientConfig.builder()
55+
.impressionsMode(ImpressionsManager.Mode.DEBUG)
3956
.impressionsRefreshRate(-1)
40-
.build();
57+
.build(); // OPTIMIZED BY DEFAULT
58+
59+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.DEBUG)));
60+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(30))); // 5 minutes
61+
62+
cfg = SplitClientConfig.builder()
63+
.impressionsMode(ImpressionsManager.Mode.DEBUG)
64+
.impressionsRefreshRate(0)
65+
.build(); // OPTIMIZED BY DEFAULT
66+
67+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.DEBUG)));
68+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(30))); // 5 minutes
69+
70+
cfg = SplitClientConfig.builder()
71+
.impressionsMode(ImpressionsManager.Mode.DEBUG)
72+
.impressionsRefreshRate(1) // default value
73+
.build(); // OPTIMIZED BY DEFAULT
74+
75+
assertThat(cfg.impressionsMode(), is(equalTo(ImpressionsManager.Mode.DEBUG)));
76+
assertThat(cfg.impressionsRefreshRate(), is(equalTo(1))); // 5 minutes
4177
}
4278

4379
@Test

0 commit comments

Comments
 (0)