@@ -121,8 +121,14 @@ void _syncTests<T>({
121
121
}
122
122
123
123
List <Object ?> pushCheckpoint (
124
- {int lastOpId = 1 , List <Object > buckets = const []}) {
125
- return syncLine (checkpoint (lastOpId: lastOpId, buckets: buckets));
124
+ {int lastOpId = 1 ,
125
+ List <Object > buckets = const [],
126
+ String ? writeCheckpoint}) {
127
+ return syncLine (checkpoint (
128
+ lastOpId: lastOpId,
129
+ buckets: buckets,
130
+ writeCheckpoint: writeCheckpoint,
131
+ ));
126
132
}
127
133
128
134
List <Object ?> pushCheckpointComplete ({int ? priority, String lastOpId = '1' }) {
@@ -676,6 +682,123 @@ void _syncTests<T>({
676
682
});
677
683
});
678
684
685
+ group ('applies pending changes' , () {
686
+ test ('write checkpoint before upload complete' , () {
687
+ // local write while offline
688
+ db.execute ("insert into items (id, col) values ('local', 'data');" );
689
+ invokeControl ('start' , null );
690
+
691
+ // Start upload process. Assume data has been uploaded and a write
692
+ // checkpoint has been requested, but not received yet.
693
+ db.execute ('DELETE FROM ps_crud' );
694
+ pushCheckpoint (buckets: priorityBuckets, writeCheckpoint: '1' );
695
+ pushSyncData ('prio1' , '1' , 'row-0' , 'PUT' , {'col' : 'hi' });
696
+ expect (pushCheckpointComplete (), [
697
+ containsPair ('LogLine' , {
698
+ 'severity' : 'INFO' ,
699
+ 'line' : contains ('Will retry at completed upload' )
700
+ })
701
+ ]);
702
+
703
+ // Now complete the upload process.
704
+ db.execute (r"UPDATE ps_buckets SET target_op = 1 WHERE name = '$local'" );
705
+ invokeControl ('completed_upload' , null );
706
+
707
+ // This should apply the pending write checkpoint.
708
+ expect (fetchRows (), [
709
+ {'id' : 'row-0' , 'col' : 'hi' }
710
+ ]);
711
+ });
712
+
713
+ test ('write checkpoint with synced data' , () {
714
+ // local write while offline
715
+ db.execute ("insert into items (id, col) values ('local', 'data');" );
716
+ invokeControl ('start' , null );
717
+
718
+ // Complete upload process
719
+ db.execute ('DELETE FROM ps_crud' );
720
+ db.execute (r"UPDATE ps_buckets SET target_op = 1 WHERE name = '$local'" );
721
+ expect (invokeControl ('completed_upload' , null ), isEmpty);
722
+
723
+ // Sync afterwards containing data and write checkpoint.
724
+ pushCheckpoint (buckets: priorityBuckets, writeCheckpoint: '1' );
725
+ pushSyncData ('prio1' , '1' , 'row-0' , 'PUT' , {'col' : 'hi' });
726
+ pushCheckpointComplete ();
727
+ expect (fetchRows (), [
728
+ {'id' : 'row-0' , 'col' : 'hi' }
729
+ ]);
730
+ });
731
+
732
+ test ('write checkpoint after synced data' , () {
733
+ // local write while offline
734
+ db.execute ("insert into items (id, col) values ('local', 'data');" );
735
+ invokeControl ('start' , null );
736
+
737
+ // Upload changes, assume that triggered a checkpoint.
738
+ db.execute ('DELETE FROM ps_crud' );
739
+ pushCheckpoint (buckets: priorityBuckets);
740
+ pushSyncData ('prio1' , '1' , 'row-0' , 'PUT' , {'col' : 'hi' });
741
+ expect (pushCheckpointComplete (), [
742
+ containsPair ('LogLine' , {
743
+ 'severity' : 'INFO' ,
744
+ 'line' : contains ('Will retry at completed upload' )
745
+ })
746
+ ]);
747
+
748
+ // Now the upload is complete and requests a write checkpoint
749
+ db.execute (r"UPDATE ps_buckets SET target_op = 1 WHERE name = '$local'" );
750
+ expect (invokeControl ('completed_upload' , null ), isEmpty);
751
+
752
+ // Which triggers a new iteration
753
+ pushCheckpoint (buckets: priorityBuckets, writeCheckpoint: '1' );
754
+ expect (
755
+ pushCheckpointComplete (),
756
+ contains (containsPair ('LogLine' , {
757
+ 'severity' : 'DEBUG' ,
758
+ 'line' : contains ('Validated and applied checkpoint' )
759
+ })));
760
+
761
+ expect (fetchRows (), [
762
+ {'id' : 'row-0' , 'col' : 'hi' }
763
+ ]);
764
+ });
765
+
766
+ test ('second local write' , () {
767
+ // first local write while offline
768
+ db.execute ("insert into items (id, col) values ('local', 'data');" );
769
+ invokeControl ('start' , null );
770
+
771
+ // Upload changes, assume that triggered a checkpoint.
772
+ db.execute ('DELETE FROM ps_crud' );
773
+ pushCheckpoint (buckets: priorityBuckets, writeCheckpoint: '1' );
774
+ pushSyncData ('prio1' , '1' , 'row-0' , 'PUT' , {'col' : 'hi' });
775
+ expect (pushCheckpointComplete (), [
776
+ containsPair ('LogLine' , {
777
+ 'severity' : 'INFO' ,
778
+ 'line' : contains ('Will retry at completed upload' )
779
+ })
780
+ ]);
781
+
782
+ // Second local write during sync
783
+ db.execute ("insert into items (id, col) values ('local2', 'data2');" );
784
+
785
+ // Now the upload is complete and requests a write checkpoint
786
+ db.execute (r"UPDATE ps_buckets SET target_op = 1 WHERE name = '$local'" );
787
+ expect (invokeControl ('completed_upload' , null ), [
788
+ containsPair ('LogLine' , {
789
+ 'severity' : 'WARNING' ,
790
+ 'line' :
791
+ 'Could not apply pending checkpoint even after completed upload'
792
+ })
793
+ ]);
794
+
795
+ expect (fetchRows (), [
796
+ {'id' : 'local' , 'col' : 'data' },
797
+ {'id' : 'local2' , 'col' : 'data2' },
798
+ ]);
799
+ });
800
+ });
801
+
679
802
group ('errors' , () {
680
803
syncTest ('diff without prior checkpoint' , (_) {
681
804
invokeControl ('start' , null );
0 commit comments