Skip to content

Commit

Permalink
add a test unit to simulate the ANR caused by operationRepo.enqueue w…
Browse files Browse the repository at this point in the history
…hile loading is not completed
  • Loading branch information
jinliu9508 committed Dec 10, 2024
1 parent 877246e commit ed34602
Showing 1 changed file with 54 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.onesignal.common.events.EventProducer
import com.onesignal.common.modeling.IModelChangedHandler
import com.onesignal.common.modeling.IModelStoreChangeHandler
import com.onesignal.common.modeling.ModelChangedArgs
import com.onesignal.core.internal.operations.Operation
import com.onesignal.core.internal.operations.impl.OperationModelStore
import com.onesignal.core.internal.preferences.PreferenceOneSignalKeys
import com.onesignal.core.internal.preferences.PreferenceStores
Expand All @@ -15,11 +16,64 @@ import com.onesignal.user.internal.subscriptions.SubscriptionModel
import com.onesignal.user.internal.subscriptions.SubscriptionModelStore
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import org.json.JSONArray
import org.json.JSONObject
import java.util.UUID

class ModelingTests : FunSpec({

test("ensure prolonged loading in the background thread does not block insertion in the main thread") {
// Given
val prefs = MockPreferencesService()
val operationModelStore = OperationModelStore(prefs)
val mockOperationModelStore = mockk<OperationModelStore>()
every { mockOperationModelStore.list() } answers { operationModelStore.list() }
every { mockOperationModelStore.add(any()) } answers { operationModelStore.add(firstArg<Operation>()) }
every { mockOperationModelStore.remove(any()) } answers {
val id = firstArg<String>()
operationModelStore.remove(id)
}
every { mockOperationModelStore.create(any()) } answers {
// force load() to take at least 200 ms to complete
Thread.sleep(200)
operationModelStore.create(firstArg<JSONObject>())
}
every { mockOperationModelStore.loadOperations() } answers {
// TODO: simulate a prolonged loading process while synchronizing operationModelStore.models
}

// add an arbitrary operation to the cache
val cachedOperation = LoginUserFromSubscriptionOperation()
val newOperation = LoginUserOperation()
cachedOperation.id = UUID.randomUUID().toString()
val jsonArray = JSONArray()
jsonArray.put(cachedOperation.toJSON())
prefs.saveString(PreferenceStores.ONESIGNAL, PreferenceOneSignalKeys.MODEL_STORE_PREFIX + "operations", jsonArray.toString())

// simulate a background thread to load operations
val backgroundThread =
Thread {
mockOperationModelStore.loadOperations()
}

val mainThread =
Thread {
mockOperationModelStore.add(newOperation)
}

backgroundThread.start()
mainThread.start()

mainThread.join(100)

// Then
// insertion from the main thread is done without blocking
mockOperationModelStore.list().count() shouldBe 1
mockOperationModelStore.list().first() shouldBe newOperation
}

test("Deadlock related to Model.setOptAnyProperty") {
// Given
val modelStore = MockHelper.configModelStore()
Expand Down

0 comments on commit ed34602

Please sign in to comment.