Skip to content
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

Sets telemetry tests #541

Merged
merged 4 commits into from
Sep 14, 2023
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
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());
}
}