diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerThreadingTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerThreadingTest.java index 753318ace..fd452a2ff 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerThreadingTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerThreadingTest.java @@ -7,9 +7,6 @@ import static junit.framework.Assert.assertTrue; import static org.robolectric.Shadows.shadowOf; -import android.os.Handler; -import android.os.HandlerThread; - import androidx.activity.ComponentActivity; import org.junit.After; @@ -19,10 +16,6 @@ import org.robolectric.android.controller.ActivityController; import org.robolectric.shadows.ShadowDialog; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - public class IterableInAppManagerThreadingTest extends BaseTest { private ActivityController controller; @@ -51,27 +44,9 @@ public void tearDown() { @Test public void showMessage_fromBackgroundLooperThread_displaysOnMainThreadWithoutCrashing() throws InterruptedException { - // A looper thread, like the React Native native-modules thread. - HandlerThread background = new HandlerThread("background"); - background.start(); - final AtomicReference thrown = new AtomicReference<>(); - final CountDownLatch done = new CountDownLatch(1); - new Handler(background.getLooper()).post(new Runnable() { - @Override - public void run() { - try { - inAppManager.showMessage(message, true, null); - } catch (Throwable t) { - thrown.set(t); - } finally { - done.countDown(); - } - } - }); - assertTrue(done.await(5, TimeUnit.SECONDS)); - background.quitSafely(); + LooperTestUtils.runOnBackgroundLooperAndWait( + () -> inAppManager.showMessage(message, true, null)); - assertNull(thrown.get()); assertNull(IterableInAppDialogNotification.getInstance()); assertFalse(message.isRead()); assertFalse(message.isMarkedForDeletion()); diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/LooperTestUtils.kt b/iterableapi/src/test/java/com/iterable/iterableapi/LooperTestUtils.kt new file mode 100644 index 000000000..f17f045d7 --- /dev/null +++ b/iterableapi/src/test/java/com/iterable/iterableapi/LooperTestUtils.kt @@ -0,0 +1,36 @@ +package com.iterable.iterableapi + +import android.os.Handler +import android.os.HandlerThread +import org.robolectric.Shadows.shadowOf +import java.util.concurrent.atomic.AtomicReference + +object LooperTestUtils { + + /** + * Runs [action] to completion on a background looper. + * Work that [action] posts to the main looper stays queued. + */ + @JvmStatic + @Throws(InterruptedException::class) + fun runOnBackgroundLooperAndWait(action: Runnable) { + val thread = HandlerThread("test-background") + val failure = AtomicReference() + thread.start() + try { + shadowOf(thread.looper).pause() + Handler(thread.looper).post { + try { + action.run() + } catch (error: Throwable) { + failure.set(error) + } + } + shadowOf(thread.looper).idle() + } finally { + thread.quit() + thread.join() + } + failure.get()?.let { throw AssertionError("Background action failed", it) } + } +}