@@ -175,6 +175,44 @@ final class OneSignalUserTests: XCTestCase {
175175 XCTAssertTrue ( client. allRequestsHandled)
176176 }
177177
178+ /**
179+ This test aims to ensure concurrency safety in the Property Executor.
180+ It is possible for two threads to modify and cache queues concurrently.
181+ */
182+ func testPropertyExecutorConcurrency( ) throws {
183+ /* Setup */
184+ let client = MockOneSignalClient ( )
185+ // Ensure all requests fire the executor's callback so it will modify queues and cache it
186+ client. fireSuccessForAllRequests = true
187+ OneSignalCoreImpl . setSharedClient ( client)
188+
189+ let identityModel = OSIdentityModel ( aliases: [ OS_ONESIGNAL_ID: UUID ( ) . uuidString] , changeNotifier: OSEventProducer ( ) )
190+ OneSignalUserManagerImpl . sharedInstance. addIdentityModelToRepo ( identityModel)
191+
192+ let executor = OSPropertyOperationExecutor ( )
193+ OSOperationRepo . sharedInstance. addExecutor ( executor)
194+
195+ /* When */
196+
197+ DispatchQueue . concurrentPerform ( iterations: 50 ) { _ in
198+ // 1. Enqueue Deltas to the Operation Repo
199+ OSOperationRepo . sharedInstance. enqueueDelta ( OSDelta ( name: OS_UPDATE_PROPERTIES_DELTA, identityModelId: identityModel. modelId, model: OSPropertiesModel ( changeNotifier: OSEventProducer ( ) ) , property: " language " , value: UUID ( ) . uuidString) )
200+ OSOperationRepo . sharedInstance. enqueueDelta ( OSDelta ( name: OS_UPDATE_PROPERTIES_DELTA, identityModelId: identityModel. modelId, model: OSPropertiesModel ( changeNotifier: OSEventProducer ( ) ) , property: " language " , value: UUID ( ) . uuidString) )
201+
202+ // 2. Flush Operation Repo
203+ OSOperationRepo . sharedInstance. addFlushDeltaQueueToDispatchQueue ( )
204+
205+ // 3. Simulate updating the executor's request queue from a network response
206+ executor. executeUpdatePropertiesRequest ( OSRequestUpdateProperties ( params: [ " properties " : [ " language " : UUID ( ) . uuidString] , " refresh_device_metadata " : false ] , identityModel: identityModel) , inBackground: false )
207+ }
208+
209+ // 4. Run background threads
210+ OneSignalCoreMocks . waitForBackgroundThreads ( seconds: 0.5 )
211+
212+ /* Then */
213+ // No crash
214+ }
215+
178216 /**
179217 This test aims to ensure concurrency safety in the User Executor.
180218 It is possible for two threads to modify and cache queues concurrently.
0 commit comments