Skip to content
Open
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
Expand Up @@ -263,7 +263,6 @@ internal class OneSignalImp(
suspendifyOnIO {
internalInit(context, appId)
}
initState = InitState.SUCCESS
return true
}

Expand Down Expand Up @@ -306,22 +305,48 @@ internal class OneSignalImp(
) {
Logging.log(LogLevel.DEBUG, "Calling deprecated login(externalId: $externalId, jwtBearerToken: $jwtBearerToken)")

if (!initState.isSDKAccessible()) {
throw IllegalStateException("Must call 'initWithContext' before 'login'")
// Check state and provide appropriate error messages
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can isSDKAccessible() be changed to something like checkSDKAccessible() so that it throws proper error messages based on initState, and do nothing if allow proceeding?

when (initState) {
InitState.FAILED -> {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
InitState.NOT_STARTED -> {
throw IllegalStateException("Must call 'initWithContext' before 'login'")
}
InitState.IN_PROGRESS, InitState.SUCCESS -> {
// Continue - these states allow proceeding (will wait if needed)
}
}

waitForInit()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are essentially checking init state before and after waitForInit(). Should we let waitForInit() handle the throwing/proceeding based on the initState so we don't need to check for the state again in the usage?

// Re-check state after waiting - init might have failed during the wait
if (initState == InitState.FAILED) {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
suspendifyOnIO { loginHelper.login(externalId, jwtBearerToken) }
}

override fun logout() {
Logging.log(LogLevel.DEBUG, "Calling deprecated logout()")

if (!initState.isSDKAccessible()) {
throw IllegalStateException("Must call 'initWithContext' before 'logout'")
// Check state and provide appropriate error messages
when (initState) {
InitState.FAILED -> {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
InitState.NOT_STARTED -> {
throw IllegalStateException("Must call 'initWithContext' before 'logout'")
}
InitState.IN_PROGRESS, InitState.SUCCESS -> {
// Continue - these states allow proceeding (will wait if needed)
}
Comment on lines +332 to +342
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate code, can we make a function for this?

}

waitForInit()
// Re-check state after waiting - init might have failed during the wait
if (initState == InitState.FAILED) {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
suspendifyOnIO { logoutHelper.logout() }
}

Expand Down Expand Up @@ -358,6 +383,10 @@ internal class OneSignalImp(
withTimeout(MAX_TIMEOUT_TO_INIT) {
initAwaiter.awaitSuspend()
}
// Re-check state after waiting - init might have failed during the wait
if (initState == InitState.FAILED) {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
} catch (e: TimeoutCancellationException) {
throw IllegalStateException("initWithContext was timed out after $MAX_TIMEOUT_TO_INIT ms")
}
Expand All @@ -384,13 +413,21 @@ internal class OneSignalImp(
InitState.IN_PROGRESS -> {
Logging.debug("Waiting for init to complete...")
waitForInit()
// Re-check state after waiting - init might have failed during the wait
if (initState == InitState.FAILED) {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
}
InitState.FAILED -> {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
else -> {
// SUCCESS
waitForInit()
// Re-check state after waiting - init might have failed during the wait
if (initState == InitState.FAILED) {
throw IllegalStateException("Initialization failed. Cannot proceed.")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,19 @@ class SDKInitTests : FunSpec({
accessorThread.join(500)

// Then
// should complete even SharedPreferences is unavailable
// should complete even SharedPreferences is unavailable (non-blocking)
accessorThread.isAlive shouldBe false

// Release the SharedPreferences lock so internalInit can complete
trigger.complete()

// Wait for initialization to complete (internalInit runs asynchronously)
var attempts = 0
while (!os.isInitialized && attempts < 50) {
Thread.sleep(20)
attempts++
}

os.isInitialized shouldBe true
}

Expand Down Expand Up @@ -224,12 +235,23 @@ class SDKInitTests : FunSpec({
accessorThread.start()
accessorThread.join(500)

os.isInitialized shouldBe true
// initWithContext should return immediately (non-blocking)
// but isInitialized won't be true until internalInit completes
// which requires SharedPreferences to be unblocked
accessorThread.isAlive shouldBe true

// release the lock on SharedPreferences
// release the lock on SharedPreferences so internalInit can complete
trigger.complete()

// Wait for initialization to complete (internalInit runs asynchronously)
var initAttempts = 0
while (!os.isInitialized && initAttempts < 50) {
Thread.sleep(20)
initAttempts++
}

os.isInitialized shouldBe true

accessorThread.join(500)
accessorThread.isAlive shouldBe false
os.user.externalId shouldBe externalId
Expand Down