[SDK-406] Sdk fix flaky tests#1007
Conversation
89f24e2 to
20b97b9
Compare
These tests use @RunWith(JUnit4) with only org.json imports and have no Android framework dependencies. Running them as JVM unit tests removes the emulator requirement and speeds up CI. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace Mockito.timeout() with shadowOf(getMainLooper()).idle() + verify() in IterablePushRegistrationTaskTest and IterableInAppManagerTest - Replace Thread.sleep(1000) with shadowOf(getMainLooper()).idle() in IterableNotificationTest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update 23 @ignore annotations with actionable descriptions: - JWT tests: blocked on IterableAuthManager.executor not being injectable - Universal link test: needs MockWebServer to stub HTTP redirect - Database logout test: IterableTaskStorage singleton state leakage - In-app stalling tests: Robolectric incompatible, need Espresso Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
testSyncOnLogin: initialize() can trigger syncInApp via background init, causing a double call. Reset the mock after initialize so the verify only checks the setEmail-triggered sync. testTrackPushOpenWithCustomAction: cross-test state leakage causes a spurious inApp/getMessages request that arrives at the mock server before trackPushOpen. Skip non-trackPushOpen requests when verifying. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ests Cross-test state leakage causes spurious inApp/getMessages requests to arrive at the mock server before the expected requests. Added a helper takeRequestWithPath() that skips unexpected in-app sync requests when verifying request order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
testSetEmailWithAutomaticPushRegistration / testSetUserIdWithAutomaticPushRegistration: initialize() can trigger executePushRegistrationTask via background init. Reset the mock after initialize so verify only captures the setEmail/setUserId call. testMessagePersistentReadStateFromServer: Flush pending looper callbacks from setUp's createIterableApiNew before the test starts. Stale onPostExecute callbacks can corrupt InlineExecutorService state under CI resource pressure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n delete The createIterableApiNew() call triggers syncInApp() via setEmail(), which consumes the single enqueued MockWebServer response meant for the test. Fix by enqueuing a dummy response for the init-triggered sync, plus flushing the looper before test assertions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
setUp's createIterableApiNew() fires async HTTP requests (InAppManager constructor sync + setEmail sync) on background threads. On CI, these can arrive at MockWebServer after a test enqueues its responses, consuming them. Fix by: 1. Draining all setUp HTTP requests via server.takeRequest() in setUp 2. Flushing their looper callbacks with idle() 3. Adding idle() to testJsonOnlyInAppMessageDelegateCallbacks to flush the constructor sync before foreground transition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The tests raced initializeInBackground() against setEmail/setUserId — if background init completed before the API calls, operations executed immediately instead of being queued, failing the size assertion. Fix: use simulateInitializingState() to hold init in progress, then simulateInitializationComplete() after assertions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- testSetEmailWithAutomaticPushRegistration: flush looper before resetting the mock so background init callbacks don't trigger extra push registration - IterableAsyncInitializationTest: increase all waitForAsyncInitialization timeouts from 3s to 5s for CI reliability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove simulateInitializationComplete() from PII masking tests that only verify queue contents. The call triggers processAll() -> shutdownBackgroundExecutorAsync() which can race with the next test's executor setup, causing testInitializeInBackground_WithConfig to fail. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
shutdownBackgroundExecutorAsync() now captures the executor reference before spawning the shutdown thread, so it only shuts down the intended executor — not a replacement created by resetBackgroundInitializationState(). resetBackgroundInitializationState() now always creates a fresh executor instead of conditionally reusing one that may have a pending async shutdown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
497a8a4 to
86f560a
Compare
sumeruchat
left a comment
There was a problem hiding this comment.
@franco-zalamena-iterable Can you please explain the changes in background executor.
|
The changes on the Background executor were made to prevent the main cause of flakiness on our tests. We were having a synchronized read and write with a lock, so even if it was a different executor it was waiting for the other test to finish to be able to shut it down, meanwhile the other test was doing the same thing. We now have a synchronized read but no need to wait for the other test to be able to shut it down. this prevents the deadlock we were seeing before |
|
The suggested fix is to stop shutdownBackgroundExecutorAsync() from looking up the global backgroundExecutor at shutdown time. Right now it does this in iterableapi/src/main/java/com/iterable/iterableapi/IterableBackgroundInitializer.java:340:
That is the race. If test reset swaps in a new executor before a straggler calls this helper, the helper can shut down the new executor instead of the old The concrete change is:
|
🔹 Jira Ticket(s) if any
✏️ Description
Removing timeouts in some tests that can be causing flakiness. Moved some unit tests that were running as instrumental tests, added better description into ignored tests