@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
@@ -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,43 +1101,77 @@ 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 () => {
1108
1168
  await using f = await generateStorageFactory({ dropAll: true });
1109
1169
  const metrics = await f.getStorageMetrics();
1110
- expect(metrics).toEqual({
1170
+ expect(metrics).toMatchObject({
1111
1171
  operations_size_bytes: 0,
1112
1172
  parameters_size_bytes: 0,
1113
- replication_size_bytes: 0
1173
+ replication_size_bytes: 0,
1174
+ object_storage_size_bytes: 0
1114
1175
  });
1115
1176
  const r = await f.configureSyncRules(updateSyncRulesFromYaml('bucket_definitions: {}'));
1116
1177
  const storage = f.getInstance(r.persisted_sync_rules);
@@ -1125,7 +1186,7 @@ bucket_definitions:
1125
1186
  // but large enough in size to be split over multiple returned chunks.
1126
1187
  // Similar to the above test, but splits over 1MB chunks.
1127
1188
  await using factory = await generateStorageFactory();
1128
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1189
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1129
1190
  bucket_definitions:
1130
1191
  global:
1131
1192
  data:
@@ -1134,7 +1195,7 @@ bucket_definitions:
1134
1195
  `, {
1135
1196
  storageVersion
1136
1197
  }));
1137
- const bucketStorage = factory.getInstance(syncRules);
1198
+ const bucketStorage = factory.getInstance(replicationStream);
1138
1199
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1139
1200
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, 1);
1140
1201
  const sourceTableIgnore = await test_utils.resolveTestTable(writer, 'test_ignore', ['id'], config, 2);
@@ -1166,7 +1227,7 @@ bucket_definitions:
1166
1227
  });
1167
1228
  test('unchanged checksums', async () => {
1168
1229
  await using factory = await generateStorageFactory();
1169
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1230
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1170
1231
  bucket_definitions:
1171
1232
  global:
1172
1233
  data:
@@ -1174,7 +1235,7 @@ bucket_definitions:
1174
1235
  `, {
1175
1236
  storageVersion
1176
1237
  }));
1177
- const bucketStorage = factory.getInstance(syncRules);
1238
+ const bucketStorage = factory.getInstance(replicationStream);
1178
1239
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1179
1240
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1180
1241
  await writer.markAllSnapshotDone('1/1');
@@ -1188,23 +1249,25 @@ bucket_definitions:
1188
1249
  afterReplicaId: test_utils.rid('test1')
1189
1250
  });
1190
1251
  await writer.commit('1/1');
1191
- const { checkpoint } = await bucketStorage.getCheckpoint();
1252
+ const checkpoint = await bucketStorage.getCheckpoint();
1192
1253
  const request = bucketRequest(syncRules, 'global[]');
1193
1254
  const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
1194
1255
  expect(checksums).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1195
- const checksums2 = [...(await bucketStorage.getChecksums(checkpoint + 1n, [request])).values()];
1256
+ const checksums2 = [
1257
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint.checkpoint + 1n), [request])).values()
1258
+ ];
1196
1259
  expect(checksums2).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1197
1260
  });
1198
1261
  testChecksumBatching(config);
1199
1262
  test('empty checkpoints (1)', async () => {
1200
1263
  await using factory = await generateStorageFactory();
1201
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1264
+ const { stream: replicationStream } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1202
1265
  bucket_definitions:
1203
1266
  global:
1204
1267
  data:
1205
1268
  - SELECT id, description FROM "%"
1206
1269
  `, { storageVersion }));
1207
- const bucketStorage = factory.getInstance(syncRules);
1270
+ const bucketStorage = factory.getInstance(replicationStream);
1208
1271
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1209
1272
  await writer.markAllSnapshotDone('1/1');
1210
1273
  await writer.commit('1/1');
@@ -1224,7 +1287,7 @@ bucket_definitions:
1224
1287
  });
1225
1288
  test('empty checkpoints (2)', async () => {
1226
1289
  await using factory = await generateStorageFactory();
1227
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1290
+ const { stream: replicationStream } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1228
1291
  bucket_definitions:
1229
1292
  global:
1230
1293
  data:
@@ -1232,7 +1295,7 @@ bucket_definitions:
1232
1295
  `, {
1233
1296
  storageVersion
1234
1297
  }));
1235
- const bucketStorage = factory.getInstance(syncRules);
1298
+ const bucketStorage = factory.getInstance(replicationStream);
1236
1299
  await using writer1 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1237
1300
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1238
1301
  const sourceTable = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
@@ -1263,7 +1326,7 @@ bucket_definitions:
1263
1326
  });
1264
1327
  test('empty checkpoints (sync rule activation)', async () => {
1265
1328
  await using factory = await generateStorageFactory();
1266
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1329
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1267
1330
  bucket_definitions:
1268
1331
  global:
1269
1332
  data:
@@ -1271,7 +1334,7 @@ bucket_definitions:
1271
1334
  `, {
1272
1335
  storageVersion
1273
1336
  }));
1274
- const bucketStorage = factory.getInstance(syncRules);
1337
+ const bucketStorage = factory.getInstance(replicationStream);
1275
1338
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1276
1339
  const result1 = await writer.commit('1/1', { createEmptyCheckpoints: false });
1277
1340
  expect(result1).toEqual({ checkpointBlocked: true, checkpointCreated: false });
@@ -1290,8 +1353,8 @@ bucket_definitions:
1290
1353
  // Now, the checkpoint should advance the sync rules active.
1291
1354
  const cp2 = await bucketStorage.getCheckpoint();
1292
1355
  expect(cp2.lsn).toEqual('3/1');
1293
- const activeSyncRules = await factory.getActiveSyncRulesContent();
1294
- expect(activeSyncRules?.id).toEqual(syncRules.id);
1356
+ const activeSyncRules = await factory.getActiveSyncConfig();
1357
+ expect(activeSyncRules?.content.replicationStreamId).toEqual(syncRules.replicationStreamId);
1295
1358
  // At this point, it should be a truely empty checkpoint
1296
1359
  const result4 = await writer.commit('4/1', { createEmptyCheckpoints: false });
1297
1360
  expect(result4).toEqual({ checkpointBlocked: false, checkpointCreated: false });
@@ -1301,7 +1364,7 @@ bucket_definitions:
1301
1364
  });
1302
1365
  test.runIf(storageVersion >= 3)('deleting while streaming', async () => {
1303
1366
  await using factory = await generateStorageFactory();
1304
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1367
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1305
1368
  bucket_definitions:
1306
1369
  global:
1307
1370
  data:
@@ -1309,7 +1372,7 @@ bucket_definitions:
1309
1372
  `, {
1310
1373
  storageVersion
1311
1374
  }));
1312
- const bucketStorage = factory.getInstance(syncRules);
1375
+ const bucketStorage = factory.getInstance(replicationStream);
1313
1376
  await using snapshotWriter = await bucketStorage.createWriter({
1314
1377
  ...test_utils.BATCH_OPTIONS,
1315
1378
  skipExistingRows: true
@@ -1344,7 +1407,7 @@ bucket_definitions:
1344
1407
  await streamingWriter.keepalive('3/1');
1345
1408
  const cp = await bucketStorage.getCheckpoint();
1346
1409
  expect(cp.lsn).toEqual('3/1');
1347
- const data = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(cp.checkpoint, [bucketRequest(syncRules, 'global[]')]));
1410
+ const data = await test_utils.getBatchArray(bucketStorage.getBucketDataBatch(cp, [bucketRequest(syncRules, 'global[]')]));
1348
1411
  expect(data).toEqual([]);
1349
1412
  });
1350
1413
  }
@@ -1357,7 +1420,7 @@ export function testChecksumBatching(config) {
1357
1420
  const storageVersion = config.storageVersion ?? CURRENT_STORAGE_VERSION;
1358
1421
  test('checksums for multiple buckets', async () => {
1359
1422
  await using factory = await config.factory();
1360
- const syncRules = await factory.updateSyncRules(updateSyncRulesFromYaml(`
1423
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(factory, updateSyncRulesFromYaml(`
1361
1424
  bucket_definitions:
1362
1425
  user:
1363
1426
  parameters: select request.user_id() as user_id
@@ -1366,7 +1429,7 @@ bucket_definitions:
1366
1429
  `, {
1367
1430
  storageVersion
1368
1431
  }));
1369
- const bucketStorage = factory.getInstance(syncRules);
1432
+ const bucketStorage = factory.getInstance(replicationStream);
1370
1433
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1371
1434
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1372
1435
  await writer.markAllSnapshotDone('1/1');
@@ -1386,7 +1449,7 @@ bucket_definitions:
1386
1449
  }
1387
1450
  }
1388
1451
  await writer.commit('1/1');
1389
- const { checkpoint } = await bucketStorage.getCheckpoint();
1452
+ const checkpoint = await bucketStorage.getCheckpoint();
1390
1453
  bucketStorage.clearChecksumCache();
1391
1454
  const users = ['u1', 'u2', 'u3', 'u4'];
1392
1455
  const expectedChecksums = [346204588, 5261081, 134760718, -302639724];
@@ -1411,7 +1474,11 @@ streams:
1411
1474
  invalid:
1412
1475
  query: UPDATE test SET foo = 'bar' RETURNING *
1413
1476
  `));
1414
- const { errors } = deployed.parsed({ defaultSchema: 'ignored' }).syncConfigWithErrors;
1477
+ const [deployedContent] = deployed.syncConfigContent;
1478
+ expect(deployedContent).toBeDefined();
1479
+ const [deployedConfig] = deployedContent.parsed({ defaultSchema: 'ignored' }).syncConfigs;
1480
+ expect(deployedConfig).toBeDefined();
1481
+ const { errors } = deployedConfig;
1415
1482
  expect(errors).toHaveLength(1);
1416
1483
  expect(errors[0].message).toStrictEqual('Expected a SELECT statement');
1417
1484
  expect(errors[0].location).toStrictEqual({