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

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 (41) hide show
  1. package/CHANGELOG.md +75 -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/stream_utils.d.ts +0 -1
  14. package/dist/test-utils/stream_utils.js +0 -10
  15. package/dist/test-utils/stream_utils.js.map +1 -1
  16. package/dist/tests/register-compacting-tests.js +28 -21
  17. package/dist/tests/register-compacting-tests.js.map +1 -1
  18. package/dist/tests/register-data-storage-checkpoint-tests.js +102 -3
  19. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  20. package/dist/tests/register-data-storage-data-tests.js +202 -136
  21. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  22. package/dist/tests/register-data-storage-parameter-tests.js +44 -42
  23. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  24. package/dist/tests/register-sync-tests.js +399 -82
  25. package/dist/tests/register-sync-tests.js.map +1 -1
  26. package/dist/tests/util.d.ts +2 -2
  27. package/dist/tests/util.js.map +1 -1
  28. package/package.json +5 -6
  29. package/src/test-utils/AbstractStreamTestContext.ts +31 -27
  30. package/src/test-utils/StorageDataHelpers.ts +52 -8
  31. package/src/test-utils/bucket-validation.ts +3 -3
  32. package/src/test-utils/general-utils.ts +62 -10
  33. package/src/test-utils/stream_utils.ts +0 -11
  34. package/src/tests/register-compacting-tests.ts +47 -24
  35. package/src/tests/register-data-storage-checkpoint-tests.ts +132 -3
  36. package/src/tests/register-data-storage-data-tests.ts +248 -148
  37. package/src/tests/register-data-storage-parameter-tests.ts +58 -42
  38. package/src/tests/register-sync-tests.ts +438 -84
  39. package/src/tests/util.ts +2 -2
  40. package/tsconfig.json +1 -4
  41. package/tsconfig.tsbuildinfo +1 -1
@@ -27,13 +27,13 @@ export function registerDataStorageDataTests(config) {
27
27
  const storageVersion = config.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
28
28
  test('removing row', async () => {
29
29
  await using factory = await generateStorageFactory();
30
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
30
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
31
31
  bucket_definitions:
32
32
  global:
33
33
  data:
34
34
  - SELECT id, description FROM "%"
35
35
  `, { storageVersion }));
36
- const bucketStorage = factory.getInstance(syncRules);
36
+ const bucketStorage = factory.getInstance(replicationStream);
37
37
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
38
38
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
39
39
  await writer.markAllSnapshotDone('1/1');
@@ -52,9 +52,9 @@ bucket_definitions:
52
52
  beforeReplicaId: test_utils.rid('test1')
53
53
  });
54
54
  await writer.commit('1/1');
55
- const { checkpoint } = await bucketStorage.getCheckpoint();
55
+ const checkpoint = await bucketStorage.getCheckpoint();
56
56
  const request = bucketRequest(syncRules, 'global[]');
57
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
57
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
58
58
  const data = batch[0].chunkData.data.map((d) => {
59
59
  return {
60
60
  op: d.op,
@@ -79,13 +79,13 @@ bucket_definitions:
79
79
  });
80
80
  test('insert after delete in new batch', async () => {
81
81
  await using factory = await generateStorageFactory();
82
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
82
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
83
83
  bucket_definitions:
84
84
  global:
85
85
  data:
86
86
  - SELECT id, description FROM "%"
87
87
  `, { storageVersion }));
88
- const bucketStorage = factory.getInstance(syncRules);
88
+ const bucketStorage = factory.getInstance(replicationStream);
89
89
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
90
90
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
91
91
  await writer.markAllSnapshotDone('1/1');
@@ -105,9 +105,9 @@ bucket_definitions:
105
105
  afterReplicaId: test_utils.rid('test1')
106
106
  });
107
107
  await writer.commit('2/1');
108
- const { checkpoint } = await bucketStorage.getCheckpoint();
108
+ const checkpoint = await bucketStorage.getCheckpoint();
109
109
  const request = bucketRequest(syncRules, 'global[]');
110
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
110
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
111
111
  const data = batch[0].chunkData.data.map((d) => {
112
112
  return {
113
113
  op: d.op,
@@ -129,13 +129,13 @@ bucket_definitions:
129
129
  test('update after delete in new batch', async () => {
130
130
  // Update after delete may not be common, but the storage layer should handle it in an eventually-consistent way.
131
131
  await using factory = await generateStorageFactory();
132
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
132
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
133
133
  bucket_definitions:
134
134
  global:
135
135
  data:
136
136
  - SELECT id, description FROM "%"
137
137
  `, { storageVersion }));
138
- const bucketStorage = factory.getInstance(syncRules);
138
+ const bucketStorage = factory.getInstance(replicationStream);
139
139
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
140
140
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
141
141
  await writer.markAllSnapshotDone('1/1');
@@ -159,9 +159,9 @@ bucket_definitions:
159
159
  afterReplicaId: test_utils.rid('test1')
160
160
  });
161
161
  await writer.commit('2/1');
162
- const { checkpoint } = await bucketStorage.getCheckpoint();
162
+ const checkpoint = await bucketStorage.getCheckpoint();
163
163
  const request = bucketRequest(syncRules, 'global[]');
164
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
164
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
165
165
  const data = batch[0].chunkData.data.map((d) => {
166
166
  return {
167
167
  op: d.op,
@@ -182,7 +182,7 @@ bucket_definitions:
182
182
  });
183
183
  test('insert after delete in same batch', async () => {
184
184
  await using factory = await generateStorageFactory();
185
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
185
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
186
186
  bucket_definitions:
187
187
  global:
188
188
  data:
@@ -190,7 +190,7 @@ bucket_definitions:
190
190
  `, {
191
191
  storageVersion
192
192
  }));
193
- const bucketStorage = factory.getInstance(syncRules);
193
+ const bucketStorage = factory.getInstance(replicationStream);
194
194
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
195
195
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
196
196
  await writer.markAllSnapshotDone('1/1');
@@ -209,9 +209,9 @@ bucket_definitions:
209
209
  afterReplicaId: test_utils.rid('test1')
210
210
  });
211
211
  await writer.commit('1/1');
212
- const { checkpoint } = await bucketStorage.getCheckpoint();
212
+ const checkpoint = await bucketStorage.getCheckpoint();
213
213
  const request = bucketRequest(syncRules, 'global[]');
214
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
214
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
215
215
  const data = batch[0].chunkData.data.map((d) => {
216
216
  return {
217
217
  op: d.op,
@@ -232,7 +232,7 @@ bucket_definitions:
232
232
  });
233
233
  test('(insert, delete, insert), (delete)', async () => {
234
234
  await using factory = await generateStorageFactory();
235
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
235
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
236
236
  bucket_definitions:
237
237
  global:
238
238
  data:
@@ -240,7 +240,7 @@ bucket_definitions:
240
240
  `, {
241
241
  storageVersion
242
242
  }));
243
- const bucketStorage = factory.getInstance(syncRules);
243
+ const bucketStorage = factory.getInstance(replicationStream);
244
244
  {
245
245
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
246
246
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -281,9 +281,9 @@ bucket_definitions:
281
281
  });
282
282
  await writer.commit('2/1');
283
283
  }
284
- const { checkpoint } = await bucketStorage.getCheckpoint();
284
+ const checkpoint = await bucketStorage.getCheckpoint();
285
285
  const request = bucketRequest(syncRules, 'global[]');
286
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
286
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
287
287
  expect(reduceBucket(batch[0].chunkData.data).slice(1)).toEqual([]);
288
288
  const data = batch[0].chunkData.data.map((d) => {
289
289
  return {
@@ -296,7 +296,7 @@ bucket_definitions:
296
296
  });
297
297
  test('changing client ids', async () => {
298
298
  await using factory = await generateStorageFactory();
299
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
299
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
300
300
  bucket_definitions:
301
301
  global:
302
302
  data:
@@ -304,7 +304,7 @@ bucket_definitions:
304
304
  `, {
305
305
  storageVersion
306
306
  }));
307
- const bucketStorage = factory.getInstance(syncRules);
307
+ const bucketStorage = factory.getInstance(replicationStream);
308
308
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
309
309
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
310
310
  await writer.markAllSnapshotDone('1/1');
@@ -339,8 +339,8 @@ bucket_definitions:
339
339
  afterReplicaId: test_utils.rid('test2')
340
340
  });
341
341
  await writer.commit('1/1');
342
- const { checkpoint } = await bucketStorage.getCheckpoint();
343
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]')]));
342
+ const checkpoint = await bucketStorage.getCheckpoint();
343
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]')]));
344
344
  const data = batch[0].chunkData.data.map((d) => {
345
345
  return {
346
346
  op: d.op,
@@ -356,7 +356,7 @@ bucket_definitions:
356
356
  });
357
357
  test('re-apply delete', async () => {
358
358
  await using factory = await generateStorageFactory();
359
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
359
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
360
360
  bucket_definitions:
361
361
  global:
362
362
  data:
@@ -364,7 +364,7 @@ bucket_definitions:
364
364
  `, {
365
365
  storageVersion
366
366
  }));
367
- const bucketStorage = factory.getInstance(syncRules);
367
+ const bucketStorage = factory.getInstance(replicationStream);
368
368
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
369
369
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
370
370
  await writer.markAllSnapshotDone('1/1');
@@ -390,9 +390,9 @@ bucket_definitions:
390
390
  beforeReplicaId: test_utils.rid('test1')
391
391
  });
392
392
  await writer.flush();
393
- const { checkpoint } = await bucketStorage.getCheckpoint();
393
+ const checkpoint = await bucketStorage.getCheckpoint();
394
394
  const request = bucketRequest(syncRules, 'global[]');
395
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
395
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
396
396
  const data = batch[0].chunkData.data.map((d) => {
397
397
  return {
398
398
  op: d.op,
@@ -417,13 +417,13 @@ bucket_definitions:
417
417
  });
418
418
  test('re-apply update + delete', async () => {
419
419
  await using factory = await generateStorageFactory();
420
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
420
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
421
421
  bucket_definitions:
422
422
  global:
423
423
  data:
424
424
  - SELECT id, description FROM "%"
425
425
  `, { storageVersion }));
426
- const bucketStorage = factory.getInstance(syncRules);
426
+ const bucketStorage = factory.getInstance(replicationStream);
427
427
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
428
428
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
429
429
  await writer.markAllSnapshotDone('1/1');
@@ -487,9 +487,9 @@ bucket_definitions:
487
487
  beforeReplicaId: test_utils.rid('test1')
488
488
  });
489
489
  await writer.commit('2/1');
490
- const { checkpoint } = await bucketStorage.getCheckpoint();
490
+ const checkpoint = await bucketStorage.getCheckpoint();
491
491
  const request = bucketRequest(syncRules, 'global[]');
492
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
492
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request]));
493
493
  const data = batch[0].chunkData.data.map((d) => {
494
494
  return {
495
495
  op: d.op,
@@ -523,13 +523,13 @@ bucket_definitions:
523
523
  // 1. Not getting the correct "current_data" state for each operation.
524
524
  // 2. Output order not being correct.
525
525
  await using factory = await generateStorageFactory();
526
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
526
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
527
527
  bucket_definitions:
528
528
  global:
529
529
  data:
530
530
  - SELECT id, description FROM "test"
531
531
  `, { storageVersion }));
532
- const bucketStorage = factory.getInstance(syncRules);
532
+ const bucketStorage = factory.getInstance(replicationStream);
533
533
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
534
534
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
535
535
  // Pre-setup
@@ -627,7 +627,7 @@ bucket_definitions:
627
627
  const result2 = await writer.flush();
628
628
  const checkpoint2 = result2.flushed_op;
629
629
  const request = bucketRequest(syncRules, 'global[]', checkpoint1);
630
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
630
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint2), [request]));
631
631
  const data = batch[0].chunkData.data.map((d) => {
632
632
  return {
633
633
  op: d.op,
@@ -659,7 +659,7 @@ bucket_definitions:
659
659
  ]);
660
660
  }
661
661
  await using factory = await generateStorageFactory();
662
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
662
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
663
663
  bucket_definitions:
664
664
  global:
665
665
  data:
@@ -667,7 +667,7 @@ bucket_definitions:
667
667
  `, {
668
668
  storageVersion
669
669
  }));
670
- const bucketStorage = factory.getInstance(syncRules);
670
+ const bucketStorage = factory.getInstance(replicationStream);
671
671
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
672
672
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
673
673
  // Pre-setup
@@ -713,7 +713,7 @@ bucket_definitions:
713
713
  const result3 = await writer.flush();
714
714
  const checkpoint3 = result3.flushed_op;
715
715
  const request = bucketRequest(syncRules, 'global[]');
716
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }]));
716
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }]));
717
717
  const data = batch[0].chunkData.data.map((d) => {
718
718
  return {
719
719
  op: d.op,
@@ -755,7 +755,7 @@ bucket_definitions:
755
755
  ]);
756
756
  }
757
757
  await using factory = await generateStorageFactory();
758
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
758
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
759
759
  bucket_definitions:
760
760
  global:
761
761
  data:
@@ -763,7 +763,7 @@ bucket_definitions:
763
763
  `, {
764
764
  storageVersion
765
765
  }));
766
- const bucketStorage = factory.getInstance(syncRules);
766
+ const bucketStorage = factory.getInstance(replicationStream);
767
767
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
768
768
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
769
769
  // Pre-setup
@@ -809,7 +809,7 @@ bucket_definitions:
809
809
  const result3 = await writer.flush();
810
810
  const checkpoint3 = result3.flushed_op;
811
811
  const request = bucketRequest(syncRules, 'global[]');
812
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }]));
812
+ const batch = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }]));
813
813
  const data = batch[0].chunkData.data.map((d) => {
814
814
  return {
815
815
  op: d.op,
@@ -842,7 +842,7 @@ bucket_definitions:
842
842
  // The specific batch splits is an implementation detail of the storage driver,
843
843
  // and the test will have to updated when other implementations are added.
844
844
  await using factory = await generateStorageFactory();
845
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
845
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
846
846
  bucket_definitions:
847
847
  global:
848
848
  data:
@@ -850,7 +850,7 @@ bucket_definitions:
850
850
  `, {
851
851
  storageVersion
852
852
  }));
853
- const bucketStorage = factory.getInstance(syncRules);
853
+ const bucketStorage = factory.getInstance(replicationStream);
854
854
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
855
855
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
856
856
  await writer.markAllSnapshotDone('1/1');
@@ -893,12 +893,12 @@ bucket_definitions:
893
893
  afterReplicaId: test_utils.rid('test3')
894
894
  });
895
895
  await writer.commit('1/1');
896
- const { checkpoint } = await bucketStorage.getCheckpoint();
896
+ const checkpoint = await bucketStorage.getCheckpoint();
897
897
  const options = {
898
898
  chunkLimitBytes: 16 * 1024 * 1024
899
899
  };
900
900
  const request = bucketRequest(syncRules, 'global[]');
901
- const batch1 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
901
+ const batch1 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
902
902
  expect(test_utils.getBatchData(batch1)).toEqual([
903
903
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
904
904
  { op_id: '2', op: 'PUT', object_id: 'large1', checksum: 454746904 }
@@ -908,7 +908,7 @@ bucket_definitions:
908
908
  has_more: true,
909
909
  next_after: '2'
910
910
  });
911
- const batch2 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }], options));
911
+ const batch2 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }], options));
912
912
  expect(test_utils.getBatchData(batch2)).toEqual([
913
913
  { op_id: '3', op: 'PUT', object_id: 'large2', checksum: 1795508474 },
914
914
  { op_id: '4', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
@@ -918,14 +918,15 @@ bucket_definitions:
918
918
  has_more: false,
919
919
  next_after: '4'
920
920
  });
921
- const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }], options));
921
+ const batch3 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }], options));
922
922
  expect(test_utils.getBatchData(batch3)).toEqual([]);
923
923
  expect(test_utils.getBatchMeta(batch3)).toEqual(null);
924
924
  });
925
925
  test('long batch', async () => {
926
- // Test syncing a batch of data that is limited by count.
926
+ // Test syncing a batch of data that is limited by count. Compressed storage limits persisted
927
+ // documents and finishes yielding all operations from a document once it has been hydrated.
927
928
  await using factory = await generateStorageFactory();
928
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
929
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
929
930
  bucket_definitions:
930
931
  global:
931
932
  data:
@@ -933,7 +934,7 @@ bucket_definitions:
933
934
  `, {
934
935
  storageVersion
935
936
  }));
936
- const bucketStorage = factory.getInstance(syncRules);
937
+ const bucketStorage = factory.getInstance(replicationStream);
937
938
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
938
939
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
939
940
  await writer.markAllSnapshotDone('1/1');
@@ -949,42 +950,57 @@ bucket_definitions:
949
950
  });
950
951
  }
951
952
  await writer.commit('1/1');
952
- const { checkpoint } = await bucketStorage.getCheckpoint();
953
+ const checkpoint = await bucketStorage.getCheckpoint();
953
954
  const request = bucketRequest(syncRules, 'global[]');
954
- const batch1 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 }));
955
- expect(test_utils.getBatchData(batch1)).toEqual([
955
+ const batch1 = await test_utils.getSingleBatchItem(bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 }));
956
+ const allOperations = [
956
957
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
957
958
  { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
958
959
  { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
959
- { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 }
960
- ]);
961
- expect(test_utils.getBatchMeta(batch1)).toEqual({
962
- after: '0',
963
- has_more: true,
964
- next_after: '4'
965
- });
966
- const batch2 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
967
- limit: 4
968
- }));
969
- expect(test_utils.getBatchData(batch2)).toEqual([
960
+ { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
970
961
  { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
971
962
  { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 }
972
- ]);
973
- expect(test_utils.getBatchMeta(batch2)).toEqual({
974
- after: '4',
975
- has_more: false,
976
- next_after: '6'
977
- });
978
- const batch3 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
979
- limit: 4
980
- }));
981
- expect(test_utils.getBatchData(batch3)).toEqual([]);
982
- expect(test_utils.getBatchMeta(batch3)).toEqual(null);
963
+ ];
964
+ if (config.compressedBucketStorage) {
965
+ expect(test_utils.getBatchData(batch1)).toEqual(allOperations);
966
+ expect(test_utils.getBatchMeta(batch1)).toEqual({
967
+ after: '0',
968
+ has_more: false,
969
+ next_after: '6'
970
+ });
971
+ const batch2 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
972
+ limit: 4
973
+ }));
974
+ expect(test_utils.getBatchData(batch2)).toEqual([]);
975
+ expect(test_utils.getBatchMeta(batch2)).toEqual(null);
976
+ }
977
+ else {
978
+ expect(test_utils.getBatchData(batch1)).toEqual(allOperations.slice(0, 4));
979
+ expect(test_utils.getBatchMeta(batch1)).toEqual({
980
+ after: '0',
981
+ has_more: true,
982
+ next_after: '4'
983
+ });
984
+ const batch2 = await test_utils.getSingleBatchItem(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
985
+ limit: 4
986
+ }));
987
+ expect(test_utils.getBatchData(batch2)).toEqual(allOperations.slice(4));
988
+ expect(test_utils.getBatchMeta(batch2)).toEqual({
989
+ after: '4',
990
+ has_more: false,
991
+ next_after: '6'
992
+ });
993
+ const batch3 = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
994
+ limit: 4
995
+ }));
996
+ expect(test_utils.getBatchData(batch3)).toEqual([]);
997
+ expect(test_utils.getBatchMeta(batch3)).toEqual(null);
998
+ }
983
999
  });
984
1000
  describe('batch has_more', () => {
985
- const setup = async (options) => {
1001
+ const setup = async (options, commitAfter) => {
986
1002
  await using factory = await generateStorageFactory();
987
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1003
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
988
1004
  bucket_definitions:
989
1005
  global1:
990
1006
  data:
@@ -993,7 +1009,7 @@ bucket_definitions:
993
1009
  data:
994
1010
  - SELECT id, description FROM test WHERE bucket = 'global2'
995
1011
  `, { storageVersion }));
996
- const bucketStorage = factory.getInstance(syncRules);
1012
+ const bucketStorage = factory.getInstance(replicationStream);
997
1013
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
998
1014
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
999
1015
  await writer.markAllSnapshotDone('1/1');
@@ -1008,28 +1024,39 @@ bucket_definitions:
1008
1024
  },
1009
1025
  afterReplicaId: `test${i}`
1010
1026
  });
1027
+ if (i == commitAfter) {
1028
+ await writer.commit('1/1');
1029
+ }
1011
1030
  }
1012
- await writer.commit('1/1');
1013
- const { checkpoint } = await bucketStorage.getCheckpoint();
1031
+ await writer.commit(commitAfter == null ? '1/1' : '1/2');
1032
+ const checkpoint = await bucketStorage.getCheckpoint();
1014
1033
  const global1Request = bucketRequest(syncRules, 'global1[]', 0n);
1015
1034
  const global2Request = bucketRequest(syncRules, 'global2[]', 0n);
1016
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [global1Request, global2Request], options));
1035
+ const batch = await new test_utils.StorageDataHelpers(bucketStorage, syncRules).getAllBucketData([global1Request, global2Request], checkpoint, options);
1017
1036
  return { batch, global1Request, global2Request };
1018
1037
  };
1019
1038
  test('batch has_more (1)', async () => {
1020
- const { batch, global1Request, global2Request } = await setup({ limit: 5 });
1021
- expect(batch.length).toEqual(2);
1039
+ // The commit boundary creates two compressed documents for global2. The limit selects the global1
1040
+ // document and the first global2 document, leaving the second global2 document for the next batch.
1041
+ const { batch, global1Request, global2Request } = await setup({ limit: 2 }, 5);
1042
+ expect(batch.length).toBeGreaterThanOrEqual(2);
1022
1043
  expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1023
1044
  expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1024
1045
  expect(test_utils.getBatchData(batch[0])).toEqual([
1025
1046
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1026
1047
  ]);
1027
- expect(test_utils.getBatchData(batch[1])).toEqual([
1048
+ const global2Operations = [
1028
1049
  { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1029
1050
  { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
1030
1051
  { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
1031
- { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 }
1032
- ]);
1052
+ { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
1053
+ { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 },
1054
+ { op_id: '7', op: 'PUT', object_id: 'test7', checksum: 2477637855 },
1055
+ { op_id: '8', op: 'PUT', object_id: 'test8', checksum: 3644033632 },
1056
+ { op_id: '9', op: 'PUT', object_id: 'test9', checksum: 1011055869 },
1057
+ { op_id: '10', op: 'PUT', object_id: 'test10', checksum: 1331456365 }
1058
+ ];
1059
+ expect(test_utils.getBatchData(batch[1])).toEqual(config.compressedBucketStorage ? global2Operations.slice(0, 4) : global2Operations.slice(0, 1));
1033
1060
  expect(test_utils.getBatchMeta(batch[0])).toEqual({
1034
1061
  after: '0',
1035
1062
  has_more: false,
@@ -1038,7 +1065,7 @@ bucket_definitions:
1038
1065
  expect(test_utils.getBatchMeta(batch[1])).toEqual({
1039
1066
  after: '0',
1040
1067
  has_more: true,
1041
- next_after: '5'
1068
+ next_after: config.compressedBucketStorage ? '5' : '2'
1042
1069
  });
1043
1070
  });
1044
1071
  test('batch has_more (2)', async () => {
@@ -1074,34 +1101,67 @@ bucket_definitions:
1074
1101
  test('batch has_more (3)', async () => {
1075
1102
  // 50 bytes is more than 1 row, less than 2 rows
1076
1103
  const { batch, global1Request, global2Request } = await setup({ limit: 3, chunkLimitBytes: 50 });
1077
- expect(batch.length).toEqual(3);
1078
- expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1079
- expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1080
- expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1081
- expect(test_utils.getBatchData(batch[0])).toEqual([
1082
- { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1083
- ]);
1084
- expect(test_utils.getBatchData(batch[1])).toEqual([
1085
- { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1086
- ]);
1087
- expect(test_utils.getBatchData(batch[2])).toEqual([
1088
- { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1089
- ]);
1090
- expect(test_utils.getBatchMeta(batch[0])).toEqual({
1091
- after: '0',
1092
- has_more: false,
1093
- next_after: '1'
1094
- });
1095
- expect(test_utils.getBatchMeta(batch[1])).toEqual({
1096
- after: '0',
1097
- has_more: true,
1098
- next_after: '2'
1099
- });
1100
- expect(test_utils.getBatchMeta(batch[2])).toEqual({
1101
- after: '2',
1102
- has_more: true,
1103
- next_after: '3'
1104
- });
1104
+ if (config.compressedBucketStorage) {
1105
+ // In v3+, ops in the same bucket share a document. Once hydrated, the entire document is yielded even
1106
+ // when it exceeds the byte limit; the byte limit controls whether another document is fetched.
1107
+ expect(batch.length).toEqual(2);
1108
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1109
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1110
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1111
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1112
+ ]);
1113
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1114
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1115
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 },
1116
+ { op_id: '4', op: 'PUT', object_id: 'test4', checksum: 2049153252 },
1117
+ { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
1118
+ { op_id: '6', op: 'PUT', object_id: 'test6', checksum: 1974820016 },
1119
+ { op_id: '7', op: 'PUT', object_id: 'test7', checksum: 2477637855 },
1120
+ { op_id: '8', op: 'PUT', object_id: 'test8', checksum: 3644033632 },
1121
+ { op_id: '9', op: 'PUT', object_id: 'test9', checksum: 1011055869 },
1122
+ { op_id: '10', op: 'PUT', object_id: 'test10', checksum: 1331456365 }
1123
+ ]);
1124
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1125
+ after: '0',
1126
+ has_more: false,
1127
+ next_after: '1'
1128
+ });
1129
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1130
+ after: '0',
1131
+ has_more: false,
1132
+ next_after: '10'
1133
+ });
1134
+ }
1135
+ else {
1136
+ expect(batch.length).toBeGreaterThanOrEqual(3);
1137
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1138
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1139
+ expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1140
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1141
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1142
+ ]);
1143
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1144
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1145
+ ]);
1146
+ expect(test_utils.getBatchData(batch[2])).toEqual([
1147
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1148
+ ]);
1149
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1150
+ after: '0',
1151
+ has_more: false,
1152
+ next_after: '1'
1153
+ });
1154
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1155
+ after: '0',
1156
+ has_more: true,
1157
+ next_after: '2'
1158
+ });
1159
+ expect(test_utils.getBatchMeta(batch[2])).toEqual({
1160
+ after: '2',
1161
+ has_more: true,
1162
+ next_after: '3'
1163
+ });
1164
+ }
1105
1165
  });
1106
1166
  });
1107
1167
  test('empty storage metrics', async () => {
@@ -1125,7 +1185,7 @@ bucket_definitions:
1125
1185
  // but large enough in size to be split over multiple returned chunks.
1126
1186
  // Similar to the above test, but splits over 1MB chunks.
1127
1187
  await using factory = await generateStorageFactory();
1128
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1188
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1129
1189
  bucket_definitions:
1130
1190
  global:
1131
1191
  data:
@@ -1134,7 +1194,7 @@ bucket_definitions:
1134
1194
  `, {
1135
1195
  storageVersion
1136
1196
  }));
1137
- const bucketStorage = factory.getInstance(syncRules);
1197
+ const bucketStorage = factory.getInstance(replicationStream);
1138
1198
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1139
1199
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, 1);
1140
1200
  const sourceTableIgnore = await test_utils.resolveTestTable(writer, 'test_ignore', ['id'], config, 2);
@@ -1166,7 +1226,7 @@ bucket_definitions:
1166
1226
  });
1167
1227
  test('unchanged checksums', async () => {
1168
1228
  await using factory = await generateStorageFactory();
1169
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1229
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1170
1230
  bucket_definitions:
1171
1231
  global:
1172
1232
  data:
@@ -1174,7 +1234,7 @@ bucket_definitions:
1174
1234
  `, {
1175
1235
  storageVersion
1176
1236
  }));
1177
- const bucketStorage = factory.getInstance(syncRules);
1237
+ const bucketStorage = factory.getInstance(replicationStream);
1178
1238
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1179
1239
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1180
1240
  await writer.markAllSnapshotDone('1/1');
@@ -1188,23 +1248,25 @@ bucket_definitions:
1188
1248
  afterReplicaId: test_utils.rid('test1')
1189
1249
  });
1190
1250
  await writer.commit('1/1');
1191
- const { checkpoint } = await bucketStorage.getCheckpoint();
1251
+ const checkpoint = await bucketStorage.getCheckpoint();
1192
1252
  const request = bucketRequest(syncRules, 'global[]');
1193
1253
  const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
1194
1254
  expect(checksums).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1195
- const checksums2 = [...(await bucketStorage.getChecksums(checkpoint + 1n, [request])).values()];
1255
+ const checksums2 = [
1256
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint.checkpoint + 1n), [request])).values()
1257
+ ];
1196
1258
  expect(checksums2).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1197
1259
  });
1198
1260
  testChecksumBatching(config);
1199
1261
  test('empty checkpoints (1)', async () => {
1200
1262
  await using factory = await generateStorageFactory();
1201
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1263
+ const { stream: replicationStream } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1202
1264
  bucket_definitions:
1203
1265
  global:
1204
1266
  data:
1205
1267
  - SELECT id, description FROM "%"
1206
1268
  `, { storageVersion }));
1207
- const bucketStorage = factory.getInstance(syncRules);
1269
+ const bucketStorage = factory.getInstance(replicationStream);
1208
1270
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1209
1271
  await writer.markAllSnapshotDone('1/1');
1210
1272
  await writer.commit('1/1');
@@ -1224,7 +1286,7 @@ bucket_definitions:
1224
1286
  });
1225
1287
  test('empty checkpoints (2)', async () => {
1226
1288
  await using factory = await generateStorageFactory();
1227
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1289
+ const { stream: replicationStream } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1228
1290
  bucket_definitions:
1229
1291
  global:
1230
1292
  data:
@@ -1232,7 +1294,7 @@ bucket_definitions:
1232
1294
  `, {
1233
1295
  storageVersion
1234
1296
  }));
1235
- const bucketStorage = factory.getInstance(syncRules);
1297
+ const bucketStorage = factory.getInstance(replicationStream);
1236
1298
  await using writer1 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1237
1299
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1238
1300
  const sourceTable = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
@@ -1263,7 +1325,7 @@ bucket_definitions:
1263
1325
  });
1264
1326
  test('empty checkpoints (sync rule activation)', async () => {
1265
1327
  await using factory = await generateStorageFactory();
1266
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1328
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1267
1329
  bucket_definitions:
1268
1330
  global:
1269
1331
  data:
@@ -1271,7 +1333,7 @@ bucket_definitions:
1271
1333
  `, {
1272
1334
  storageVersion
1273
1335
  }));
1274
- const bucketStorage = factory.getInstance(syncRules);
1336
+ const bucketStorage = factory.getInstance(replicationStream);
1275
1337
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1276
1338
  const result1 = await writer.commit('1/1', { createEmptyCheckpoints: false });
1277
1339
  expect(result1).toEqual({ checkpointBlocked: true, checkpointCreated: false });
@@ -1290,8 +1352,8 @@ bucket_definitions:
1290
1352
  // Now, the checkpoint should advance the sync rules active.
1291
1353
  const cp2 = await bucketStorage.getCheckpoint();
1292
1354
  expect(cp2.lsn).toEqual('3/1');
1293
- const activeSyncRules = await factory.getActiveSyncRulesContent();
1294
- expect(activeSyncRules?.id).toEqual(syncRules.id);
1355
+ const activeSyncRules = await factory.getActiveSyncConfig();
1356
+ expect(activeSyncRules?.content.replicationStreamId).toEqual(syncRules.replicationStreamId);
1295
1357
  // At this point, it should be a truely empty checkpoint
1296
1358
  const result4 = await writer.commit('4/1', { createEmptyCheckpoints: false });
1297
1359
  expect(result4).toEqual({ checkpointBlocked: false, checkpointCreated: false });
@@ -1301,7 +1363,7 @@ bucket_definitions:
1301
1363
  });
1302
1364
  test.runIf(storageVersion >= 3)('deleting while streaming', async () => {
1303
1365
  await using factory = await generateStorageFactory();
1304
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1366
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1305
1367
  bucket_definitions:
1306
1368
  global:
1307
1369
  data:
@@ -1309,7 +1371,7 @@ bucket_definitions:
1309
1371
  `, {
1310
1372
  storageVersion
1311
1373
  }));
1312
- const bucketStorage = factory.getInstance(syncRules);
1374
+ const bucketStorage = factory.getInstance(replicationStream);
1313
1375
  await using snapshotWriter = await bucketStorage.createWriter({
1314
1376
  ...test_utils.BATCH_OPTIONS,
1315
1377
  skipExistingRows: true
@@ -1344,7 +1406,7 @@ bucket_definitions:
1344
1406
  await streamingWriter.keepalive('3/1');
1345
1407
  const cp = await bucketStorage.getCheckpoint();
1346
1408
  expect(cp.lsn).toEqual('3/1');
1347
- const data = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(cp.checkpoint, [bucketRequest(syncRules, 'global[]')]));
1409
+ const data = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(cp, [bucketRequest(syncRules, 'global[]')]));
1348
1410
  expect(data).toEqual([]);
1349
1411
  });
1350
1412
  }
@@ -1357,7 +1419,7 @@ export function testChecksumBatching(config) {
1357
1419
  const storageVersion = config.storageVersion ?? CURRENT_STORAGE_VERSION;
1358
1420
  test('checksums for multiple buckets', async () => {
1359
1421
  await using factory = await config.factory();
1360
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1422
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1361
1423
  bucket_definitions:
1362
1424
  user:
1363
1425
  parameters: select request.user_id() as user_id
@@ -1366,7 +1428,7 @@ bucket_definitions:
1366
1428
  `, {
1367
1429
  storageVersion
1368
1430
  }));
1369
- const bucketStorage = factory.getInstance(syncRules);
1431
+ const bucketStorage = factory.getInstance(replicationStream);
1370
1432
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1371
1433
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1372
1434
  await writer.markAllSnapshotDone('1/1');
@@ -1386,7 +1448,7 @@ bucket_definitions:
1386
1448
  }
1387
1449
  }
1388
1450
  await writer.commit('1/1');
1389
- const { checkpoint } = await bucketStorage.getCheckpoint();
1451
+ const checkpoint = await bucketStorage.getCheckpoint();
1390
1452
  bucketStorage.clearChecksumCache();
1391
1453
  const users = ['u1', 'u2', 'u3', 'u4'];
1392
1454
  const expectedChecksums = [346204588, 5261081, 134760718, -302639724];
@@ -1411,7 +1473,11 @@ streams:
1411
1473
  invalid:
1412
1474
  query: UPDATE test SET foo = 'bar' RETURNING *
1413
1475
  `));
1414
- const { errors } = deployed.parsed({ defaultSchema: 'ignored' }).syncConfigWithErrors;
1476
+ const [deployedContent] = deployed.syncConfigContent;
1477
+ expect(deployedContent).toBeDefined();
1478
+ const [deployedConfig] = deployedContent.parsed({ defaultSchema: 'ignored' }).syncConfigs;
1479
+ expect(deployedConfig).toBeDefined();
1480
+ const { errors } = deployedConfig;
1415
1481
  expect(errors).toHaveLength(1);
1416
1482
  expect(errors[0].message).toStrictEqual('Expected a SELECT statement');
1417
1483
  expect(errors[0].location).toStrictEqual({