@@ -5,11 +5,15 @@ import com.onesignal.common.threading.WaiterWithValue
5
5
import com.onesignal.core.internal.operations.impl.OperationModelStore
6
6
import com.onesignal.core.internal.operations.impl.OperationRepo
7
7
import com.onesignal.core.internal.operations.impl.OperationRepo.OperationQueueItem
8
+ import com.onesignal.core.internal.preferences.PreferenceOneSignalKeys
9
+ import com.onesignal.core.internal.preferences.PreferenceStores
8
10
import com.onesignal.core.internal.time.impl.Time
9
11
import com.onesignal.debug.LogLevel
10
12
import com.onesignal.debug.internal.logging.Logging
11
13
import com.onesignal.mocks.MockHelper
14
+ import com.onesignal.mocks.MockPreferencesService
12
15
import com.onesignal.user.internal.operations.ExecutorMocks.Companion.getNewRecordState
16
+ import com.onesignal.user.internal.operations.LoginUserOperation
13
17
import io.kotest.core.spec.style.FunSpec
14
18
import io.kotest.matchers.shouldBe
15
19
import io.mockk.CapturingSlot
@@ -28,6 +32,7 @@ import kotlinx.coroutines.launch
28
32
import kotlinx.coroutines.withTimeout
29
33
import kotlinx.coroutines.withTimeoutOrNull
30
34
import kotlinx.coroutines.yield
35
+ import org.json.JSONArray
31
36
import java.util.UUID
32
37
33
38
// Mocks used by every test in this file
@@ -76,6 +81,65 @@ class OperationRepoTests : FunSpec({
76
81
Logging .logLevel = LogLevel .NONE
77
82
}
78
83
84
+ test("ensure loading in the background thread does not block enqueue") {
85
+ // Given
86
+ val prefs = MockPreferencesService ()
87
+ val mocks = Mocks ()
88
+ val operationModelStore : OperationModelStore = spyk(OperationModelStore (prefs))
89
+ val operationRepo =
90
+ spyk(
91
+ OperationRepo (
92
+ listOf(mocks.executor),
93
+ operationModelStore,
94
+ mocks.configModelStore,
95
+ Time (),
96
+ getNewRecordState(mocks.configModelStore),
97
+ ),
98
+ )
99
+
100
+ val cachedOperation = LoginUserOperation ()
101
+ val newOperation = LoginUserOperation ()
102
+ val jsonArray = JSONArray ()
103
+
104
+ // cache the operation
105
+ jsonArray.put(cachedOperation.toJSON())
106
+ prefs.saveString(PreferenceStores .ONESIGNAL , PreferenceOneSignalKeys .MODEL_STORE_PREFIX + "operations", jsonArray.toString())
107
+
108
+ cachedOperation.id = UUID .randomUUID().toString()
109
+ newOperation.id = UUID .randomUUID().toString()
110
+ every { operationModelStore.create(any()) } answers {
111
+ // simulate a prolonged loading from cache
112
+ Thread .sleep(1000)
113
+ cachedOperation
114
+ }
115
+
116
+ // simulate a background thread to load operations
117
+ val backgroundThread =
118
+ Thread {
119
+ operationRepo.loadSavedOperations()
120
+ }
121
+
122
+ val mainThread =
123
+ Thread {
124
+ operationRepo.enqueue(newOperation)
125
+ }
126
+
127
+ // When
128
+ backgroundThread.start()
129
+ mainThread.start()
130
+
131
+ // Then
132
+ // insertion from the main thread is done without blocking
133
+ mainThread.join(500)
134
+ operationRepo.queue.size shouldBe 1
135
+ mainThread.state shouldBe Thread .State .TERMINATED
136
+
137
+ // after loading is completed, the cached operation should be at the beginning of the queue
138
+ backgroundThread.join()
139
+ operationRepo.queue.size shouldBe 2
140
+ operationRepo.queue.first().operation shouldBe cachedOperation
141
+ }
142
+
79
143
test("containsInstanceOf") {
80
144
// Given
81
145
val operationRepo = Mocks ().operationRepo
0 commit comments