Skip to content

Commit

Permalink
Merge pull request #2076 from OneSignal/fix/op-repo-loadSavedOperatio…
Browse files Browse the repository at this point in the history
…ns-dup-bug

Follow Up to PR #2068: ensure internalEnqueue can't add the same operation
  • Loading branch information
jkasten2 authored May 7, 2024
2 parents 18a388c + 6e9b690 commit eb284ef
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ internal class OperationRepo(
)

private val executorsMap: Map<String, IOperationExecutor>
private val queue = mutableListOf<OperationQueueItem>()
internal val queue = mutableListOf<OperationQueueItem>()
private val waiter = WaiterWithValue<LoopWaiterMessage>()
private var paused = false
private var coroutineScope = CoroutineScope(newSingleThreadContext(name = "OpRepo"))
Expand Down Expand Up @@ -143,6 +143,12 @@ internal class OperationRepo(
addToStore: Boolean,
index: Int? = null,
) {
val hasExisting = queue.any { it.operation.id == queueItem.operation.id }
if (hasExisting) {
Logging.debug("OperationRepo: internalEnqueue - operation.id: ${queueItem.operation.id} already exists in the queue.")
return
}

synchronized(queue) {
if (index != null) {
queue.add(index, queueItem)
Expand Down Expand Up @@ -402,7 +408,7 @@ internal class OperationRepo(
* NOTE: Sometimes the loading might take longer than expected due to I/O reads from disk
* Any I/O implies executing time will vary greatly.
*/
private fun loadSavedOperations() {
internal fun loadSavedOperations() {
_operationModelStore.loadOperations()
for (operation in _operationModelStore.list().withIndex()) {
internalEnqueue(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,24 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.coroutines.yield
import java.util.UUID

// Mocks used by every test in this file
private class Mocks {
val configModelStore = MockHelper.configModelStore()

val operationModelStore: OperationModelStore =
run {
val operationStoreList = mutableListOf<Operation>()
val mockOperationModelStore = mockk<OperationModelStore>()
every { mockOperationModelStore.loadOperations() } just runs
every { mockOperationModelStore.list() } returns listOf()
every { mockOperationModelStore.add(any()) } just runs
every { mockOperationModelStore.remove(any()) } just runs
every { mockOperationModelStore.list() } returns operationStoreList
every { mockOperationModelStore.add(any()) } answers { operationStoreList.add(firstArg<Operation>()) }
every { mockOperationModelStore.remove(any()) } answers {
val id = firstArg<String>()
val op = operationStoreList.firstOrNull { it.id == id }
operationStoreList.remove(op)
}
mockOperationModelStore
}

Expand Down Expand Up @@ -117,9 +123,9 @@ class OperationRepoTests : FunSpec({
test("enqueue operation executes and is removed when executed") {
// Given
val mocks = Mocks()

val operationIdSlot = slot<String>()
val operation = mockOperation(operationIdSlot = operationIdSlot)
val opId = operation.id

// When
mocks.operationRepo.start()
Expand All @@ -136,7 +142,7 @@ class OperationRepoTests : FunSpec({
it[0] shouldBe operation
},
)
mocks.operationModelStore.remove("operationId")
mocks.operationModelStore.remove(opId)
}
}

Expand All @@ -151,6 +157,7 @@ class OperationRepoTests : FunSpec({

val operationIdSlot = slot<String>()
val operation = mockOperation(operationIdSlot = operationIdSlot)
val opId = operation.id

// When
opRepo.start()
Expand All @@ -174,7 +181,7 @@ class OperationRepoTests : FunSpec({
it[0] shouldBe operation
},
)
mocks.operationModelStore.remove("operationId")
mocks.operationModelStore.remove(opId)
}
}

Expand Down Expand Up @@ -210,6 +217,7 @@ class OperationRepoTests : FunSpec({

val operationIdSlot = slot<String>()
val operation = mockOperation(operationIdSlot = operationIdSlot)
val opId = operation.id

// When
mocks.operationRepo.start()
Expand All @@ -226,7 +234,7 @@ class OperationRepoTests : FunSpec({
it[0] shouldBe operation
},
)
mocks.operationModelStore.remove("operationId")
mocks.operationModelStore.remove(opId)
}
}

Expand Down Expand Up @@ -608,10 +616,24 @@ class OperationRepoTests : FunSpec({
spyListener.onOperationRepoLoaded()
}
}

test("ensure loadSavedOperations doesn't duplicate existing OperationItems") {
// Given
val mocks = Mocks()
val op = mockOperation()
mocks.operationRepo.enqueue(op)

// When
mocks.operationRepo.loadSavedOperations()

// Then
mocks.operationRepo.queue.size shouldBe 1
mocks.operationRepo.queue.first().operation shouldBe op
}
}) {
companion object {
private fun mockOperation(
id: String = "operationId",
id: String = UUID.randomUUID().toString(),
name: String = "DUMMY_OPERATION",
canStartExecute: Boolean = true,
groupComparisonType: GroupComparisonType = GroupComparisonType.NONE,
Expand Down

0 comments on commit eb284ef

Please sign in to comment.