@@ -9,6 +9,7 @@ import com.onesignal.mocks.MockPreferencesService
9
9
import com.onesignal.user.internal.subscriptions.SubscriptionModel
10
10
import com.onesignal.user.internal.subscriptions.SubscriptionModelStore
11
11
import io.kotest.core.spec.style.FunSpec
12
+ import io.kotest.matchers.shouldBe
12
13
import io.kotest.runner.junit4.KotestTestRunner
13
14
import junit.framework.TestCase
14
15
import org.junit.runner.RunWith
@@ -70,13 +71,11 @@ class ModelingTests : FunSpec({
70
71
val t1 =
71
72
Thread {
72
73
// acquire "ModelStore.models", then trigger the onChanged event
73
- System .out .println("1")
74
74
modelStore.add(newSubscriptionModel)
75
75
}
76
76
77
77
val t2 =
78
78
Thread {
79
- System .out .println("2")
80
79
// acquire "model.data", then wait for "ModelStore.models"
81
80
newSubscriptionModel.toJSON()
82
81
}
@@ -116,4 +115,29 @@ class ModelingTests : FunSpec({
116
115
// verify if the thread has been successfully terminated
117
116
TestCase .assertEquals(Thread .State .TERMINATED , t2.state)
118
117
}
118
+
119
+ test("Unsubscribing handler in change event may cause the concurrent modification exception") {
120
+ // Given an arbitrary model
121
+ val modelStore = MockHelper .configModelStore()
122
+ val model = modelStore.model
123
+
124
+ // subscribe to a change handler
125
+ model.subscribe(
126
+ object : IModelChangedHandler {
127
+ override fun onChanged(
128
+ args: ModelChangedArgs ,
129
+ tag: String ,
130
+ ) {
131
+ // remove from "subscribers" while "subscribers" is being accessed
132
+ model.unsubscribe(this)
133
+ }
134
+ },
135
+ )
136
+
137
+ // this will trigger EventProducer.fire and loop through the list "subscribers"
138
+ model.setOptAnyProperty("key1", "value1")
139
+
140
+ // ensure no concurrent modification exception is thrown and "subcribers" is clear
141
+ model.hasSubscribers shouldBe false
142
+ }
119
143
})
0 commit comments