From 1ac51c5ee70c4e5cec0fe5b1e8deaa648f5da46b Mon Sep 17 00:00:00 2001 From: jinliu9508 Date: Tue, 2 Dec 2025 14:30:21 -0500 Subject: [PATCH 1/2] chores: tests: replace or remove thread.sleep or delay in tests --- .../common/threading/CompletionAwaiterTests.kt | 6 ------ .../internal/application/ApplicationServiceTests.kt | 9 +++++---- .../core/internal/startup/StartupServiceTests.kt | 2 +- .../outcomes/OutcomeEventsControllerTests.kt | 12 ++++++++---- .../migrations/RecoverFromDroppedLoginBugTests.kt | 8 ++++++-- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/common/threading/CompletionAwaiterTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/common/threading/CompletionAwaiterTests.kt index 37f239ead3..ba11a11535 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/common/threading/CompletionAwaiterTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/common/threading/CompletionAwaiterTests.kt @@ -115,9 +115,6 @@ class CompletionAwaiterTests : FunSpec({ jobs.add(thread) } - // Wait a bit to ensure all threads are waiting - Thread.sleep(100) - // Complete the awaiter awaiter.complete() @@ -257,9 +254,6 @@ class CompletionAwaiterTests : FunSpec({ } blockingThreads.forEach { it.start() } - // Wait a bit to ensure all are waiting - Thread.sleep(100) - // Complete the awaiter awaiter.complete() diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt index 81f0df9825..648e91b125 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt @@ -9,16 +9,19 @@ import com.onesignal.common.threading.suspendifyOnIO import com.onesignal.core.internal.application.impl.ApplicationService import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.IOMockHelper +import com.onesignal.mocks.IOMockHelper.awaitIO import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.mockk.spyk import io.mockk.verify -import kotlinx.coroutines.delay import org.robolectric.Robolectric @RobolectricTest class ApplicationServiceTests : FunSpec({ + listener(IOMockHelper) + beforeAny { Logging.logLevel = LogLevel.NONE } @@ -199,7 +202,7 @@ class ApplicationServiceTests : FunSpec({ waiter.wake(response) } - delay(7000) + awaitIO(7_000) applicationService.onActivityStarted(activity) val response = waiter.waitForWake() @@ -224,8 +227,6 @@ class ApplicationServiceTests : FunSpec({ waiter.wake(response) } - delay(3000) - applicationService.onActivityStarted(activity) val response = waiter.waitForWake() diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt index 93fa9e6b11..937c449aec 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/startup/StartupServiceTests.kt @@ -90,9 +90,9 @@ class StartupServiceTests : FunSpec({ // When startupService.scheduleStart() + awaitIO() // Then - Thread.sleep(10) verify(exactly = 1) { mockStartupService1.start() } verify(exactly = 1) { mockStartupService2.start() } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt index b4559464ac..5784902152 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/outcomes/OutcomeEventsControllerTests.kt @@ -4,6 +4,8 @@ import com.onesignal.common.exceptions.BackendException import com.onesignal.common.threading.Waiter import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.IOMockHelper +import com.onesignal.mocks.IOMockHelper.awaitIO import com.onesignal.mocks.MockHelper import com.onesignal.session.internal.influence.IInfluenceManager import com.onesignal.session.internal.influence.Influence @@ -32,10 +34,12 @@ import io.mockk.just import io.mockk.mockk import io.mockk.runs import io.mockk.spyk -import kotlinx.coroutines.delay import org.json.JSONArray class OutcomeEventsControllerTests : FunSpec({ + + listener(IOMockHelper) + beforeAny { Logging.logLevel = LogLevel.NONE } @@ -595,7 +599,7 @@ class OutcomeEventsControllerTests : FunSpec({ // When outcomeEventsController.start() - delay(1000) + awaitIO() // Then coVerify(exactly = 1) { @@ -687,7 +691,7 @@ class OutcomeEventsControllerTests : FunSpec({ // When outcomeEventsController.start() - delay(1000) + awaitIO() // Then coVerify(exactly = 1) { @@ -763,7 +767,7 @@ class OutcomeEventsControllerTests : FunSpec({ // When outcomeEventsController.start() - delay(1000) + awaitIO() // Then coVerify(exactly = 1) { diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/migrations/RecoverFromDroppedLoginBugTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/migrations/RecoverFromDroppedLoginBugTests.kt index 554c09ac96..9112db3bab 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/migrations/RecoverFromDroppedLoginBugTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/migrations/RecoverFromDroppedLoginBugTests.kt @@ -5,6 +5,8 @@ import com.onesignal.core.internal.operations.impl.OperationRepo import com.onesignal.core.internal.time.impl.Time import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging +import com.onesignal.mocks.IOMockHelper +import com.onesignal.mocks.IOMockHelper.awaitIO import com.onesignal.mocks.MockHelper import com.onesignal.user.internal.operations.ExecutorMocks import com.onesignal.user.internal.operations.LoginUserOperation @@ -16,7 +18,6 @@ import io.mockk.mockk import io.mockk.runs import io.mockk.spyk import io.mockk.verify -import kotlinx.coroutines.delay import kotlinx.coroutines.withTimeout private class Mocks { @@ -76,6 +77,9 @@ private class Mocks { } class RecoverFromDroppedLoginBugTests : FunSpec({ + + listener(IOMockHelper) + beforeAny { Logging.logLevel = LogLevel.NONE } @@ -100,7 +104,7 @@ class RecoverFromDroppedLoginBugTests : FunSpec({ // When mocks.operationRepo.start() // give operation repo some time to fully initialize - delay(200) + awaitIO() mocks.recovery.start() withTimeout(1_000) { mocks.operationRepo.awaitInitialized() } From 71ee9c07e60f9d483c6ab38859f281c410d0ea3b Mon Sep 17 00:00:00 2001 From: jinliu9508 Date: Tue, 2 Dec 2025 16:12:07 -0500 Subject: [PATCH 2/2] tests: fix flaky tests --- .../NotificationGenerationProcessorTests.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt index 154b879a11..8172d6cc4d 100644 --- a/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt +++ b/OneSignalSDK/onesignal/notifications/src/test/java/com/onesignal/notifications/internal/generation/NotificationGenerationProcessorTests.kt @@ -5,6 +5,8 @@ import com.onesignal.common.threading.suspendifyOnIO import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging import com.onesignal.mocks.AndroidMockHelper +import com.onesignal.mocks.IOMockHelper +import com.onesignal.mocks.IOMockHelper.awaitIO import com.onesignal.mocks.MockHelper import com.onesignal.notifications.INotificationReceivedEvent import com.onesignal.notifications.INotificationWillDisplayEvent @@ -96,6 +98,9 @@ private class Mocks { } class NotificationGenerationProcessorTests : FunSpec({ + + listener(IOMockHelper) + beforeAny { Logging.logLevel = LogLevel.NONE @@ -276,16 +281,17 @@ class NotificationGenerationProcessorTests : FunSpec({ coEvery { mocks.notificationLifecycleService.externalNotificationWillShowInForeground(any()) } coAnswers { val willDisplayEvent = firstArg() willDisplayEvent.preventDefault(false) + // Call preventDefault(true) synchronously to wake the waiter before it times out + willDisplayEvent.preventDefault(true) + // Then call display() asynchronously to ensure it happens after waitForWake completes suspendifyOnIO { - delay(100) - willDisplayEvent.preventDefault(true) - delay(100) willDisplayEvent.notification.display() } } // When mocks.notificationGenerationProcessor.processNotificationData(mocks.context, 1, mocks.notificationPayload, false, 1111) + awaitIO() // Then coVerify(exactly = 0) { @@ -301,15 +307,14 @@ class NotificationGenerationProcessorTests : FunSpec({ val receivedEvent = firstArg() receivedEvent.preventDefault(false) suspendifyOnIO { - delay(100) receivedEvent.preventDefault(true) - delay(100) receivedEvent.notification.display() } } // When mocks.notificationGenerationProcessor.processNotificationData(mocks.context, 1, mocks.notificationPayload, true, 1111) + awaitIO() // Then coVerify(exactly = 0) {