diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiAuthTests.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiAuthTests.java index 12d1b473b..ebc879508 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiAuthTests.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiAuthTests.java @@ -67,7 +67,7 @@ private void reInitIterableApi() { authHandler = mock(IterableAuthHandler.class); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testRefreshToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -95,7 +95,7 @@ public void testRefreshToken() throws Exception { timer = IterableApi.getInstance().getAuthManager().timer; } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetEmailWithToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -119,7 +119,7 @@ public void testSetEmailWithToken() throws Exception { shadowOf(getMainLooper()).runToEndOfTasks(); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetEmailWithTokenExpired() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -133,7 +133,7 @@ public void testSetEmailWithTokenExpired() throws Exception { assertEquals(IterableApi.getInstance().getAuthToken(), expiredJWT); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetUserIdWithToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -157,7 +157,7 @@ public void testSetUserIdWithToken() throws Exception { assertEquals(expiredJWT, IterableApi.getInstance().getAuthToken()); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSameEmailWithNewToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -181,7 +181,7 @@ public void testSameEmailWithNewToken() throws Exception { assertEquals(IterableApi.getInstance().getAuthToken(), newJWT); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSameUserIdWithNewToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -200,7 +200,7 @@ public void testSameUserIdWithNewToken() throws Exception { assertEquals(IterableApi.getInstance().getAuthToken(), newJWT); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetSameEmailAndRemoveToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -219,7 +219,7 @@ public void testSetSameEmailAndRemoveToken() throws Exception { assertNull(IterableApi.getInstance().getAuthToken()); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetSameUserIdAndRemoveToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -277,7 +277,7 @@ public void testSetSameUserId() throws Exception { assertNull(IterableApi.getInstance().getAuthToken()); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetSameEmailWithSameToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -297,7 +297,7 @@ public void testSetSameEmailWithSameToken() throws Exception { assertEquals(IterableApi.getInstance().getAuthToken(), token); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testSetSameUserIdWithSameToken() throws Exception { IterableApi.initialize(getContext(), "apiKey"); @@ -352,7 +352,7 @@ public void testUserIdLogOut() throws Exception { assertNull(IterableApi.getInstance().getAuthToken()); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthTokenPresentInRequest() throws Exception { // server.enqueue(new MockResponse().setResponseCode(200).setBody("{}")); @@ -392,7 +392,7 @@ public void testAuthTokenPresentInRequest() throws Exception { assertEquals(HEADER_SDK_AUTH_FORMAT + newJWT, getMessagesSet2Request.getHeader("Authorization")); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthFailureReturns401() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); @@ -418,7 +418,7 @@ public void testAuthFailureReturns401() throws InterruptedException { assertEquals(IterableApi.getInstance().getAuthToken(), expiredJWT); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthRequestedOnSetEmail() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); @@ -433,7 +433,7 @@ public void testAuthRequestedOnSetEmail() throws InterruptedException { } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthRequestedOnUpdateEmail() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); @@ -447,7 +447,7 @@ public void testAuthRequestedOnUpdateEmail() throws InterruptedException { //TODO: Shouldn't the update call also update the authToken in IterableAPI class? } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthRequestedOnSetUserId() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); @@ -456,7 +456,7 @@ public void testAuthRequestedOnSetUserId() throws InterruptedException { assertEquals(IterableApi.getInstance().getAuthToken(), expiredJWT); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testAuthSetToNullOnLogOut() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); @@ -469,7 +469,7 @@ public void testAuthSetToNullOnLogOut() throws InterruptedException { assertNull(IterableApi.getInstance().getAuthToken()); } - @Ignore ("Ignoring the JWT Tests") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testRegisterForPushInvokedAfterTokenRefresh() throws InterruptedException { doReturn(expiredJWT).when(authHandler).onAuthTokenRequested(); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiMergeUserEmailTests.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiMergeUserEmailTests.java index 8c37c6bdf..fba70269f 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiMergeUserEmailTests.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiMergeUserEmailTests.java @@ -181,6 +181,21 @@ private void addResponse(String endPoint) { dispatcher.enqueueResponse("/" + endPoint, new MockResponse().setResponseCode(200).setBody("{}")); } + /** + * Takes the next request matching the expected endpoint, skipping any spurious + * in-app sync requests caused by cross-test state leakage. + */ + private RecordedRequest takeRequestWithPath(String expectedEndpoint) throws InterruptedException { + String expectedPath = "/" + expectedEndpoint; + RecordedRequest request; + do { + request = server.takeRequest(1, TimeUnit.SECONDS); + if (request == null) return null; + } while (request.getPath().startsWith("/" + IterableConstants.ENDPOINT_GET_INAPP_MESSAGES) + && !expectedPath.startsWith("/" + IterableConstants.ENDPOINT_GET_INAPP_MESSAGES)); + return request; + } + // all userId tests @Test public void testCriteriaNotMetUserIdDefault() throws Exception { @@ -844,18 +859,18 @@ public void testCriteriaMetEmailMergeTrue() throws Exception { triggerTrackPurchaseEvent("test", "keyboard", 4.67, 3); shadowOf(getMainLooper()).idle(); - // check if request was sent to unknown user session endpoint - RecordedRequest unknownSessionRequest = server.takeRequest(1, TimeUnit.SECONDS); + // check if request was sent to unknown user session endpoint (skip any spurious in-app syncs) + RecordedRequest unknownSessionRequest = takeRequestWithPath(IterableConstants.ENDPOINT_TRACK_UNKNOWN_SESSION); assertNotNull("Unknown user session request should not be null", unknownSessionRequest); assertEquals("/" + IterableConstants.ENDPOINT_TRACK_UNKNOWN_SESSION, unknownSessionRequest.getPath()); // check if request was sent to track purchase endpoint - RecordedRequest purchaseRequest = server.takeRequest(1, TimeUnit.SECONDS); + RecordedRequest purchaseRequest = takeRequestWithPath(IterableConstants.ENDPOINT_TRACK_PURCHASE); assertNotNull("Purchase request should not be null", purchaseRequest); assertEquals("/" + IterableConstants.ENDPOINT_TRACK_PURCHASE, purchaseRequest.getPath()); // check if request was sent to getInAppMessages endpoint (triggered by completeUserLogin) - RecordedRequest inAppRequest = server.takeRequest(1, TimeUnit.SECONDS); + RecordedRequest inAppRequest = takeRequestWithPath(IterableConstants.ENDPOINT_GET_INAPP_MESSAGES); assertNotNull("InApp messages request should be sent", inAppRequest); assertTrue("InApp messages request path should start with correct endpoint", inAppRequest.getPath().startsWith("/" + IterableConstants.ENDPOINT_GET_INAPP_MESSAGES)); @@ -872,7 +887,7 @@ public void testCriteriaMetEmailMergeTrue() throws Exception { IterableApi.getInstance().setEmail(email, identityResolution); // check if request was sent to merge endpoint - RecordedRequest mergeRequest = server.takeRequest(1, TimeUnit.SECONDS); + RecordedRequest mergeRequest = takeRequestWithPath(IterableConstants.ENDPOINT_MERGE_USER); assertNotNull(mergeRequest); assertEquals("/" + IterableConstants.ENDPOINT_MERGE_USER, mergeRequest.getPath()); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiRequestTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiRequestTest.java index bb781b9ad..166f1bcbb 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiRequestTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiRequestTest.java @@ -225,7 +225,7 @@ public void testPostRequestHeaders() throws Exception { Assert.assertEquals("fake_key", request.getHeader(IterableConstants.HEADER_API_KEY)); } - @Ignore("Ignoring the JWT related test error") + @Ignore("Blocked: IterableAuthManager.executor is not injectable - auth token requests run on uncontrollable background thread") @Test public void testUpdateEmailRequest() throws Exception { server.enqueue(new MockResponse().setResponseCode(200).setBody("{}")); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java index 8d873993a..e0a2da2c7 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java @@ -238,7 +238,7 @@ public void testUpdateEmailWithUserId() throws Exception { assertEquals("testUserId", IterableApi.getInstance().getUserId()); } - @Ignore + @Ignore("handleAppLink performs real HTTP redirect - needs MockWebServer to stub the redirect endpoint") @Test public void testHandleUniversalLinkRewrite() throws Exception { IterableUrlHandler urlHandlerMock = mock(IterableUrlHandler.class); @@ -262,6 +262,8 @@ public void testHandleUniversalLinkRewrite() throws Exception { @Test public void testSetEmailWithAutomaticPushRegistration() throws Exception { IterableApi.initialize(getContext(), "fake_key", new IterableConfig.Builder().setPushIntegrationName("pushIntegration").setAutoPushRegistration(true).build()); + // Reset after initialize since it may trigger push registration via background init + Mockito.reset(IterablePushRegistration.instance); // Check that setEmail calls registerForPush IterableApi.getInstance().setEmail("test@email.com"); @@ -290,6 +292,8 @@ public void testSetEmailWithoutAutomaticPushRegistration() throws Exception { @Test public void testSetUserIdWithAutomaticPushRegistration() throws Exception { IterableApi.initialize(getContext(), "fake_key", new IterableConfig.Builder().setPushIntegrationName("pushIntegration").setAutoPushRegistration(true).build()); + // Reset after initialize since it may trigger push registration via background init + Mockito.reset(IterablePushRegistration.instance); // Check that setUserId calls registerForPush IterableApi.getInstance().setUserId("userId"); @@ -423,7 +427,7 @@ public void testInAppResetOnLogout() throws Exception { verify(IterableApi.sharedInstance.getInAppManager(), times(2)).reset(); } - @Ignore("Ignoring this test as it fails on CI for some reason") + @Ignore("Fails on CI: likely IterableTaskStorage singleton state leakage between tests - needs investigation") @Test public void databaseClearOnLogout() throws Exception { IterableTaskStorage taskStorage = IterableTaskStorage.sharedInstance(getContext()); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerSyncTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerSyncTest.java index 3dd8a191c..6d03f73cf 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerSyncTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerSyncTest.java @@ -77,6 +77,8 @@ public void testSyncOnLogin() throws Exception { IterableInAppManager inAppManagerMock = mock(IterableInAppManager.class); IterableApi.sharedInstance = new IterableApi(inAppManagerMock); IterableApi.initialize(getApplicationContext(), "apiKey"); + // Reset after initialize since it may also trigger syncInApp via background init + reset(inAppManagerMock); IterableApi.getInstance().setEmail("test@email.com"); verify(inAppManagerMock).syncInApp(); } diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerTest.java index 7dcabe729..2a5902978 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerTest.java @@ -27,6 +27,7 @@ import org.robolectric.shadows.ShadowDialog; import java.io.IOException; +import java.util.concurrent.TimeUnit; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -44,7 +45,6 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.robolectric.Shadows.shadowOf; @@ -61,7 +61,7 @@ public class IterableInAppManagerTest extends BaseTest { private PausedExecutorService backgroundExecutor; @Before - public void setUp() throws IOException { + public void setUp() throws Exception { backgroundExecutor = new PausedExecutorService(); server = new MockWebServer(); dispatcher = new PathBasedQueueDispatcher(); @@ -81,6 +81,10 @@ public IterableConfig.Builder run(IterableConfig.Builder builder) { .setUrlHandler(urlHandler); } }); + // Drain init sync HTTP requests from MockWebServer (constructor sync + setEmail sync) + // and flush their callbacks, so they don't consume responses enqueued by tests + while (server.takeRequest(200, TimeUnit.MILLISECONDS) != null) { } + shadowOf(getMainLooper()).idle(); IterableInAppFragmentHTMLNotification.notification = null; } @@ -90,7 +94,7 @@ public void tearDown() throws IOException { server = null; } - @Ignore("Ignoring due to stalling") + @Ignore("Stalls under Robolectric: showIterableFragmentNotificationHTML requires real Activity lifecycle - candidate for androidTest with Espresso") @Test public void testDoNotShowMultipleTimes() throws Exception { ActivityController controller = Robolectric.buildActivity(FragmentActivity.class).create().start().resume(); @@ -104,7 +108,7 @@ public void testDoNotShowMultipleTimes() throws Exception { controller.pause().stop().destroy(); } - @Ignore("Ignoring due to stalling") + @Ignore("Stalls under Robolectric: showIterableFragmentNotificationHTML requires real Activity lifecycle - candidate for androidTest with Espresso") @Test public void testIfDialogDoesNotDestroysAfterConfigurationChange() throws Exception { ActivityController controller = Robolectric.buildActivity(FragmentActivity.class).create().start().resume(); @@ -118,7 +122,7 @@ public void testIfDialogDoesNotDestroysAfterConfigurationChange() throws Excepti controller.pause().stop().destroy(); } - @Ignore("Ignoring due to stalling") + @Ignore("Stalls under Robolectric: showIterableFragmentNotificationHTML requires real Activity lifecycle - candidate for androidTest with Espresso") @Test public void testIfDialogFragmentExistAfterRotation() throws Exception { ActivityController controller = Robolectric.buildActivity(FragmentActivity.class).create().start().resume(); @@ -234,6 +238,7 @@ public void testListenerCalledOnMainThread() throws Exception { JSONObject payload = new JSONObject(IterableTestUtils.getResourceString("inapp_payload_single.json")); dispatcher.enqueueResponse("/inApp/getMessages", new MockResponse().setBody(payload.toString())); final IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager(); + inAppManager.syncInApp(); shadowOf(getMainLooper()).idle(); IterableInAppManager.Listener listener = mock(IterableInAppManager.Listener.class); @@ -256,7 +261,7 @@ public void run() { backgroundExecutor.runAll(); shadowOf(getMainLooper()).idle(); - verify(listener, timeout(100)).onInboxUpdated(); + verify(listener).onInboxUpdated(); } @Test @@ -278,9 +283,12 @@ public IterableConfig.Builder run(IterableConfig.Builder builder) { }); doReturn(true).when(urlHandler).handleIterableURL(any(Uri.class), any(IterableActionContext.class)); + // Flush init sync callbacks so messages are loaded before foreground transition + shadowOf(getMainLooper()).idle(); + // Bring the app into foreground to trigger in-app display Robolectric.buildActivity(Activity.class).create().start().resume(); - Robolectric.flushForegroundThreadScheduler(); + shadowOf(getMainLooper()).idle(); ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass(IterableHelper.IterableUrlCallback.class); verify(inAppDisplayerMock).showMessage(any(IterableInAppMessage.class), eq(IterableInAppLocation.IN_APP), callbackCaptor.capture()); IterableInAppMessage message = inAppManager.getMessages().get(0); @@ -342,9 +350,12 @@ public IterableConfig.Builder run(IterableConfig.Builder builder) { }); doReturn(true).when(urlHandler).handleIterableURL(any(Uri.class), any(IterableActionContext.class)); + // Flush init sync callbacks so messages are loaded before foreground transition + shadowOf(getMainLooper()).idle(); + // Bring the app into foreground Robolectric.buildActivity(Activity.class).create().start().resume(); - Robolectric.flushForegroundThreadScheduler(); + shadowOf(getMainLooper()).idle(); IterableInAppMessage message = inAppManager.getMessages().get(0); // Verify that message is not consumed by default if consume = false and iterable://dismiss is clicked @@ -379,7 +390,7 @@ public void testInAppAutoDisplayPause() throws Exception { inAppManager.setAutoDisplayPaused(true); ActivityController activityController = Robolectric.buildActivity(Activity.class).create().start().resume(); - Robolectric.flushForegroundThreadScheduler(); + shadowOf(getMainLooper()).idle(); ArgumentCaptor inAppMessageCaptor = ArgumentCaptor.forClass(IterableInAppMessage.class); verify(inAppHandler, times(0)).onNewInApp(inAppMessageCaptor.capture()); @@ -389,6 +400,7 @@ public void testInAppAutoDisplayPause() throws Exception { @Test public void testMessagePersistentReadStateFromServer() throws Exception { + // load the in-app that has not been synchronized with the server yet (read state is set to false) dispatcher.enqueueResponse("/inApp/getMessages", new MockResponse().setBody(IterableTestUtils.getResourceString("inapp_payload_inbox_read_state_1.json"))); IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager(); @@ -591,8 +603,7 @@ public void testJsonOnlyInAppMessageDelegateCallbacks() throws Exception { mock(IterableInAppDisplayer.class))); IterableApi.sharedInstance = new IterableApi(inAppManager); - // First sync to get messages - inAppManager.syncInApp(); + // Flush constructor sync callback so messages are loaded shadowOf(getMainLooper()).idle(); // Process messages by bringing app to foreground diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableNotificationTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableNotificationTest.java index a66d6002d..817547693 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableNotificationTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableNotificationTest.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.InputStreamReader; +import static android.os.Looper.getMainLooper; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -50,11 +51,11 @@ private Context getContext() { return getApplicationContext(); } - private IterableNotificationBuilder postNotification(Bundle notificationData) throws InterruptedException { + private IterableNotificationBuilder postNotification(Bundle notificationData) { getContext().getApplicationInfo().icon = android.R.drawable.sym_def_app_icon; IterableNotificationBuilder iterableNotification = IterableNotificationHelper.createNotification(getContext(), notificationData); IterableNotificationHelper.postNotificationOnDevice(appContext, iterableNotification); - Thread.sleep(1000); + shadowOf(getMainLooper()).idle(); return iterableNotification; } diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushActionReceiverTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushActionReceiverTest.java index b738cf69a..02f914164 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushActionReceiverTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushActionReceiverTest.java @@ -90,9 +90,13 @@ public void testTrackPushOpenWithCustomAction() throws Exception { assertNotNull(activityIntent); assertEquals(Intent.ACTION_MAIN, activityIntent.getAction()); - // Verify trackPushOpen HTTP request - RecordedRequest recordedRequest = server.takeRequest(1, TimeUnit.SECONDS); - assertEquals("/" + IterableConstants.ENDPOINT_TRACK_PUSH_OPEN, recordedRequest.getPath()); + // Verify trackPushOpen HTTP request (skip any in-app sync requests from cross-test state) + String expectedPath = "/" + IterableConstants.ENDPOINT_TRACK_PUSH_OPEN; + RecordedRequest recordedRequest; + do { + recordedRequest = server.takeRequest(1, TimeUnit.SECONDS); + assertNotNull("Expected trackPushOpen request but no more requests arrived", recordedRequest); + } while (!recordedRequest.getPath().startsWith(expectedPath)); JSONObject jsonBody = new JSONObject(recordedRequest.getBody().readUtf8()); assertEquals(1234, jsonBody.getInt(IterableConstants.KEY_CAMPAIGN_ID)); assertEquals(4321, jsonBody.getInt(IterableConstants.KEY_TEMPLATE_ID)); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushRegistrationTaskTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushRegistrationTaskTest.java index 214b667ae..194ca8546 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushRegistrationTaskTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterablePushRegistrationTaskTest.java @@ -19,7 +19,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -73,7 +72,8 @@ public void testEnableDevice() throws Exception { new IterablePushRegistrationTask().execute(data); deviceAttributes.put(DEVICE_ATTRIBUTES_KEY, DEVICE_ATTRIBUTES_VALUE); - verify(apiMock, timeout(100)).registerDeviceToken(eq(IterableTestUtils.userEmail), nullable(String.class), isNull(), eq(INTEGRATION_NAME), eq(TEST_TOKEN), eq(deviceAttributes)); + shadowOf(getMainLooper()).idle(); + verify(apiMock).registerDeviceToken(eq(IterableTestUtils.userEmail), nullable(String.class), isNull(), eq(INTEGRATION_NAME), eq(TEST_TOKEN), eq(deviceAttributes)); verify(apiMock, never()).disableToken(eq(IterableTestUtils.userEmail), nullable(String.class), nullable(String.class), any(String.class), nullable(IterableHelper.SuccessHandler.class), nullable(IterableHelper.FailureHandler.class)); } @@ -87,6 +87,6 @@ public void testDisableDevice() throws Exception { new IterablePushRegistrationTask().execute(data); shadowOf(getMainLooper()).idle(); - verify(apiMock, timeout(100)).disableToken(eq(IterableTestUtils.userEmail), isNull(), isNull(), eq(TEST_TOKEN), nullable(IterableHelper.SuccessHandler.class), nullable(IterableHelper.FailureHandler.class)); + verify(apiMock).disableToken(eq(IterableTestUtils.userEmail), isNull(), isNull(), eq(TEST_TOKEN), nullable(IterableHelper.SuccessHandler.class), nullable(IterableHelper.FailureHandler.class)); } } \ No newline at end of file diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CombinationComplexCriteriaCheckerTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/CombinationComplexCriteriaCheckerTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CombinationComplexCriteriaCheckerTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/CombinationComplexCriteriaCheckerTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CombinationLogicEventTypeCriteriaTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/CombinationLogicEventTypeCriteriaTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CombinationLogicEventTypeCriteriaTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/CombinationLogicEventTypeCriteriaTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/ComplexCriteriaCheckerTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/ComplexCriteriaCheckerTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/ComplexCriteriaCheckerTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/ComplexCriteriaCheckerTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CriteriaCompletionCheckerTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/CriteriaCompletionCheckerTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CriteriaCompletionCheckerTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/CriteriaCompletionCheckerTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CriteriaCompletionComparatorTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/CriteriaCompletionComparatorTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/CriteriaCompletionComparatorTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/CriteriaCompletionComparatorTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DataTypeComparatorArrayInputCriteriaTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/DataTypeComparatorArrayInputCriteriaTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DataTypeComparatorArrayInputCriteriaTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/DataTypeComparatorArrayInputCriteriaTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DataTypeComparatorSearchQueryCriteriaTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/DataTypeComparatorSearchQueryCriteriaTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DataTypeComparatorSearchQueryCriteriaTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/DataTypeComparatorSearchQueryCriteriaTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DoesNotEqualCriteriaMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/DoesNotEqualCriteriaMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/DoesNotEqualCriteriaMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/DoesNotEqualCriteriaMatchTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/IsOneOfAndIsNotOneOfCriteriaMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/IsOneOfAndIsNotOneOfCriteriaMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/IsOneOfAndIsNotOneOfCriteriaMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/IsOneOfAndIsNotOneOfCriteriaMatchTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaMatchTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaWithArrayMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaWithArrayMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaWithArrayMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/MultiLevelNestedCriteriaWithArrayMatchTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/NestedCriteriaMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/NestedCriteriaMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/NestedCriteriaMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/NestedCriteriaMatchTest.java diff --git a/iterableapi/src/androidTest/java/com/iterable/iterableapi/util/SinglePrimitiveArrayNestedCriteriaMatchTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/util/SinglePrimitiveArrayNestedCriteriaMatchTest.java similarity index 100% rename from iterableapi/src/androidTest/java/com/iterable/iterableapi/util/SinglePrimitiveArrayNestedCriteriaMatchTest.java rename to iterableapi/src/test/java/com/iterable/iterableapi/util/SinglePrimitiveArrayNestedCriteriaMatchTest.java