@@ -60,7 +60,12 @@ void _syncTests<T>({
6060
6161 db.execute ('commit' );
6262 final [row] = result;
63- return jsonDecode (row.columnAt (0 ));
63+ final rawResult = row.columnAt (0 );
64+ if (rawResult is String ) {
65+ return jsonDecode (rawResult);
66+ } else {
67+ return const [];
68+ }
6469 }
6570
6671 Object ? invokeControlScalar (String operation, Object ? data) {
@@ -83,6 +88,10 @@ void _syncTests<T>({
8388 return row.columnAt (0 );
8489 }
8590
91+ int seedCheckpointRequestId (Object ? requestId) {
92+ return invokeControlScalar ('seed_checkpoint_request_id' , requestId) as int ;
93+ }
94+
8695 bool establishesSyncStream (List <Object ?> instructions) {
8796 return instructions.any ((instruction) =>
8897 instruction is Map && instruction.containsKey ('EstablishSyncStream' ));
@@ -98,10 +107,7 @@ void _syncTests<T>({
98107 }
99108
100109 if (operation == 'start' && establishesSyncStream (result)) {
101- final seedResult = matcher.enabled
102- ? matcher.invoke ('seed_checkpoint_request_id' , 1 )
103- : invokeControlRaw ('seed_checkpoint_request_id' , 1 );
104- return [...result, ...seedResult];
110+ seedCheckpointRequestId (1 );
105111 }
106112
107113 return result;
@@ -246,15 +252,12 @@ void _syncTests<T>({
246252 });
247253
248254 syncTest ('app_metadata is passed to EstablishSyncStream request' , (_) {
249- final startInstructions = [
250- ...invokeControlRaw (
251- 'start' ,
252- json.encode ({
253- 'app_metadata' : {'key1' : 'value1' , 'key2' : 'value2' }
254- }),
255- ),
256- ...invokeControlRaw ('seed_checkpoint_request_id' , 1 ),
257- ];
255+ final startInstructions = invokeControlRaw (
256+ 'start' ,
257+ json.encode ({
258+ 'app_metadata' : {'key1' : 'value1' , 'key2' : 'value2' }
259+ }),
260+ );
258261
259262 expect (
260263 startInstructions,
@@ -470,7 +473,7 @@ void _syncTests<T>({
470473 expect (currentCheckpointRequestId (), isNull);
471474
472475 invokeControlRaw ('start' , null );
473- invokeControlRaw ( 'seed_checkpoint_request_id' , 1 );
476+ expect ( seedCheckpointRequestId ( 1 ) , 1 );
474477 expect (currentCheckpointRequestId (), 1 );
475478
476479 expect (currentCheckpointRequestId (), 1 );
@@ -494,7 +497,7 @@ void _syncTests<T>({
494497 syncTest ('seeds requested checkpoint request ids from service state' , (_) {
495498 final startInstructions = invokeControlRaw ('start' , null );
496499 expect (streamLastCheckpointRequestId (startInstructions), isNull);
497- invokeControlRaw ( 'seed_checkpoint_request_id' , 41 );
500+ expect ( seedCheckpointRequestId ( 41 ) , 41 );
498501
499502 expect (nextCheckpointRequestId (), 42 );
500503 expect (lastRequestedCheckpointRequestId (), 42 );
@@ -505,21 +508,21 @@ void _syncTests<T>({
505508 contains (containsPair ('EstablishSyncStream' , anything)),
506509 );
507510 expect (streamLastCheckpointRequestId (restartInstructions), 42 );
508- expect (invokeControlRaw ( 'seed_checkpoint_request_id' , 100 ), isEmpty );
511+ expect (seedCheckpointRequestId ( 100 ), 100 );
509512
510513 expect (nextCheckpointRequestId (), 101 );
511514 expect (lastRequestedCheckpointRequestId (), 101 );
512515 });
513516
514517 syncTest ('stores seeded checkpoint request ids verbatim' , (_) {
515518 invokeControlRaw ('start' , null );
516- invokeControlRaw ( 'seed_checkpoint_request_id' , 41 );
519+ expect ( seedCheckpointRequestId ( 41 ) , 41 );
517520 expect (lastRequestedCheckpointRequestId (), 41 );
518521
519522 // Core does not enforce monotonicity when seeding. SDKs own reconciliation and seed the
520523 // effective state accepted by the service, which may be below the local counter (e.g. after
521524 // switching users).
522- invokeControlRaw ( 'seed_checkpoint_request_id' , 5 );
525+ expect ( seedCheckpointRequestId ( 5 ) , 5 );
523526 expect (lastRequestedCheckpointRequestId (), 5 );
524527 expect (nextCheckpointRequestId (), 6 );
525528 });
@@ -552,12 +555,23 @@ void _syncTests<T>({
552555
553556 syncTest ('accepts text checkpoint request ids when seeding' , (_) {
554557 invokeControlRaw ('start' , null );
555- invokeControlRaw ( 'seed_checkpoint_request_id' , '41' );
558+ expect ( seedCheckpointRequestId ( '41' ), 41 );
556559
557560 expect (lastRequestedCheckpointRequestId (), 41 );
558561 expect (nextCheckpointRequestId (), 42 );
559562 });
560563
564+ syncTest ('requires active sync iteration before seeding checkpoint ids' , (_) {
565+ expect (
566+ () => seedCheckpointRequestId (1 ),
567+ throwsA (isSqliteException (
568+ 21 ,
569+ contains ('No iteration is active' ),
570+ )),
571+ );
572+ expect (lastRequestedCheckpointRequestId (), isNull);
573+ });
574+
561575 syncTest ('requires checkpoint request state before allocating checkpoint ids' ,
562576 (_) {
563577 invokeControlRaw ('start' , null );
@@ -572,7 +586,9 @@ void _syncTests<T>({
572586 expect (probeTargetCheckpointRequestId (), isNull);
573587 });
574588
575- syncTest ('probes and updates target checkpoint request id without sync iteration' , (_) {
589+ syncTest (
590+ 'probes and updates target checkpoint request id without sync iteration' ,
591+ (_) {
576592 expect (probeTargetCheckpointRequestId (), isNull);
577593 expect (probeTargetCheckpointRequestId (1 ), isNull);
578594 expect (lastRequestedCheckpointRequestId (), isNull);
@@ -583,7 +599,9 @@ void _syncTests<T>({
583599 expect (probeTargetCheckpointRequestId (), 2 );
584600 });
585601
586- syncTest ('accepts text checkpoint request ids for target checkpoint request id' , (_) {
602+ syncTest (
603+ 'accepts text checkpoint request ids for target checkpoint request id' ,
604+ (_) {
587605 expect (probeTargetCheckpointRequestId ('1' ), isNull);
588606 expect (lastRequestedCheckpointRequestId (), isNull);
589607 expect (probeTargetCheckpointRequestId (), 1 );
@@ -599,9 +617,10 @@ void _syncTests<T>({
599617 );
600618 });
601619
602- syncTest ('target checkpoint request id does not update checkpoint request id' , (_) {
620+ syncTest ('target checkpoint request id does not update checkpoint request id' ,
621+ (_) {
603622 invokeControlRaw ('start' , null );
604- invokeControlRaw ( 'seed_checkpoint_request_id' , 10 );
623+ expect ( seedCheckpointRequestId ( 10 ) , 10 );
605624
606625 expect (lastRequestedCheckpointRequestId (), 10 );
607626 expect (probeTargetCheckpointRequestId (7 ), isNull);
0 commit comments