@@ -368,6 +368,123 @@ class DataStoreConsecutiveUpdatesTests: SyncEngineIntegrationTestBase {
368
368
wait ( for: [ apiQuerySuccess] , timeout: networkTimeout)
369
369
}
370
370
371
+ /// - Given: API has been setup with `Post` model registered
372
+ /// - When: A Post is saved with sync complete, then it is updated 10 times
373
+ /// - Then: The Post should be updated with new fields
374
+ func testSaveThenMultipleUpdate( ) throws {
375
+ try startAmplifyAndWaitForSync ( )
376
+
377
+ let newPost = Post ( title: " MyPost " ,
378
+ content: " This is my post. " ,
379
+ createdAt: . now( ) ,
380
+ rating: 3 ,
381
+ status: . published)
382
+ var updatedPost = newPost
383
+ let updatedPostDefaultTitle = " MyUpdatedPost "
384
+ let updateCount = 10
385
+
386
+ let saveSyncReceived = expectation ( description: " Received create mutation event on subscription for Post " )
387
+ let updateSyncReceived = expectation ( description: " Received update mutation event on subscription for Post " )
388
+
389
+ let hubListener = Amplify . Hub. listen (
390
+ to: . dataStore,
391
+ eventName: HubPayload . EventName. DataStore. syncReceived) { payload in
392
+ guard let mutationEvent = payload. data as? MutationEvent else {
393
+ XCTFail ( " Can't cast payload as mutation event " )
394
+ return
395
+ }
396
+
397
+ guard let post = try ? mutationEvent. decodeModel ( ) as? Post , post. id == newPost. id else {
398
+ return
399
+ }
400
+
401
+ if mutationEvent. mutationType == GraphQLMutationType . create. rawValue {
402
+ XCTAssertEqual ( post, newPost)
403
+ XCTAssertEqual ( mutationEvent. version, 1 )
404
+ saveSyncReceived. fulfill ( )
405
+ return
406
+ }
407
+
408
+ if mutationEvent. mutationType == GraphQLMutationType . update. rawValue {
409
+ if post. title == updatedPostDefaultTitle + String( updateCount) {
410
+ updateSyncReceived. fulfill ( )
411
+ return
412
+ }
413
+ }
414
+
415
+ }
416
+
417
+ guard try HubListenerTestUtilities . waitForListener ( with: hubListener, timeout: 5.0 ) else {
418
+ XCTFail ( " Listener not registered for hub " )
419
+ return
420
+ }
421
+
422
+ let saveCompleted = expectation ( description: " Save is completed " )
423
+ Amplify . DataStore. save ( newPost) { result in
424
+ switch result {
425
+ case . success:
426
+ saveCompleted. fulfill ( )
427
+ case . failure( let error) :
428
+ XCTFail ( " Error: \( error) " )
429
+ }
430
+ }
431
+ wait ( for: [ saveCompleted, saveSyncReceived] , timeout: networkTimeout)
432
+
433
+ for index in 1 ... updateCount {
434
+ updatedPost. title = updatedPostDefaultTitle + String( index)
435
+ let saveExpectation = expectation ( description: " Save \( index) is successful " )
436
+ Amplify . DataStore. save ( updatedPost) { result in
437
+ switch result {
438
+ case . success:
439
+ saveExpectation. fulfill ( )
440
+ case . failure( let error) :
441
+ XCTFail ( " Error: \( error) " )
442
+ }
443
+ }
444
+ wait ( for: [ saveExpectation] , timeout: networkTimeout)
445
+ }
446
+
447
+ wait ( for: [ updateSyncReceived] , timeout: networkTimeout)
448
+
449
+ // query the updated post in eventual consistent state
450
+ guard let queryResultAfterSync = queryPost ( byId: updatedPost. id) else {
451
+ XCTFail ( " Post should be available after update and sync " )
452
+ return
453
+ }
454
+
455
+ XCTAssertEqual ( queryResultAfterSync, updatedPost)
456
+
457
+ let queryRequest =
458
+ GraphQLRequest< MutationSyncResult?> . query( modelName: updatedPost. modelName, byId: updatedPost. id)
459
+ let apiQuerySuccess = expectation ( description: " API query is successful " )
460
+ Amplify . API. query ( request: queryRequest) { result in
461
+ switch result {
462
+ case . success( let mutationSyncResult) :
463
+ switch mutationSyncResult {
464
+ case . success( let data) :
465
+ guard let post = data else {
466
+ XCTFail ( " Failed to get data " )
467
+ return
468
+ }
469
+
470
+ XCTAssertEqual ( post. model [ " title " ] as? String , updatedPost. title)
471
+ XCTAssertEqual ( post. model [ " content " ] as? String , updatedPost. content)
472
+ XCTAssertEqual ( post. model [ " rating " ] as? Double , updatedPost. rating)
473
+ // version can be anything between 3 to 11 depending on how many
474
+ // pending mutations are overwritten in pending mutation queue
475
+ // while the first update mutation is being processed
476
+ XCTAssertTrue ( post. syncMetadata. version >= 3 && post. syncMetadata. version <= 11 )
477
+ apiQuerySuccess. fulfill ( )
478
+ case . failure( let error) :
479
+ XCTFail ( " Error: \( error) " )
480
+ }
481
+ case . failure( let error) :
482
+ XCTFail ( " Error: \( error) " )
483
+ }
484
+ }
485
+ wait ( for: [ apiQuerySuccess] , timeout: networkTimeout)
486
+ }
487
+
371
488
private func queryPost( byId id: String ) -> Post ? {
372
489
let queryExpectation = expectation ( description: " Query is successful " )
373
490
var queryResult : Post ?
0 commit comments