Skip to content

Commit

Permalink
Sets telemetry tests (#541)
Browse files Browse the repository at this point in the history
  • Loading branch information
gthea authored Sep 14, 2023
2 parents ef47f73 + bf8bca2 commit 776e30b
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;

import android.content.Context;
Expand All @@ -11,6 +12,7 @@
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
Expand All @@ -28,6 +30,8 @@
import io.split.android.client.SplitClient;
import io.split.android.client.SplitClientConfig;
import io.split.android.client.SplitFactory;
import io.split.android.client.SplitFilter;
import io.split.android.client.SyncConfig;
import io.split.android.client.api.Key;
import io.split.android.client.dtos.Split;
import io.split.android.client.dtos.SplitChange;
Expand Down Expand Up @@ -79,19 +83,77 @@ public void telemetryInitTest() {

@Test
public void telemetryEvaluationLatencyTest() {
initializeClient(false);
initializeClient(false, "a", "b");
client.getTreatment("test_split");
client.getTreatments(Arrays.asList("test_split", "test_split_2"), null);
client.getTreatmentWithConfig("test_split", null);
client.getTreatmentsWithConfig(Arrays.asList("test_split", "test_split_2"), null);
client.track("test_traffic_type", "test_split");
client.getTreatmentsByFlagSet("a", null);
client.getTreatmentsByFlagSets(Arrays.asList("a", "b"), null);
client.getTreatmentsWithConfigByFlagSet("a", null);
client.getTreatmentsWithConfigByFlagSets(Arrays.asList("a", "b"), null);

MethodLatencies methodLatencies = mTelemetryStorage.popLatencies();
assertFalse(methodLatencies.getTreatment().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatments().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentWithConfig().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentsWithConfig().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTrack().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentsByFlagSet().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentsByFlagSets().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentsWithConfigByFlagSet().stream().allMatch(aLong -> aLong == 0L));
assertFalse(methodLatencies.getTreatmentsWithConfigByFlagSets().stream().allMatch(aLong -> aLong == 0L));
}

@Test
public void evaluationByFlagsInfoIsInPayload() throws InterruptedException {
CountDownLatch metricsLatch = new CountDownLatch(1);
AtomicReference<String> metricsPayload = new AtomicReference<>();
final Dispatcher dispatcher = new Dispatcher() {

@Override
public MockResponse dispatch(RecordedRequest request) {
String path = request.getPath();
if (path.contains("/mySegments")) {
return new MockResponse().setResponseCode(200).setBody("{\"mySegments\":[{ \"id\":\"id1\", \"name\":\"segment1\"}, { \"id\":\"id1\", \"name\":\"segment2\"}]}");
} else if (path.contains("/splitChanges")) {
long changeNumber = -1;
return new MockResponse().setResponseCode(200)
.setBody("{\"splits\":[], \"since\":" + changeNumber + ", \"till\":" + (changeNumber + 1000) + "}");
} else if (path.contains("/events/bulk")) {
return new MockResponse().setResponseCode(200);
} else if (path.contains("metrics/usage")) {
metricsPayload.set(request.getBody().readUtf8());
metricsLatch.countDown();
return new MockResponse().setResponseCode(200);
} else if (path.contains("metrics")) {
return new MockResponse().setResponseCode(200);
} else if (path.contains("auth")) {
return new MockResponse().setResponseCode(401);
} else {
return new MockResponse().setResponseCode(404);
}
}
};

mWebServer.setDispatcher(dispatcher);

initializeClient(false, "a", "b");
client.getTreatmentsByFlagSet("a", null);
client.getTreatmentsByFlagSets(Arrays.asList("a", "b"), null);
client.getTreatmentsWithConfigByFlagSet("a", null);
client.getTreatmentsWithConfigByFlagSets(Arrays.asList("a", "b"), null);

boolean await = metricsLatch.await(10, TimeUnit.SECONDS);

assertTrue(await);
assertTrue(metricsPayload.get().contains("\"tf\":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"));
assertTrue(metricsPayload.get().contains("\"tfs\":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"));
assertTrue(metricsPayload.get().contains("\"tcf\":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"));
assertTrue(metricsPayload.get().contains("\"tcfs\":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]"));
assertTrue(metricsPayload.get().contains("\"tcf\":0,\"tcfs\":0"));
assertTrue(metricsPayload.get().contains("\"tf\":0,\"tfs\":0"));
}

@Test
Expand Down Expand Up @@ -195,11 +257,53 @@ public void recordSessionLength() throws InterruptedException {
assertTrue(sessionLength > 0);
}

private void initializeClient(boolean streamingEnabled) {
@Test
public void flagSetsAreIncludedInPayload() throws InterruptedException {
CountDownLatch sseLatch = new CountDownLatch(1);
CountDownLatch metricsLatch = new CountDownLatch(2);
AtomicReference<String> metricsPayload = new AtomicReference<>();
final Dispatcher dispatcher = new Dispatcher() {

@Override
public MockResponse dispatch(RecordedRequest request) {
String path = request.getPath();
if (path.contains("/mySegments")) {
return new MockResponse().setResponseCode(200).setBody("{\"mySegments\":[{ \"id\":\"id1\", \"name\":\"segment1\"}, { \"id\":\"id1\", \"name\":\"segment2\"}]}");
} else if (path.contains("/splitChanges")) {
long changeNumber = -1;
return new MockResponse().setResponseCode(200)
.setBody("{\"splits\":[], \"since\":" + changeNumber + ", \"till\":" + (changeNumber + 1000) + "}");
} else if (path.contains("/events/bulk")) {
return new MockResponse().setResponseCode(200);
} else if (path.contains("metrics/usage")) {
metricsLatch.countDown();
return new MockResponse().setResponseCode(200);
} else if (path.contains("metrics")) {
metricsPayload.set(request.getBody().readUtf8());
return new MockResponse().setResponseCode(200);
} else if (path.contains("auth")) {
sseLatch.countDown();
return new MockResponse().setResponseCode(401);
} else {
return new MockResponse().setResponseCode(404);
}
}
};

mWebServer.setDispatcher(dispatcher);

initializeClient(false, "a", "_b", "a", "a", "c", "d", "_d");
metricsLatch.await(20, TimeUnit.SECONDS);
String s = metricsPayload.get();
assertTrue(s.contains("\"fsT\":5"));
assertTrue(s.contains("\"fsI\":2"));
}

private void initializeClient(boolean streamingEnabled, String ... sets) {
insertSplitsFromFileIntoDB();
CountDownLatch countDownLatch = new CountDownLatch(1);

client = getTelemetrySplitFactory(mWebServer, streamingEnabled).client();
client = getTelemetrySplitFactory(mWebServer, streamingEnabled, sets).client();

TestingHelper.TestEventTask readyFromCacheTask = new TestingHelper.TestEventTask(countDownLatch);
client.on(SplitEvent.SDK_READY, readyFromCacheTask);
Expand All @@ -211,15 +315,15 @@ private void initializeClient(boolean streamingEnabled) {
}
}

private SplitFactory getTelemetrySplitFactory(MockWebServer webServer, boolean streamingEnabled) {
private SplitFactory getTelemetrySplitFactory(MockWebServer webServer, boolean streamingEnabled, String... sets) {
final String url = webServer.url("/").url().toString();
ServiceEndpoints endpoints = ServiceEndpoints.builder()
.eventsEndpoint(url)
.telemetryServiceEndpoint(url)
.sseAuthServiceEndpoint(url)
.apiEndpoint(url).eventsEndpoint(url).build();

SplitClientConfig config = new TestableSplitConfigBuilder()
TestableSplitConfigBuilder builder = new TestableSplitConfigBuilder()
.serviceEndpoints(endpoints)
.enableDebug()
.telemetryRefreshRate(10)
Expand All @@ -228,8 +332,15 @@ private SplitFactory getTelemetrySplitFactory(MockWebServer webServer, boolean s
.impressionsRefreshRate(9999)
.readTimeout(3000)
.streamingEnabled(streamingEnabled)
.shouldRecordTelemetry(true)
.build();
.shouldRecordTelemetry(true);

if (sets != null && sets.length > 0) {
builder.syncConfig(SyncConfig.builder()
.addSplitFilter(SplitFilter.bySet(Arrays.asList(sets)))
.build());
}

SplitClientConfig config = builder.build();
mTelemetryStorage = StorageFactory.getTelemetryStorage(true);

return IntegrationHelper.buildFactory(
Expand Down
12 changes: 10 additions & 2 deletions src/main/java/io/split/android/client/SyncConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,28 @@ public class SyncConfig {

private final List<SplitFilter> mFilters;

private int mInvalidValueCount = 0;

private SyncConfig(List<SplitFilter> filters) {
private SyncConfig(List<SplitFilter> filters, int invalidValueCount) {
mFilters = filters;
mInvalidValueCount = invalidValueCount;
}

public List<SplitFilter> getFilters() {
return mFilters;
}

public int getInvalidValueCount() {
return mInvalidValueCount;
}

public static Builder builder() {
return new Builder();
}

public static class Builder {
private List<SplitFilter> mBuilderFilters = new ArrayList<>();
private int mInvalidValueCount = 0;
private final SplitValidator mSplitValidator = new SplitValidatorImpl();

public SyncConfig build() {
Expand All @@ -46,14 +53,15 @@ public SyncConfig build() {
validatedFilters.add(new SplitFilter(filter.getType(), validatedValues));
}
}
return new SyncConfig(validatedFilters);
return new SyncConfig(validatedFilters, mInvalidValueCount);
}

public Builder addSplitFilter(@NonNull SplitFilter filter) {
if (filter == null) {
throw new IllegalArgumentException("Filter can't be null");
}
mBuilderFilters.add(filter);
mInvalidValueCount += filter.getInvalidValueCount();
return this;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ private TelemetryTaskFactory initializeTelemetryTaskFactory(@NonNull SplitClient
SplitFilter bySetFilter = filters.get(SplitFilter.Type.BY_SET);
if (bySetFilter != null) {
flagSetCount = bySetFilter.getValues().size();
invalidFlagSetCount = bySetFilter.getInvalidValueCount();
invalidFlagSetCount = (splitClientConfig.syncConfig() != null) ?
splitClientConfig.syncConfig().getInvalidValueCount() : 0;
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/test/java/io/split/android/client/SyncConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,16 @@ public void addingNullFilterToConfig() {
Assert.assertTrue(exceptionThrown);
Assert.assertNull(config);
}

@Test
public void invalidValuesAreTracked() {
// Currently only invalid values for {@link SplitFilter#BY_SET} are tracked, for telemetry

SyncConfig config = SyncConfig.builder()
.addSplitFilter(SplitFilter.bySet(Arrays.asList("_f1", "f2", "f3")))
.addSplitFilter(SplitFilter.bySet(Arrays.asList("f4", "_f5", "_f6", "_f6")))
.build();

Assert.assertEquals(4, config.getInvalidValueCount());
}
}

0 comments on commit 776e30b

Please sign in to comment.