Skip to content
Open
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 @@ -59,6 +59,7 @@ public static class SdkConfigEventParams {
boolean enableDiagnostics;
String[] globalPrivateAttributes;
Long flushIntervalMs;
Boolean enableGzip;
}

public static class SdkConfigTagParams {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,9 @@ private LDConfig buildSdkConfig(SdkConfigParams params, LDLogAdapter logAdapter,
if (params.events.globalPrivateAttributes != null) {
eventsBuilder.privateAttributes(params.events.globalPrivateAttributes);
}
if (params.events.enableGzip != null) {
eventsBuilder.enableCompression(params.events.enableGzip);
}
builder.events(eventsBuilder);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class TestService extends NanoHTTPD {
"client-prereq-events",
"client-prereq-cycle-detection",
"polling-gzip",
"event-gzip",
"optional-event-gzip",
"evaluation-hooks",
"track-hooks",
"client-per-context-summaries",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import okio.GzipSource;
import okio.Okio;

public class LDClientEventTest {
// For better test isolation, any tests here that need to inject flag data will use a simple
Expand Down Expand Up @@ -520,12 +522,14 @@ public void testEventDoesNotContainAutoEnvAttributesWhenDisabled() throws Except
}
}

private LDValue[] getEventsFromLastRequest(MockWebServer server, int expectedCount) throws InterruptedException {
private LDValue[] getEventsFromLastRequest(MockWebServer server, int expectedCount) throws IOException, InterruptedException {
RecordedRequest r = server.takeRequest();
assertEquals("POST", r.getMethod());
assertEquals("/mobile/events/bulk", r.getPath());
assertEquals(mobileKey, r.getHeader("Authorization"));
String body = r.getBody().readUtf8();
String body = "gzip".equals(r.getHeader("Content-Encoding"))
? Okio.buffer(new GzipSource(r.getBody())).readUtf8()
: r.getBody().readUtf8();
System.out.println(body);
LDValue[] events = GsonHelpers.gsonInstance().fromJson(body, LDValue[].class);
if (events.length != expectedCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public EventProcessor build(ClientContext clientContext) {
StandardEndpoints.ANALYTICS_EVENTS_REQUEST_PATH,
StandardEndpoints.DIAGNOSTIC_EVENTS_REQUEST_PATH,
0L, // use default retry delay
false, // disable gzip compression for Android
enableCompression,
clientContext.getBaseLogger()),
1, // eventSendingThreadPoolSize
clientContext.getServiceEndpoints().getEventsBaseUri(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public abstract class EventProcessorBuilder implements ComponentConfigurer<Event
*/
protected int diagnosticRecordingIntervalMillis = DEFAULT_DIAGNOSTIC_RECORDING_INTERVAL_MILLIS;

/**
* Whether event payloads are sent gzip-encoded
*/
protected boolean enableCompression = false;

/**
* The flush interval in millis
*/
Expand Down Expand Up @@ -119,6 +124,21 @@ public EventProcessorBuilder diagnosticRecordingIntervalMillis(int diagnosticRec
return this;
}

/**
* Sets whether event payloads sent to LaunchDarkly use gzip compression.
* <p>
* Compression reduces egress bandwidth cost. By default this is {@code false}, because older versions
* of the Relay Proxy do not accept gzip-encoded event payloads; applications not using the Relay Proxy
* are strongly encouraged to set it to {@code true}.
*
* @param enableCompression true to send event payloads gzip-encoded
* @return the builder
*/
public EventProcessorBuilder enableCompression(boolean enableCompression) {
this.enableCompression = enableCompression;
return this;
}

/**
* Sets the interval between flushes of the event buffer.
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.launchdarkly.sdk.android;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import com.launchdarkly.sdk.LDContext;
import com.launchdarkly.sdk.LDValue;
import com.launchdarkly.sdk.android.LDConfig.Builder.AutoEnvAttributes;
import com.launchdarkly.sdk.android.env.EnvironmentReporterBuilder;
import com.launchdarkly.sdk.android.integrations.EventProcessorBuilder;
import com.launchdarkly.sdk.android.subsystems.ClientContext;
import com.launchdarkly.sdk.android.subsystems.EventProcessor;
import com.launchdarkly.testhelpers.httptest.Handlers;
import com.launchdarkly.testhelpers.httptest.HttpServer;
import com.launchdarkly.testhelpers.httptest.RequestInfo;

import org.junit.Rule;
import org.junit.Test;

public class EventCompressionTest {
private static final LDContext CONTEXT = LDContext.create("context-key");
private static final String MOBILE_KEY = "test-mobile-key";
private static final String EVENT_KEY = "compression-test-event";

@Rule
public LogCaptureRule logging = new LogCaptureRule();

@Test
public void eventPayloadsAreSentUncompressedByDefault() throws Exception {
RequestInfo request = sendOneEvent(Components.sendEvents());

assertNull(request.getHeader("Content-Encoding"));
assertTrue("the payload should be sent as plain JSON", request.getBody().contains(EVENT_KEY));
}

@Test
public void eventPayloadsAreGzipEncodedWhenCompressionIsEnabled() throws Exception {
RequestInfo request = sendOneEvent(Components.sendEvents().enableCompression(true));

assertEquals("gzip", request.getHeader("Content-Encoding"));
assertFalse("the payload should not be sent as plain JSON", request.getBody().contains(EVENT_KEY));
}

private RequestInfo sendOneEvent(EventProcessorBuilder eventsBuilder) throws Exception {
try (HttpServer server = HttpServer.start(Handlers.status(202))) {
LDConfig config = new LDConfig.Builder(AutoEnvAttributes.Disabled)
.mobileKey(MOBILE_KEY)
.diagnosticOptOut(true)
.serviceEndpoints(Components.serviceEndpoints().events(server.getUri()))
.build();
ClientContext clientContext = ClientContextImpl.fromConfig(config, MOBILE_KEY, "",
null, null, CONTEXT, logging.logger, new MockPlatformState(),
new EnvironmentReporterBuilder().build(), new SimpleTestTaskExecutor());

try (EventProcessor eventProcessor = eventsBuilder.build(clientContext)) {
eventProcessor.setOffline(false);
eventProcessor.recordCustomEvent(CONTEXT, EVENT_KEY, LDValue.ofNull(), null);
eventProcessor.flush();
return server.getRecorder().requireRequest();
}
}
}
}
Loading