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 @@ -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,
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ internal class OperationRepo(
internal val queue = mutableListOf<OperationQueueItem>()
private val waiter = WaiterWithValue<LoopWaiterMessage>()
private val retryWaiter = WaiterWithValue<LoopWaiterMessage>()
private var paused = false
private val initialized = CompletableDeferred<Unit>()

override suspend fun awaitInitialized() {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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")

Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<IUserBackendService>()
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(404, "NOT FOUND")
Expand All @@ -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<IUserBackendService>()
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } throws BackendException(400, "INVALID")

val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()

val mockIdentityModelStore = MockHelper.identityModelStore()
val mockPropertiesModelStore = MockHelper.propertiesModelStore()
val mockSubscriptionsModelStore = mockk<SubscriptionModelStore>()

val loginUserOperationExecutor =
LoginUserOperationExecutor(mockIdentityOperationExecutor, AndroidMockHelper.applicationService(), MockHelper.deviceService(), mockUserBackendService, mockIdentityModelStore, mockPropertiesModelStore, mockSubscriptionsModelStore, MockHelper.configModelStore(), MockHelper.languageContext())
val operations =
listOf<Operation>(
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()) }
}

Expand Down
Loading