@@ -265,6 +265,168 @@ final class SessionTests: XCTestCase {
265265 let decryptedText2 = try XCTUnwrap ( String ( data: decrypted2, encoding: . utf8) )
266266 XCTAssertEqual ( plaintext2, decryptedText2)
267267 }
268+
269+ func testThreadSafeSimultaneousDecrypt( ) async throws {
270+ let senderClient = try TestClient ( userId: UUID ( ) ) // Alice
271+ let recipientClient = try TestClient ( userId: UUID ( ) ) // Bob
272+ let recipientAddress = recipientClient. protocolAddress
273+
274+ try initializeSession ( senderClient: senderClient, recipientClient: recipientClient)
275+
276+ // Alice creates a set of messages
277+ let aliceMessageCount = 50
278+ var aliceMessages : [ ( Data , MessageContainer ) ] = [ ]
279+ for index in 0 ..< aliceMessageCount {
280+ var aliceSession = try senderClient. sessionStore. loadSession ( for: recipientAddress)
281+ let data = try XCTUnwrap ( " From Alice \( index) " . data ( using: . utf8) )
282+ let message = try XCTUnwrap (
283+ try aliceSession? . encrypt (
284+ data: data,
285+ for: recipientAddress,
286+ sessionStore: senderClient. sessionStore,
287+ identityStore: senderClient. identityKeyStore)
288+ )
289+ let item = ( data, message)
290+ aliceMessages. append ( item)
291+ }
292+ aliceMessages. shuffle ( )
293+
294+ var tasks = [ Task < ( Data , Data ) , Error > ] ( )
295+ for aliceMessage in aliceMessages {
296+ let task = Task {
297+ let decryptedMessage = try Session . decrypt (
298+ message: aliceMessage. 1 ,
299+ from: senderClient. protocolAddress,
300+ sessionStore: recipientClient. sessionStore,
301+ identityStore: recipientClient. identityKeyStore,
302+ preKeyStore: recipientClient. preKeyStore,
303+ signedPreKeyStore: recipientClient. signedPreKeyStore)
304+ let expectedMessage = aliceMessage. 0
305+ return ( decryptedMessage, expectedMessage)
306+ }
307+ tasks. append ( task)
308+ }
309+
310+ var results = [ ( decrypted: Data, expected: Data) ] ( )
311+ for task in tasks {
312+ let result = try await task. value
313+ results. append ( result)
314+ }
315+
316+ for result in results {
317+ XCTAssertEqual ( result. decrypted, result. expected)
318+ }
319+ }
320+
321+ func testThreadSafeSimultaneousEncrypt( ) async throws {
322+ let senderClient = try TestClient ( userId: UUID ( ) ) // Alice
323+ let recipientClient = try TestClient ( userId: UUID ( ) ) // Bob
324+ let recipientAddress = recipientClient. protocolAddress
325+
326+ try initializeSession ( senderClient: senderClient, recipientClient: recipientClient)
327+
328+ // Actually test for Thread Safe begins here
329+
330+ let plaintext = " Do not despair when your enemy attacks you. "
331+ let data = try XCTUnwrap ( plaintext. data ( using: . utf8) )
332+ let task1 = Task {
333+ var session = try XCTUnwrap ( try senderClient. sessionStore. loadSession ( for: recipientAddress) )
334+ return try session. encrypt (
335+ data: data,
336+ for: recipientClient. protocolAddress,
337+ sessionStore: senderClient. sessionStore,
338+ identityStore: senderClient. identityKeyStore)
339+ }
340+
341+ let task2 = Task {
342+ var session = try XCTUnwrap ( try senderClient. sessionStore. loadSession ( for: recipientAddress) )
343+ return try session. encrypt (
344+ data: data,
345+ for: recipientClient. protocolAddress,
346+ sessionStore: senderClient. sessionStore,
347+ identityStore: senderClient. identityKeyStore)
348+ }
349+
350+ let task3 = Task {
351+ var session = try XCTUnwrap ( try senderClient. sessionStore. loadSession ( for: recipientAddress) )
352+ return try session. encrypt (
353+ data: data,
354+ for: recipientClient. protocolAddress,
355+ sessionStore: senderClient. sessionStore,
356+ identityStore: senderClient. identityKeyStore)
357+ }
358+
359+ let task4 = Task {
360+ var session = try XCTUnwrap ( try senderClient. sessionStore. loadSession ( for: recipientAddress) )
361+ return try session. encrypt (
362+ data: data,
363+ for: recipientClient. protocolAddress,
364+ sessionStore: senderClient. sessionStore,
365+ identityStore: senderClient. identityKeyStore)
366+ }
367+
368+ let task5 = Task {
369+ var session = try XCTUnwrap ( try senderClient. sessionStore. loadSession ( for: recipientAddress) )
370+ return try session. encrypt (
371+ data: data,
372+ for: recipientClient. protocolAddress,
373+ sessionStore: senderClient. sessionStore,
374+ identityStore: senderClient. identityKeyStore)
375+ }
376+
377+ let message1 = try await task1. value
378+ let message2 = try await task2. value
379+ let message3 = try await task3. value
380+ let message4 = try await task4. value
381+ let message5 = try await task5. value
382+
383+ let decryptedMessage1 = try Session . decrypt (
384+ message: message1,
385+ from: senderClient. protocolAddress,
386+ sessionStore: recipientClient. sessionStore,
387+ identityStore: recipientClient. identityKeyStore,
388+ preKeyStore: recipientClient. preKeyStore,
389+ signedPreKeyStore: recipientClient. signedPreKeyStore)
390+
391+ let decryptedMessage2 = try Session . decrypt (
392+ message: message2,
393+ from: senderClient. protocolAddress,
394+ sessionStore: recipientClient. sessionStore,
395+ identityStore: recipientClient. identityKeyStore,
396+ preKeyStore: recipientClient. preKeyStore,
397+ signedPreKeyStore: recipientClient. signedPreKeyStore)
398+
399+ let decryptedMessage3 = try Session . decrypt (
400+ message: message3,
401+ from: senderClient. protocolAddress,
402+ sessionStore: recipientClient. sessionStore,
403+ identityStore: recipientClient. identityKeyStore,
404+ preKeyStore: recipientClient. preKeyStore,
405+ signedPreKeyStore: recipientClient. signedPreKeyStore)
406+
407+ let decryptedMessage4 = try Session . decrypt (
408+ message: message4,
409+ from: senderClient. protocolAddress,
410+ sessionStore: recipientClient. sessionStore,
411+ identityStore: recipientClient. identityKeyStore,
412+ preKeyStore: recipientClient. preKeyStore,
413+ signedPreKeyStore: recipientClient. signedPreKeyStore)
414+
415+ let decryptedMessage5 = try Session . decrypt (
416+ message: message5,
417+ from: senderClient. protocolAddress,
418+ sessionStore: recipientClient. sessionStore,
419+ identityStore: recipientClient. identityKeyStore,
420+ preKeyStore: recipientClient. preKeyStore,
421+ signedPreKeyStore: recipientClient. signedPreKeyStore)
422+
423+ XCTAssertEqual ( decryptedMessage1, data)
424+ XCTAssertEqual ( decryptedMessage2, data)
425+ XCTAssertEqual ( decryptedMessage3, data)
426+ XCTAssertEqual ( decryptedMessage4, data)
427+ XCTAssertEqual ( decryptedMessage5, data)
428+ }
429+
268430 // FIXME: - Need fix
269431 func testOutOfOrder( ) throws {
270432 let senderClient = try TestClient ( userId: UUID ( ) ) // Alice
0 commit comments