@powersync/service-core-tests 0.0.0-dev-20260602073133 → 0.0.0-dev-20260909133214

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +112 -4
  2. package/dist/test-utils/AbstractStreamTestContext.d.ts +7 -6
  3. package/dist/test-utils/AbstractStreamTestContext.js +28 -25
  4. package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
  5. package/dist/test-utils/StorageDataHelpers.d.ts +6 -5
  6. package/dist/test-utils/StorageDataHelpers.js +40 -2
  7. package/dist/test-utils/StorageDataHelpers.js.map +1 -1
  8. package/dist/test-utils/bucket-validation.d.ts +3 -3
  9. package/dist/test-utils/bucket-validation.js +3 -3
  10. package/dist/test-utils/general-utils.d.ts +16 -3
  11. package/dist/test-utils/general-utils.js +37 -4
  12. package/dist/test-utils/general-utils.js.map +1 -1
  13. package/dist/test-utils/storage-combinations.d.ts +13 -0
  14. package/dist/test-utils/storage-combinations.js +26 -0
  15. package/dist/test-utils/storage-combinations.js.map +1 -0
  16. package/dist/test-utils/stream_utils.d.ts +0 -1
  17. package/dist/test-utils/stream_utils.js +0 -10
  18. package/dist/test-utils/stream_utils.js.map +1 -1
  19. package/dist/test-utils/test-utils-index.d.ts +1 -0
  20. package/dist/test-utils/test-utils-index.js +1 -0
  21. package/dist/test-utils/test-utils-index.js.map +1 -1
  22. package/dist/tests/register-compacting-tests.js +36 -29
  23. package/dist/tests/register-compacting-tests.js.map +1 -1
  24. package/dist/tests/register-data-storage-checkpoint-tests.js +138 -14
  25. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  26. package/dist/tests/register-data-storage-data-tests.js +205 -138
  27. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  28. package/dist/tests/register-data-storage-parameter-tests.js +44 -42
  29. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  30. package/dist/tests/register-parameter-compacting-tests.js +3 -2
  31. package/dist/tests/register-parameter-compacting-tests.js.map +1 -1
  32. package/dist/tests/register-sync-tests.js +404 -86
  33. package/dist/tests/register-sync-tests.js.map +1 -1
  34. package/dist/tests/util.d.ts +8 -2
  35. package/dist/tests/util.js +12 -0
  36. package/dist/tests/util.js.map +1 -1
  37. package/package.json +5 -6
  38. package/src/test-utils/AbstractStreamTestContext.ts +31 -27
  39. package/src/test-utils/StorageDataHelpers.ts +52 -8
  40. package/src/test-utils/bucket-validation.ts +3 -3
  41. package/src/test-utils/general-utils.ts +62 -10
  42. package/src/test-utils/storage-combinations.ts +51 -0
  43. package/src/test-utils/stream_utils.ts +0 -11
  44. package/src/test-utils/test-utils-index.ts +1 -0
  45. package/src/tests/register-compacting-tests.ts +55 -32
  46. package/src/tests/register-data-storage-checkpoint-tests.ts +171 -14
  47. package/src/tests/register-data-storage-data-tests.ts +251 -150
  48. package/src/tests/register-data-storage-parameter-tests.ts +58 -42
  49. package/src/tests/register-parameter-compacting-tests.ts +3 -2
  50. package/src/tests/register-sync-tests.ts +443 -88
  51. package/src/tests/util.ts +15 -2
  52. package/tsconfig.json +1 -4
  53. package/tsconfig.tsbuildinfo +1 -1
@@ -38,7 +38,8 @@ export function registerDataStorageDataTests(config: storage.TestStorageConfig)
38
38
 
39
39
  test('removing row', async () => {
40
40
  await using factory = await generateStorageFactory();
41
- const syncRules = await factory.updateSyncRules(
41
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
42
+ factory,
42
43
  updateSyncRulesFromYaml(
43
44
  `
44
45
  bucket_definitions:
@@ -49,7 +50,7 @@ bucket_definitions:
49
50
  { storageVersion }
50
51
  )
51
52
  );
52
- const bucketStorage = factory.getInstance(syncRules);
53
+ const bucketStorage = factory.getInstance(replicationStream);
53
54
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
54
55
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
55
56
 
@@ -71,10 +72,10 @@ bucket_definitions:
71
72
  });
72
73
  await writer.commit('1/1');
73
74
 
74
- const { checkpoint } = await bucketStorage.getCheckpoint();
75
+ const checkpoint = await bucketStorage.getCheckpoint();
75
76
 
76
77
  const request = bucketRequest(syncRules, 'global[]');
77
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
78
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
78
79
  const data = batch[0].chunkData.data.map((d) => {
79
80
  return {
80
81
  op: d.op,
@@ -103,7 +104,8 @@ bucket_definitions:
103
104
 
104
105
  test('insert after delete in new batch', async () => {
105
106
  await using factory = await generateStorageFactory();
106
- const syncRules = await factory.updateSyncRules(
107
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
108
+ factory,
107
109
  updateSyncRulesFromYaml(
108
110
  `
109
111
  bucket_definitions:
@@ -114,7 +116,7 @@ bucket_definitions:
114
116
  { storageVersion }
115
117
  )
116
118
  );
117
- const bucketStorage = factory.getInstance(syncRules);
119
+ const bucketStorage = factory.getInstance(replicationStream);
118
120
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
119
121
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
120
122
  await writer.markAllSnapshotDone('1/1');
@@ -138,10 +140,10 @@ bucket_definitions:
138
140
  });
139
141
  await writer.commit('2/1');
140
142
 
141
- const { checkpoint } = await bucketStorage.getCheckpoint();
143
+ const checkpoint = await bucketStorage.getCheckpoint();
142
144
 
143
145
  const request = bucketRequest(syncRules, 'global[]');
144
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
146
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
145
147
  const data = batch[0].chunkData.data.map((d) => {
146
148
  return {
147
149
  op: d.op,
@@ -167,7 +169,8 @@ bucket_definitions:
167
169
  test('update after delete in new batch', async () => {
168
170
  // Update after delete may not be common, but the storage layer should handle it in an eventually-consistent way.
169
171
  await using factory = await generateStorageFactory();
170
- const syncRules = await factory.updateSyncRules(
172
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
173
+ factory,
171
174
  updateSyncRulesFromYaml(
172
175
  `
173
176
  bucket_definitions:
@@ -178,7 +181,7 @@ bucket_definitions:
178
181
  { storageVersion }
179
182
  )
180
183
  );
181
- const bucketStorage = factory.getInstance(syncRules);
184
+ const bucketStorage = factory.getInstance(replicationStream);
182
185
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
183
186
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
184
187
  await writer.markAllSnapshotDone('1/1');
@@ -206,10 +209,10 @@ bucket_definitions:
206
209
  });
207
210
  await writer.commit('2/1');
208
211
 
209
- const { checkpoint } = await bucketStorage.getCheckpoint();
212
+ const checkpoint = await bucketStorage.getCheckpoint();
210
213
 
211
214
  const request = bucketRequest(syncRules, 'global[]');
212
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
215
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
213
216
  const data = batch[0].chunkData.data.map((d) => {
214
217
  return {
215
218
  op: d.op,
@@ -234,7 +237,8 @@ bucket_definitions:
234
237
 
235
238
  test('insert after delete in same batch', async () => {
236
239
  await using factory = await generateStorageFactory();
237
- const syncRules = await factory.updateSyncRules(
240
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
241
+ factory,
238
242
  updateSyncRulesFromYaml(
239
243
  `
240
244
  bucket_definitions:
@@ -247,7 +251,7 @@ bucket_definitions:
247
251
  }
248
252
  )
249
253
  );
250
- const bucketStorage = factory.getInstance(syncRules);
254
+ const bucketStorage = factory.getInstance(replicationStream);
251
255
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
252
256
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
253
257
  await writer.markAllSnapshotDone('1/1');
@@ -268,10 +272,10 @@ bucket_definitions:
268
272
  });
269
273
  await writer.commit('1/1');
270
274
 
271
- const { checkpoint } = await bucketStorage.getCheckpoint();
275
+ const checkpoint = await bucketStorage.getCheckpoint();
272
276
 
273
277
  const request = bucketRequest(syncRules, 'global[]');
274
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
278
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
275
279
  const data = batch[0].chunkData.data.map((d) => {
276
280
  return {
277
281
  op: d.op,
@@ -296,7 +300,8 @@ bucket_definitions:
296
300
 
297
301
  test('(insert, delete, insert), (delete)', async () => {
298
302
  await using factory = await generateStorageFactory();
299
- const syncRules = await factory.updateSyncRules(
303
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
304
+ factory,
300
305
  updateSyncRulesFromYaml(
301
306
  `
302
307
  bucket_definitions:
@@ -309,7 +314,7 @@ bucket_definitions:
309
314
  }
310
315
  )
311
316
  );
312
- const bucketStorage = factory.getInstance(syncRules);
317
+ const bucketStorage = factory.getInstance(replicationStream);
313
318
  {
314
319
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
315
320
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -354,10 +359,10 @@ bucket_definitions:
354
359
  await writer.commit('2/1');
355
360
  }
356
361
 
357
- const { checkpoint } = await bucketStorage.getCheckpoint();
362
+ const checkpoint = await bucketStorage.getCheckpoint();
358
363
 
359
364
  const request = bucketRequest(syncRules, 'global[]');
360
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
365
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
361
366
 
362
367
  expect(reduceBucket(batch[0].chunkData.data).slice(1)).toEqual([]);
363
368
 
@@ -374,7 +379,8 @@ bucket_definitions:
374
379
 
375
380
  test('changing client ids', async () => {
376
381
  await using factory = await generateStorageFactory();
377
- const syncRules = await factory.updateSyncRules(
382
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
383
+ factory,
378
384
  updateSyncRulesFromYaml(
379
385
  `
380
386
  bucket_definitions:
@@ -387,7 +393,7 @@ bucket_definitions:
387
393
  }
388
394
  )
389
395
  );
390
- const bucketStorage = factory.getInstance(syncRules);
396
+ const bucketStorage = factory.getInstance(replicationStream);
391
397
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
392
398
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
393
399
  await writer.markAllSnapshotDone('1/1');
@@ -424,8 +430,8 @@ bucket_definitions:
424
430
  });
425
431
 
426
432
  await writer.commit('1/1');
427
- const { checkpoint } = await bucketStorage.getCheckpoint();
428
- const batch = await test_utils.fromAsync(
433
+ const checkpoint = await bucketStorage.getCheckpoint();
434
+ const batch = await test_utils.getBatchArray(
429
435
  bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]')])
430
436
  );
431
437
  const data = batch[0].chunkData.data.map((d) => {
@@ -445,7 +451,8 @@ bucket_definitions:
445
451
 
446
452
  test('re-apply delete', async () => {
447
453
  await using factory = await generateStorageFactory();
448
- const syncRules = await factory.updateSyncRules(
454
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
455
+ factory,
449
456
  updateSyncRulesFromYaml(
450
457
  `
451
458
  bucket_definitions:
@@ -458,7 +465,7 @@ bucket_definitions:
458
465
  }
459
466
  )
460
467
  );
461
- const bucketStorage = factory.getInstance(syncRules);
468
+ const bucketStorage = factory.getInstance(replicationStream);
462
469
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
463
470
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
464
471
  await writer.markAllSnapshotDone('1/1');
@@ -489,10 +496,10 @@ bucket_definitions:
489
496
  });
490
497
  await writer.flush();
491
498
 
492
- const { checkpoint } = await bucketStorage.getCheckpoint();
499
+ const checkpoint = await bucketStorage.getCheckpoint();
493
500
 
494
501
  const request = bucketRequest(syncRules, 'global[]');
495
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
502
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
496
503
  const data = batch[0].chunkData.data.map((d) => {
497
504
  return {
498
505
  op: d.op,
@@ -521,7 +528,8 @@ bucket_definitions:
521
528
 
522
529
  test('re-apply update + delete', async () => {
523
530
  await using factory = await generateStorageFactory();
524
- const syncRules = await factory.updateSyncRules(
531
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
532
+ factory,
525
533
  updateSyncRulesFromYaml(
526
534
  `
527
535
  bucket_definitions:
@@ -532,7 +540,7 @@ bucket_definitions:
532
540
  { storageVersion }
533
541
  )
534
542
  );
535
- const bucketStorage = factory.getInstance(syncRules);
543
+ const bucketStorage = factory.getInstance(replicationStream);
536
544
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
537
545
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
538
546
  await writer.markAllSnapshotDone('1/1');
@@ -608,10 +616,10 @@ bucket_definitions:
608
616
 
609
617
  await writer.commit('2/1');
610
618
 
611
- const { checkpoint } = await bucketStorage.getCheckpoint();
619
+ const checkpoint = await bucketStorage.getCheckpoint();
612
620
 
613
621
  const request = bucketRequest(syncRules, 'global[]');
614
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
622
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
615
623
 
616
624
  const data = batch[0].chunkData.data.map((d) => {
617
625
  return {
@@ -651,7 +659,8 @@ bucket_definitions:
651
659
  // 2. Output order not being correct.
652
660
 
653
661
  await using factory = await generateStorageFactory();
654
- const syncRules = await factory.updateSyncRules(
662
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
663
+ factory,
655
664
  updateSyncRulesFromYaml(
656
665
  `
657
666
  bucket_definitions:
@@ -662,7 +671,7 @@ bucket_definitions:
662
671
  { storageVersion }
663
672
  )
664
673
  );
665
- const bucketStorage = factory.getInstance(syncRules);
674
+ const bucketStorage = factory.getInstance(replicationStream);
666
675
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
667
676
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
668
677
 
@@ -773,7 +782,9 @@ bucket_definitions:
773
782
  const checkpoint2 = result2!.flushed_op;
774
783
 
775
784
  const request = bucketRequest(syncRules, 'global[]', checkpoint1);
776
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
785
+ const batch = await test_utils.getBatchArray(
786
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint2), [request])
787
+ );
777
788
 
778
789
  const data = batch[0].chunkData.data.map((d) => {
779
790
  return {
@@ -810,7 +821,8 @@ bucket_definitions:
810
821
  ]);
811
822
  }
812
823
  await using factory = await generateStorageFactory();
813
- const syncRules = await factory.updateSyncRules(
824
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
825
+ factory,
814
826
  updateSyncRulesFromYaml(
815
827
  `
816
828
  bucket_definitions:
@@ -823,7 +835,7 @@ bucket_definitions:
823
835
  }
824
836
  )
825
837
  );
826
- const bucketStorage = factory.getInstance(syncRules);
838
+ const bucketStorage = factory.getInstance(replicationStream);
827
839
 
828
840
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
829
841
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
@@ -876,8 +888,8 @@ bucket_definitions:
876
888
  const checkpoint3 = result3!.flushed_op;
877
889
 
878
890
  const request = bucketRequest(syncRules, 'global[]');
879
- const batch = await test_utils.fromAsync(
880
- bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }])
891
+ const batch = await test_utils.getBatchArray(
892
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }])
881
893
  );
882
894
  const data = batch[0].chunkData.data.map((d) => {
883
895
  return {
@@ -923,7 +935,8 @@ bucket_definitions:
923
935
  }
924
936
 
925
937
  await using factory = await generateStorageFactory();
926
- const syncRules = await factory.updateSyncRules(
938
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
939
+ factory,
927
940
  updateSyncRulesFromYaml(
928
941
  `
929
942
  bucket_definitions:
@@ -936,7 +949,7 @@ bucket_definitions:
936
949
  }
937
950
  )
938
951
  );
939
- const bucketStorage = factory.getInstance(syncRules);
952
+ const bucketStorage = factory.getInstance(replicationStream);
940
953
 
941
954
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
942
955
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
@@ -989,8 +1002,8 @@ bucket_definitions:
989
1002
  const checkpoint3 = result3!.flushed_op;
990
1003
 
991
1004
  const request = bucketRequest(syncRules, 'global[]');
992
- const batch = await test_utils.fromAsync(
993
- bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }])
1005
+ const batch = await test_utils.getBatchArray(
1006
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }])
994
1007
  );
995
1008
  const data = batch[0].chunkData.data.map((d) => {
996
1009
  return {
@@ -1026,7 +1039,8 @@ bucket_definitions:
1026
1039
  // The specific batch splits is an implementation detail of the storage driver,
1027
1040
  // and the test will have to updated when other implementations are added.
1028
1041
  await using factory = await generateStorageFactory();
1029
- const syncRules = await factory.updateSyncRules(
1042
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1043
+ factory,
1030
1044
  updateSyncRulesFromYaml(
1031
1045
  `
1032
1046
  bucket_definitions:
@@ -1039,7 +1053,7 @@ bucket_definitions:
1039
1053
  }
1040
1054
  )
1041
1055
  );
1042
- const bucketStorage = factory.getInstance(syncRules);
1056
+ const bucketStorage = factory.getInstance(replicationStream);
1043
1057
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1044
1058
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1045
1059
  await writer.markAllSnapshotDone('1/1');
@@ -1089,14 +1103,14 @@ bucket_definitions:
1089
1103
 
1090
1104
  await writer.commit('1/1');
1091
1105
 
1092
- const { checkpoint } = await bucketStorage.getCheckpoint();
1106
+ const checkpoint = await bucketStorage.getCheckpoint();
1093
1107
 
1094
1108
  const options: storage.BucketDataBatchOptions = {
1095
1109
  chunkLimitBytes: 16 * 1024 * 1024
1096
1110
  };
1097
1111
 
1098
1112
  const request = bucketRequest(syncRules, 'global[]');
1099
- const batch1 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
1113
+ const batch1 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
1100
1114
  expect(test_utils.getBatchData(batch1)).toEqual([
1101
1115
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
1102
1116
  { op_id: '2', op: 'PUT', object_id: 'large1', checksum: 454746904 }
@@ -1107,7 +1121,7 @@ bucket_definitions:
1107
1121
  next_after: '2'
1108
1122
  });
1109
1123
 
1110
- const batch2 = await test_utils.fromAsync(
1124
+ const batch2 = await test_utils.getBatchArray(
1111
1125
  bucketStorage.getBucketDataBatch(
1112
1126
  checkpoint,
1113
1127
  [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }],
@@ -1124,7 +1138,7 @@ bucket_definitions:
1124
1138
  next_after: '4'
1125
1139
  });
1126
1140
 
1127
- const batch3 = await test_utils.fromAsync(
1141
+ const batch3 = await test_utils.getBatchArray(
1128
1142
  bucketStorage.getBucketDataBatch(
1129
1143
  checkpoint,
1130
1144
  [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }],
@@ -1136,9 +1150,11 @@ bucket_definitions:
1136
1150
  });
1137
1151
 
1138
1152
  test('long batch', async () => {
1139
- // Test syncing a batch of data that is limited by count.
1153
+ // Test syncing a batch of data that is limited by count. Compressed storage limits persisted
1154
+ // documents and finishes yielding all operations from a document once it has been hydrated.
1140
1155
  await using factory = await generateStorageFactory();
1141
- const syncRules = await factory.updateSyncRules(
1156
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1157
+ factory,
1142
1158
  updateSyncRulesFromYaml(
1143
1159
  `
1144
1160
  bucket_definitions:
@@ -1151,7 +1167,7 @@ bucket_definitions:
1151
1167
  }
1152
1168
  )
1153
1169
  );
1154
- const bucketStorage = factory.getInstance(syncRules);
1170
+ const bucketStorage = factory.getInstance(replicationStream);
1155
1171
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1156
1172
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1157
1173
  await writer.markAllSnapshotDone('1/1');
@@ -1170,54 +1186,74 @@ bucket_definitions:
1170
1186
 
1171
1187
  await writer.commit('1/1');
1172
1188
 
1173
- const { checkpoint } = await bucketStorage.getCheckpoint();
1189
+ const checkpoint = await bucketStorage.getCheckpoint();
1174
1190
 
1175
1191
  const request = bucketRequest(syncRules, 'global[]');
1176
- const batch1 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 }));
1192
+ const batch1 = await test_utils.getSingleBatchItem(
1193
+ bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 })
1194
+ );
1177
1195
 
1178
- expect(test_utils.getBatchData(batch1)).toEqual([
1196
+ const allOperations = [
1179
1197
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
1180
1198
  { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1181
1199
  { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
1182
- { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 }
1183
- ]);
1184
-
1185
- expect(test_utils.getBatchMeta(batch1)).toEqual({
1186
- after: '0',
1187
- has_more: true,
1188
- next_after: '4'
1189
- });
1190
-
1191
- const batch2 = await test_utils.oneFromAsync(
1192
- bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
1193
- limit: 4
1194
- })
1195
- );
1196
- expect(test_utils.getBatchData(batch2)).toEqual([
1200
+ { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
1197
1201
  { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
1198
1202
  { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 }
1199
- ]);
1203
+ ];
1200
1204
 
1201
- expect(test_utils.getBatchMeta(batch2)).toEqual({
1202
- after: '4',
1203
- has_more: false,
1204
- next_after: '6'
1205
- });
1205
+ if (config.compressedBucketStorage) {
1206
+ expect(test_utils.getBatchData(batch1)).toEqual(allOperations);
1207
+ expect(test_utils.getBatchMeta(batch1)).toEqual({
1208
+ after: '0',
1209
+ has_more: false,
1210
+ next_after: '6'
1211
+ });
1206
1212
 
1207
- const batch3 = await test_utils.fromAsync(
1208
- bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
1209
- limit: 4
1210
- })
1211
- );
1212
- expect(test_utils.getBatchData(batch3)).toEqual([]);
1213
+ const batch2 = await test_utils.getBatchArray(
1214
+ bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
1215
+ limit: 4
1216
+ })
1217
+ );
1218
+ expect(test_utils.getBatchData(batch2)).toEqual([]);
1219
+ expect(test_utils.getBatchMeta(batch2)).toEqual(null);
1220
+ } else {
1221
+ expect(test_utils.getBatchData(batch1)).toEqual(allOperations.slice(0, 4));
1213
1222
 
1214
- expect(test_utils.getBatchMeta(batch3)).toEqual(null);
1223
+ expect(test_utils.getBatchMeta(batch1)).toEqual({
1224
+ after: '0',
1225
+ has_more: true,
1226
+ next_after: '4'
1227
+ });
1228
+
1229
+ const batch2 = await test_utils.getSingleBatchItem(
1230
+ bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
1231
+ limit: 4
1232
+ })
1233
+ );
1234
+ expect(test_utils.getBatchData(batch2)).toEqual(allOperations.slice(4));
1235
+
1236
+ expect(test_utils.getBatchMeta(batch2)).toEqual({
1237
+ after: '4',
1238
+ has_more: false,
1239
+ next_after: '6'
1240
+ });
1241
+
1242
+ const batch3 = await test_utils.getBatchArray(
1243
+ bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
1244
+ limit: 4
1245
+ })
1246
+ );
1247
+ expect(test_utils.getBatchData(batch3)).toEqual([]);
1248
+ expect(test_utils.getBatchMeta(batch3)).toEqual(null);
1249
+ }
1215
1250
  });
1216
1251
 
1217
1252
  describe('batch has_more', () => {
1218
- const setup = async (options: BucketDataBatchOptions) => {
1253
+ const setup = async (options: BucketDataBatchOptions, commitAfter?: number) => {
1219
1254
  await using factory = await generateStorageFactory();
1220
- const syncRules = await factory.updateSyncRules(
1255
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1256
+ factory,
1221
1257
  updateSyncRulesFromYaml(
1222
1258
  `
1223
1259
  bucket_definitions:
@@ -1231,7 +1267,7 @@ bucket_definitions:
1231
1267
  { storageVersion }
1232
1268
  )
1233
1269
  );
1234
- const bucketStorage = factory.getInstance(syncRules);
1270
+ const bucketStorage = factory.getInstance(replicationStream);
1235
1271
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1236
1272
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1237
1273
  await writer.markAllSnapshotDone('1/1');
@@ -1247,23 +1283,30 @@ bucket_definitions:
1247
1283
  },
1248
1284
  afterReplicaId: `test${i}`
1249
1285
  });
1286
+ if (i == commitAfter) {
1287
+ await writer.commit('1/1');
1288
+ }
1250
1289
  }
1251
1290
 
1252
- await writer.commit('1/1');
1291
+ await writer.commit(commitAfter == null ? '1/1' : '1/2');
1253
1292
 
1254
- const { checkpoint } = await bucketStorage.getCheckpoint();
1293
+ const checkpoint = await bucketStorage.getCheckpoint();
1255
1294
  const global1Request = bucketRequest(syncRules, 'global1[]', 0n);
1256
1295
  const global2Request = bucketRequest(syncRules, 'global2[]', 0n);
1257
- const batch = await test_utils.fromAsync(
1258
- bucketStorage.getBucketDataBatch(checkpoint, [global1Request, global2Request], options)
1296
+ const batch = await new test_utils.StorageDataHelpers(bucketStorage, syncRules).getAllBucketData(
1297
+ [global1Request, global2Request],
1298
+ checkpoint,
1299
+ options
1259
1300
  );
1260
1301
 
1261
1302
  return { batch, global1Request, global2Request };
1262
1303
  };
1263
1304
 
1264
1305
  test('batch has_more (1)', async () => {
1265
- const { batch, global1Request, global2Request } = await setup({ limit: 5 });
1266
- expect(batch.length).toEqual(2);
1306
+ // The commit boundary creates two compressed documents for global2. The limit selects the global1
1307
+ // document and the first global2 document, leaving the second global2 document for the next batch.
1308
+ const { batch, global1Request, global2Request } = await setup({ limit: 2 }, 5);
1309
+ expect(batch.length).toBeGreaterThanOrEqual(2);
1267
1310
 
1268
1311
  expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1269
1312
  expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
@@ -1272,12 +1315,20 @@ bucket_definitions:
1272
1315
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1273
1316
  ]);
1274
1317
 
1275
- expect(test_utils.getBatchData(batch[1])).toEqual([
1318
+ const global2Operations = [
1276
1319
  { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1277
1320
  { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
1278
1321
  { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
1279
- { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 }
1280
- ]);
1322
+ { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
1323
+ { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 },
1324
+ { op_id: '7', op: 'PUT', object_id: 'test7', checksum: 2477637855 },
1325
+ { op_id: '8', op: 'PUT', object_id: 'test8', checksum: 3644033632 },
1326
+ { op_id: '9', op: 'PUT', object_id: 'test9', checksum: 1011055869 },
1327
+ { op_id: '10', op: 'PUT', object_id: 'test10', checksum: 1331456365 }
1328
+ ];
1329
+ expect(test_utils.getBatchData(batch[1])).toEqual(
1330
+ config.compressedBucketStorage ? global2Operations.slice(0, 4) : global2Operations.slice(0, 1)
1331
+ );
1281
1332
 
1282
1333
  expect(test_utils.getBatchMeta(batch[0])).toEqual({
1283
1334
  after: '0',
@@ -1288,7 +1339,7 @@ bucket_definitions:
1288
1339
  expect(test_utils.getBatchMeta(batch[1])).toEqual({
1289
1340
  after: '0',
1290
1341
  has_more: true,
1291
- next_after: '5'
1342
+ next_after: config.compressedBucketStorage ? '5' : '2'
1292
1343
  });
1293
1344
  });
1294
1345
 
@@ -1332,49 +1383,86 @@ bucket_definitions:
1332
1383
  // 50 bytes is more than 1 row, less than 2 rows
1333
1384
  const { batch, global1Request, global2Request } = await setup({ limit: 3, chunkLimitBytes: 50 });
1334
1385
 
1335
- expect(batch.length).toEqual(3);
1336
- expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1337
- expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1338
- expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1339
-
1340
- expect(test_utils.getBatchData(batch[0])).toEqual([
1341
- { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1342
- ]);
1343
-
1344
- expect(test_utils.getBatchData(batch[1])).toEqual([
1345
- { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1346
- ]);
1347
- expect(test_utils.getBatchData(batch[2])).toEqual([
1348
- { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1349
- ]);
1386
+ if (config.compressedBucketStorage) {
1387
+ // In v3+, ops in the same bucket share a document. Once hydrated, the entire document is yielded even
1388
+ // when it exceeds the byte limit; the byte limit controls whether another document is fetched.
1389
+ expect(batch.length).toEqual(2);
1390
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1391
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1392
+
1393
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1394
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1395
+ ]);
1396
+
1397
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1398
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1399
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
1400
+ { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
1401
+ { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
1402
+ { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 },
1403
+ { op_id: '7', op: 'PUT', object_id: 'test7', checksum: 2477637855 },
1404
+ { op_id: '8', op: 'PUT', object_id: 'test8', checksum: 3644033632 },
1405
+ { op_id: '9', op: 'PUT', object_id: 'test9', checksum: 1011055869 },
1406
+ { op_id: '10', op: 'PUT', object_id: 'test10', checksum: 1331456365 }
1407
+ ]);
1408
+
1409
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1410
+ after: '0',
1411
+ has_more: false,
1412
+ next_after: '1'
1413
+ });
1350
1414
 
1351
- expect(test_utils.getBatchMeta(batch[0])).toEqual({
1352
- after: '0',
1353
- has_more: false,
1354
- next_after: '1'
1355
- });
1415
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1416
+ after: '0',
1417
+ has_more: false,
1418
+ next_after: '10'
1419
+ });
1420
+ } else {
1421
+ expect(batch.length).toBeGreaterThanOrEqual(3);
1422
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1423
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1424
+ expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1425
+
1426
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1427
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1428
+ ]);
1429
+
1430
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1431
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1432
+ ]);
1433
+ expect(test_utils.getBatchData(batch[2])).toEqual([
1434
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1435
+ ]);
1436
+
1437
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1438
+ after: '0',
1439
+ has_more: false,
1440
+ next_after: '1'
1441
+ });
1356
1442
 
1357
- expect(test_utils.getBatchMeta(batch[1])).toEqual({
1358
- after: '0',
1359
- has_more: true,
1360
- next_after: '2'
1361
- });
1443
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1444
+ after: '0',
1445
+ has_more: true,
1446
+ next_after: '2'
1447
+ });
1362
1448
 
1363
- expect(test_utils.getBatchMeta(batch[2])).toEqual({
1364
- after: '2',
1365
- has_more: true,
1366
- next_after: '3'
1367
- });
1449
+ expect(test_utils.getBatchMeta(batch[2])).toEqual({
1450
+ after: '2',
1451
+ has_more: true,
1452
+ next_after: '3'
1453
+ });
1454
+ }
1368
1455
  });
1369
1456
  });
1370
1457
 
1371
1458
  test('empty storage metrics', async () => {
1372
1459
  await using f = await generateStorageFactory({ dropAll: true });
1373
1460
  const metrics = await f.getStorageMetrics();
1374
- expect(metrics).toEqual({
1461
+ expect(metrics).toMatchObject({
1375
1462
  operations_size_bytes: 0,
1376
1463
  parameters_size_bytes: 0,
1377
- replication_size_bytes: 0
1464
+ replication_size_bytes: 0,
1465
+ object_storage_size_bytes: 0
1378
1466
  });
1379
1467
 
1380
1468
  const r = await f.configureSyncRules(updateSyncRulesFromYaml('bucket_definitions: {}'));
@@ -1392,7 +1480,8 @@ bucket_definitions:
1392
1480
  // but large enough in size to be split over multiple returned chunks.
1393
1481
  // Similar to the above test, but splits over 1MB chunks.
1394
1482
  await using factory = await generateStorageFactory();
1395
- const syncRules = await factory.updateSyncRules(
1483
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1484
+ factory,
1396
1485
  updateSyncRulesFromYaml(
1397
1486
  `
1398
1487
  bucket_definitions:
@@ -1406,7 +1495,7 @@ bucket_definitions:
1406
1495
  }
1407
1496
  )
1408
1497
  );
1409
- const bucketStorage = factory.getInstance(syncRules);
1498
+ const bucketStorage = factory.getInstance(replicationStream);
1410
1499
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1411
1500
 
1412
1501
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, 1);
@@ -1444,7 +1533,8 @@ bucket_definitions:
1444
1533
 
1445
1534
  test('unchanged checksums', async () => {
1446
1535
  await using factory = await generateStorageFactory();
1447
- const syncRules = await factory.updateSyncRules(
1536
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1537
+ factory,
1448
1538
  updateSyncRulesFromYaml(
1449
1539
  `
1450
1540
  bucket_definitions:
@@ -1457,7 +1547,7 @@ bucket_definitions:
1457
1547
  }
1458
1548
  )
1459
1549
  );
1460
- const bucketStorage = factory.getInstance(syncRules);
1550
+ const bucketStorage = factory.getInstance(replicationStream);
1461
1551
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1462
1552
 
1463
1553
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -1472,12 +1562,14 @@ bucket_definitions:
1472
1562
  afterReplicaId: test_utils.rid('test1')
1473
1563
  });
1474
1564
  await writer.commit('1/1');
1475
- const { checkpoint } = await bucketStorage.getCheckpoint();
1565
+ const checkpoint = await bucketStorage.getCheckpoint();
1476
1566
 
1477
1567
  const request = bucketRequest(syncRules, 'global[]');
1478
1568
  const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
1479
1569
  expect(checksums).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1480
- const checksums2 = [...(await bucketStorage.getChecksums(checkpoint + 1n, [request])).values()];
1570
+ const checksums2 = [
1571
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint.checkpoint + 1n), [request])).values()
1572
+ ];
1481
1573
  expect(checksums2).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1482
1574
  });
1483
1575
 
@@ -1485,7 +1577,8 @@ bucket_definitions:
1485
1577
 
1486
1578
  test('empty checkpoints (1)', async () => {
1487
1579
  await using factory = await generateStorageFactory();
1488
- const syncRules = await factory.updateSyncRules(
1580
+ const { stream: replicationStream } = await test_utils.deploySyncRules(
1581
+ factory,
1489
1582
  updateSyncRulesFromYaml(
1490
1583
  `
1491
1584
  bucket_definitions:
@@ -1496,7 +1589,7 @@ bucket_definitions:
1496
1589
  { storageVersion }
1497
1590
  )
1498
1591
  );
1499
- const bucketStorage = factory.getInstance(syncRules);
1592
+ const bucketStorage = factory.getInstance(replicationStream);
1500
1593
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1501
1594
  await writer.markAllSnapshotDone('1/1');
1502
1595
  await writer.commit('1/1');
@@ -1521,7 +1614,8 @@ bucket_definitions:
1521
1614
 
1522
1615
  test('empty checkpoints (2)', async () => {
1523
1616
  await using factory = await generateStorageFactory();
1524
- const syncRules = await factory.updateSyncRules(
1617
+ const { stream: replicationStream } = await test_utils.deploySyncRules(
1618
+ factory,
1525
1619
  updateSyncRulesFromYaml(
1526
1620
  `
1527
1621
  bucket_definitions:
@@ -1534,7 +1628,7 @@ bucket_definitions:
1534
1628
  }
1535
1629
  )
1536
1630
  );
1537
- const bucketStorage = factory.getInstance(syncRules);
1631
+ const bucketStorage = factory.getInstance(replicationStream);
1538
1632
  await using writer1 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1539
1633
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1540
1634
  const sourceTable = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
@@ -1571,7 +1665,8 @@ bucket_definitions:
1571
1665
 
1572
1666
  test('empty checkpoints (sync rule activation)', async () => {
1573
1667
  await using factory = await generateStorageFactory();
1574
- const syncRules = await factory.updateSyncRules(
1668
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1669
+ factory,
1575
1670
  updateSyncRulesFromYaml(
1576
1671
  `
1577
1672
  bucket_definitions:
@@ -1584,7 +1679,7 @@ bucket_definitions:
1584
1679
  }
1585
1680
  )
1586
1681
  );
1587
- const bucketStorage = factory.getInstance(syncRules);
1682
+ const bucketStorage = factory.getInstance(replicationStream);
1588
1683
 
1589
1684
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1590
1685
  const result1 = await writer.commit('1/1', { createEmptyCheckpoints: false });
@@ -1609,8 +1704,8 @@ bucket_definitions:
1609
1704
  const cp2 = await bucketStorage.getCheckpoint();
1610
1705
  expect(cp2.lsn).toEqual('3/1');
1611
1706
 
1612
- const activeSyncRules = await factory.getActiveSyncRulesContent();
1613
- expect(activeSyncRules?.id).toEqual(syncRules.id);
1707
+ const activeSyncRules = await factory.getActiveSyncConfig();
1708
+ expect(activeSyncRules?.content.replicationStreamId).toEqual(syncRules.replicationStreamId);
1614
1709
 
1615
1710
  // At this point, it should be a truely empty checkpoint
1616
1711
  const result4 = await writer.commit('4/1', { createEmptyCheckpoints: false });
@@ -1623,7 +1718,8 @@ bucket_definitions:
1623
1718
 
1624
1719
  test.runIf(storageVersion >= 3)('deleting while streaming', async () => {
1625
1720
  await using factory = await generateStorageFactory();
1626
- const syncRules = await factory.updateSyncRules(
1721
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1722
+ factory,
1627
1723
  updateSyncRulesFromYaml(
1628
1724
  `
1629
1725
  bucket_definitions:
@@ -1636,7 +1732,7 @@ bucket_definitions:
1636
1732
  }
1637
1733
  )
1638
1734
  );
1639
- const bucketStorage = factory.getInstance(syncRules);
1735
+ const bucketStorage = factory.getInstance(replicationStream);
1640
1736
  await using snapshotWriter = await bucketStorage.createWriter({
1641
1737
  ...test_utils.BATCH_OPTIONS,
1642
1738
  skipExistingRows: true
@@ -1675,8 +1771,8 @@ bucket_definitions:
1675
1771
 
1676
1772
  const cp = await bucketStorage.getCheckpoint();
1677
1773
  expect(cp.lsn).toEqual('3/1');
1678
- const data = await test_utils.fromAsync(
1679
- bucketStorage.getBucketDataBatch(cp.checkpoint, [bucketRequest(syncRules, 'global[]')])
1774
+ const data = await test_utils.getBatchArray(
1775
+ bucketStorage.getBucketDataBatch(cp, [bucketRequest(syncRules, 'global[]')])
1680
1776
  );
1681
1777
 
1682
1778
  expect(data).toEqual([]);
@@ -1692,7 +1788,8 @@ export function testChecksumBatching(config: storage.TestStorageConfig) {
1692
1788
  const storageVersion = config.storageVersion ?? CURRENT_STORAGE_VERSION;
1693
1789
  test('checksums for multiple buckets', async () => {
1694
1790
  await using factory = await config.factory();
1695
- const syncRules = await factory.updateSyncRules(
1791
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1792
+ factory,
1696
1793
  updateSyncRulesFromYaml(
1697
1794
  `
1698
1795
  bucket_definitions:
@@ -1706,7 +1803,7 @@ bucket_definitions:
1706
1803
  }
1707
1804
  )
1708
1805
  );
1709
- const bucketStorage = factory.getInstance(syncRules);
1806
+ const bucketStorage = factory.getInstance(replicationStream);
1710
1807
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1711
1808
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1712
1809
  await writer.markAllSnapshotDone('1/1');
@@ -1726,7 +1823,7 @@ bucket_definitions:
1726
1823
  }
1727
1824
  }
1728
1825
  await writer.commit('1/1');
1729
- const { checkpoint } = await bucketStorage.getCheckpoint();
1826
+ const checkpoint = await bucketStorage.getCheckpoint();
1730
1827
 
1731
1828
  bucketStorage.clearChecksumCache();
1732
1829
  const users = ['u1', 'u2', 'u3', 'u4'];
@@ -1756,7 +1853,11 @@ streams:
1756
1853
  `)
1757
1854
  );
1758
1855
 
1759
- const { errors } = deployed.parsed({ defaultSchema: 'ignored' }).syncConfigWithErrors;
1856
+ const [deployedContent] = deployed.syncConfigContent;
1857
+ expect(deployedContent).toBeDefined();
1858
+ const [deployedConfig] = deployedContent.parsed({ defaultSchema: 'ignored' }).syncConfigs;
1859
+ expect(deployedConfig).toBeDefined();
1860
+ const { errors } = deployedConfig;
1760
1861
  expect(errors).toHaveLength(1);
1761
1862
  expect(errors[0].message).toStrictEqual('Expected a SELECT statement');
1762
1863
  expect(errors[0].location).toStrictEqual({