diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt index 4bae59896..9b9b92c3e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationExecutor.kt @@ -79,8 +79,8 @@ enum class ExecutionResult { /** * Used in special create user case. - * The operation failed due to a non-retryable error. Pause the operation repo - * and retry on a new session, giving the SDK a chance to recover from the failed user create. + * The operation failed due to invalid arguments (eg. restricted external ID is used.) + * We should not retry the operation as the external ID should not be used again. */ - FAIL_PAUSE_OPREPO, + FAIL_INVALID_LOGIN, } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt index 4439b688e..0bab39318 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt @@ -57,7 +57,6 @@ internal class OperationRepo( internal val queue = mutableListOf() private val waiter = WaiterWithValue() private val retryWaiter = WaiterWithValue() - private var paused = false private val initialized = CompletableDeferred() override suspend fun awaitInitialized() { @@ -101,7 +100,6 @@ internal class OperationRepo( } override fun start() { - paused = false scope.launch { // load saved operations first then start processing the queue to ensure correct operation order loadSavedOperations() @@ -182,11 +180,6 @@ internal class OperationRepo( waitForNewOperationAndExecutionInterval() enqueueIntoBucket++ while (true) { - if (paused) { - Logging.debug("OperationRepo is paused") - return - } - val ops = getNextOps(executeBucket) Logging.debug("processQueueForever:ops:\n$ops") @@ -270,6 +263,7 @@ internal class OperationRepo( } ExecutionResult.FAIL_UNAUTHORIZED, // TODO: Need to provide callback for app to reset JWT. For now, fail with no retry. ExecutionResult.FAIL_NORETRY, + ExecutionResult.FAIL_INVALID_LOGIN, ExecutionResult.FAIL_CONFLICT, -> { Logging.error("Operation execution failed without retry: $operations") @@ -298,15 +292,6 @@ internal class OperationRepo( } } } - ExecutionResult.FAIL_PAUSE_OPREPO -> { - Logging.error("Operation execution failed with eventual retry, pausing the operation repo: $operations") - // keep the failed operation and pause the operation repo from executing - paused = true - // add back all operations to the front of the queue to be re-executed. - synchronized(queue) { - ops.reversed().forEach { queue.add(0, it) } - } - } } // if there are operations provided on the result, we need to enqueue them at the diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt index 46968b3e7..d86bb540f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/operations/impl/executors/LoginUserOperationExecutor.kt @@ -134,6 +134,8 @@ internal class LoginUserOperationExecutor( ) createUser(loginUserOp, operations) } + // For all other errors, the request will be dropped and will not create the user + // e.g. ExecutionResult.FAIL_INVALID_LOGIN else -> ExecutionResponse(result.result) } } @@ -238,7 +240,7 @@ internal class LoginUserOperationExecutor( NetworkUtils.ResponseStatusType.UNAUTHORIZED -> ExecutionResponse(ExecutionResult.FAIL_UNAUTHORIZED, retryAfterSeconds = ex.retryAfterSeconds) else -> - ExecutionResponse(ExecutionResult.FAIL_PAUSE_OPREPO) + ExecutionResponse(ExecutionResult.FAIL_INVALID_LOGIN) } } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt index d80dc5531..9b1352ce3 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt @@ -136,7 +136,7 @@ class LoginUserOperationExecutorTests : FunSpec({ coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } } - test("login anonymous user fails with no retry when backend error condition exists") { + test("login anonymous user fails with no retry when hit with backend error 404") { // Given val mockUserBackendService = mockk() coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(404, "NOT FOUND") @@ -159,7 +159,34 @@ class LoginUserOperationExecutorTests : FunSpec({ val response = loginUserOperationExecutor.execute(operations) // Then - response.result shouldBe ExecutionResult.FAIL_PAUSE_OPREPO + response.result shouldBe ExecutionResult.FAIL_INVALID_LOGIN + coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } + } + + test("login anonymous user fails with LOGIN_INVALID when hit with backend error 400") { + // Given + val mockUserBackendService = mockk() + coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(400, "INVALID") + + val mockIdentityOperationExecutor = mockk() + + val mockIdentityModelStore = MockHelper.identityModelStore() + val mockPropertiesModelStore = MockHelper.propertiesModelStore() + val mockSubscriptionsModelStore = mockk() + + val loginUserOperationExecutor = + LoginUserOperationExecutor(mockIdentityOperationExecutor, AndroidMockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext()) + val operations = + listOf( + LoginUserOperation(appId, localOneSignalId, null, null), + createSubscriptionOperation, + ) + + // When + val response = loginUserOperationExecutor.execute(operations) + + // Then + response.result shouldBe ExecutionResult.FAIL_INVALID_LOGIN coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) } }