Skip to content
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
@@ -0,0 +1,19 @@
package android.os;

// This file exists only to support the unit tests in src/test/java. The issue is that the SDK
// code uses android.os.Process, which only exists in the Android runtime library; but the unit
// tests (as opposed to the instrumented tests in src/androidTest/java) run against the regular
// Java runtime library. Without this class the mockable android.jar is used instead, and every
// method on it throws "Method ... not mocked".
//
// StreamingDataSource.stop() lowers the priority of its shutdown thread before closing the
// EventSource. With the mockable android.jar that call throws, the shutdown thread dies before
// closing anything, and stop() silently becomes a no-op in unit tests. Thread priority has no
// meaningful equivalent off-device, so the stub just does nothing and lets shutdown proceed.

public class Process {
public static final int THREAD_PRIORITY_BACKGROUND = 10;

public static void setThreadPriority(int priority) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@
import com.launchdarkly.testhelpers.httptest.HttpServer;
import com.launchdarkly.testhelpers.httptest.RequestInfo;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
Expand All @@ -35,6 +38,7 @@ public class StreamingDataSourceTest {
private static final LDContext CONTEXT = LDContext.create("context-key");
private static final String MOBILE_KEY = "test-mobile-key";
private static final String VALID_PUT_JSON = "{\"flag1\":{\"key\":\"flag1\",\"version\":1,\"value\":true}}";
private static final long STOP_TIMEOUT_MILLIS = 5000;

@Rule
public Timeout globalTimeout = Timeout.seconds(10);
Expand All @@ -45,13 +49,33 @@ public class StreamingDataSourceTest {
private final MockPlatformState platformState = new MockPlatformState();
private final IEnvironmentReporter environmentReporter = new EnvironmentReporterBuilder().build();
private final SimpleTestTaskExecutor taskExecutor = new SimpleTestTaskExecutor();
private final List<DataSource> startedDataSources = new ArrayList<>();
private PersistentDataStoreWrapper.PerEnvironmentData perEnvironmentData;

@Before
public void before() {
perEnvironmentData = TestUtil.makeSimplePersistentDataStoreWrapper().perEnvironmentData(MOBILE_KEY);
}

@After
public void stopDataSources() throws Exception {
for (DataSource dataSource : startedDataSources) {
AwaitableCallback<Void> stopped = new AwaitableCallback<>();
dataSource.stop(stopped);
stopped.await(STOP_TIMEOUT_MILLIS);
}
startedDataSources.clear();
}

// Each started data source owns an EventSource with its own threads and an open connection to
// the test server, so anything we start has to be stopped again in stopDataSources().
private void startDataSource(StreamingDataSource dataSource, Callback<Boolean> callback) {
if (!startedDataSources.contains(dataSource)) {
startedDataSources.add(dataSource);
}
dataSource.start(callback);
}

private ClientContext makeClientContext(boolean inBackground, Boolean previouslyInBackground) {
ClientContext baseClientContext = ClientContextImpl.fromConfig(
new LDConfig.Builder(AutoEnvAttributes.Disabled).build(), "", "", perEnvironmentData, null, CONTEXT,
Expand Down Expand Up @@ -492,7 +516,7 @@ public void startSendsRequestWithBase64ContextInPath() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());

Expand All @@ -516,7 +540,7 @@ public void startSendsRequestWithoutContextWhenUsingReport() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, true);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());

Expand All @@ -543,7 +567,7 @@ public void startSendsRequestWithReasonsWhenEnabled() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), true, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());

Expand All @@ -565,7 +589,7 @@ public void startSendsRequestWithoutReasonsWhenDisabled() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());

Expand All @@ -587,7 +611,7 @@ public void startSendsRequestWithReportAndReasons() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), true, true);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());

Expand All @@ -609,7 +633,7 @@ public void startWithHttp401ShutsDownSink() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand All @@ -633,7 +657,7 @@ public void startWithHttp403ReportsNonRetriableWithoutShutDown() throws Exceptio
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand All @@ -651,7 +675,7 @@ public void startWithHttp500ReportsRetriableError() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand Down Expand Up @@ -683,7 +707,7 @@ private void assertStatusReportsRetriableError(int status) throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand All @@ -709,7 +733,7 @@ public void startWithHttp429ReconnectsAndReceivesStreamData() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand All @@ -728,7 +752,7 @@ public void startWithNetworkErrorReportsNetworkFailure() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
URI.create("http://localhost:1"), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Throwable error = callback.awaitError();
assertNotNull(error);
Expand All @@ -744,13 +768,13 @@ public void startWithHttp401PreventsSubsequentStart() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback1 = new TrackingCallback();
sds.start(callback1);
startDataSource(sds, callback1);

assertNotNull(callback1.awaitError());

// Second start should be a no-op due to connection401Error flag
TrackingCallback callback2 = new TrackingCallback();
sds.start(callback2);
startDataSource(sds, callback2);

assertNull("Second start should not produce a callback",
callback2.errors.poll(500, TimeUnit.MILLISECONDS));
Expand All @@ -772,7 +796,7 @@ public void startReceivesPutEventAndInitsSink() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

Boolean success = callback.awaitSuccess();
assertNotNull(success);
Expand All @@ -798,7 +822,7 @@ public void startReceivesPatchEventAndUpsertsSink() throws Exception {
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());
dataSourceUpdateSink.expectInit();
Expand All @@ -823,7 +847,7 @@ public void startReceivesDeleteEventAndUpsertsDeletedPlaceholder() throws Except
StreamingDataSource sds = makeStreamingDataSource(
server.getUri(), false, false);
TrackingCallback callback = new TrackingCallback();
sds.start(callback);
startDataSource(sds, callback);

assertNotNull(callback.awaitSuccess());
dataSourceUpdateSink.expectInit();
Expand Down
Loading