@powersync/service-core-tests 0.16.0 → 0.17.1

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 (36) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/test-utils/AbstractStreamTestContext.d.ts +6 -5
  3. package/dist/test-utils/AbstractStreamTestContext.js +26 -22
  4. package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
  5. package/dist/test-utils/StorageDataHelpers.d.ts +5 -5
  6. package/dist/test-utils/StorageDataHelpers.js.map +1 -1
  7. package/dist/test-utils/bucket-validation.d.ts +3 -3
  8. package/dist/test-utils/bucket-validation.js +3 -3
  9. package/dist/test-utils/general-utils.d.ts +13 -2
  10. package/dist/test-utils/general-utils.js +24 -3
  11. package/dist/test-utils/general-utils.js.map +1 -1
  12. package/dist/tests/register-compacting-tests.js +28 -21
  13. package/dist/tests/register-compacting-tests.js.map +1 -1
  14. package/dist/tests/register-data-storage-checkpoint-tests.js +8 -2
  15. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  16. package/dist/tests/register-data-storage-data-tests.js +148 -101
  17. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  18. package/dist/tests/register-data-storage-parameter-tests.js +44 -42
  19. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  20. package/dist/tests/register-sync-tests.js +141 -8
  21. package/dist/tests/register-sync-tests.js.map +1 -1
  22. package/dist/tests/util.d.ts +2 -2
  23. package/dist/tests/util.js.map +1 -1
  24. package/package.json +6 -7
  25. package/src/test-utils/AbstractStreamTestContext.ts +29 -24
  26. package/src/test-utils/StorageDataHelpers.ts +7 -6
  27. package/src/test-utils/bucket-validation.ts +3 -3
  28. package/src/test-utils/general-utils.ts +35 -7
  29. package/src/tests/register-compacting-tests.ts +45 -22
  30. package/src/tests/register-data-storage-checkpoint-tests.ts +12 -2
  31. package/src/tests/register-data-storage-data-tests.ts +210 -107
  32. package/src/tests/register-data-storage-parameter-tests.ts +58 -42
  33. package/src/tests/register-sync-tests.ts +159 -8
  34. package/src/tests/util.ts +2 -2
  35. package/tsconfig.json +1 -4
  36. package/tsconfig.tsbuildinfo +1 -1
@@ -38,7 +38,8 @@ export function registerDataStorageDataTests(config: storage.TestStorageConfig)
38
38
 
39
39
  test('removing row', async () => {
40
40
  await using factory = await generateStorageFactory();
41
- const syncRules = await factory.updateSyncRules(
41
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
42
+ factory,
42
43
  updateSyncRulesFromYaml(
43
44
  `
44
45
  bucket_definitions:
@@ -49,7 +50,7 @@ bucket_definitions:
49
50
  { storageVersion }
50
51
  )
51
52
  );
52
- const bucketStorage = factory.getInstance(syncRules);
53
+ const bucketStorage = factory.getInstance(replicationStream);
53
54
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
54
55
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
55
56
 
@@ -74,7 +75,9 @@ bucket_definitions:
74
75
  const { checkpoint } = await bucketStorage.getCheckpoint();
75
76
 
76
77
  const request = bucketRequest(syncRules, 'global[]');
77
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
78
+ const batch = await test_utils.fromAsync(
79
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
80
+ );
78
81
  const data = batch[0].chunkData.data.map((d) => {
79
82
  return {
80
83
  op: d.op,
@@ -91,7 +94,9 @@ bucket_definitions:
91
94
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
92
95
  ]);
93
96
 
94
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
97
+ const checksums = [
98
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
99
+ ];
95
100
  expect(checksums).toEqual([
96
101
  {
97
102
  bucket: request.bucket,
@@ -103,7 +108,8 @@ bucket_definitions:
103
108
 
104
109
  test('insert after delete in new batch', async () => {
105
110
  await using factory = await generateStorageFactory();
106
- const syncRules = await factory.updateSyncRules(
111
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
112
+ factory,
107
113
  updateSyncRulesFromYaml(
108
114
  `
109
115
  bucket_definitions:
@@ -114,7 +120,7 @@ bucket_definitions:
114
120
  { storageVersion }
115
121
  )
116
122
  );
117
- const bucketStorage = factory.getInstance(syncRules);
123
+ const bucketStorage = factory.getInstance(replicationStream);
118
124
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
119
125
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
120
126
  await writer.markAllSnapshotDone('1/1');
@@ -141,7 +147,9 @@ bucket_definitions:
141
147
  const { checkpoint } = await bucketStorage.getCheckpoint();
142
148
 
143
149
  const request = bucketRequest(syncRules, 'global[]');
144
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
150
+ const batch = await test_utils.fromAsync(
151
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
152
+ );
145
153
  const data = batch[0].chunkData.data.map((d) => {
146
154
  return {
147
155
  op: d.op,
@@ -154,7 +162,9 @@ bucket_definitions:
154
162
 
155
163
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
156
164
 
157
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
165
+ const checksums = [
166
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
167
+ ];
158
168
  expect(checksums).toEqual([
159
169
  {
160
170
  bucket: request.bucket,
@@ -167,7 +177,8 @@ bucket_definitions:
167
177
  test('update after delete in new batch', async () => {
168
178
  // Update after delete may not be common, but the storage layer should handle it in an eventually-consistent way.
169
179
  await using factory = await generateStorageFactory();
170
- const syncRules = await factory.updateSyncRules(
180
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
181
+ factory,
171
182
  updateSyncRulesFromYaml(
172
183
  `
173
184
  bucket_definitions:
@@ -178,7 +189,7 @@ bucket_definitions:
178
189
  { storageVersion }
179
190
  )
180
191
  );
181
- const bucketStorage = factory.getInstance(syncRules);
192
+ const bucketStorage = factory.getInstance(replicationStream);
182
193
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
183
194
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
184
195
  await writer.markAllSnapshotDone('1/1');
@@ -209,7 +220,9 @@ bucket_definitions:
209
220
  const { checkpoint } = await bucketStorage.getCheckpoint();
210
221
 
211
222
  const request = bucketRequest(syncRules, 'global[]');
212
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
223
+ const batch = await test_utils.fromAsync(
224
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
225
+ );
213
226
  const data = batch[0].chunkData.data.map((d) => {
214
227
  return {
215
228
  op: d.op,
@@ -222,7 +235,9 @@ bucket_definitions:
222
235
 
223
236
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
224
237
 
225
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
238
+ const checksums = [
239
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
240
+ ];
226
241
  expect(checksums).toEqual([
227
242
  {
228
243
  bucket: request.bucket,
@@ -234,7 +249,8 @@ bucket_definitions:
234
249
 
235
250
  test('insert after delete in same batch', async () => {
236
251
  await using factory = await generateStorageFactory();
237
- const syncRules = await factory.updateSyncRules(
252
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
253
+ factory,
238
254
  updateSyncRulesFromYaml(
239
255
  `
240
256
  bucket_definitions:
@@ -247,7 +263,7 @@ bucket_definitions:
247
263
  }
248
264
  )
249
265
  );
250
- const bucketStorage = factory.getInstance(syncRules);
266
+ const bucketStorage = factory.getInstance(replicationStream);
251
267
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
252
268
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
253
269
  await writer.markAllSnapshotDone('1/1');
@@ -271,7 +287,9 @@ bucket_definitions:
271
287
  const { checkpoint } = await bucketStorage.getCheckpoint();
272
288
 
273
289
  const request = bucketRequest(syncRules, 'global[]');
274
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
290
+ const batch = await test_utils.fromAsync(
291
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
292
+ );
275
293
  const data = batch[0].chunkData.data.map((d) => {
276
294
  return {
277
295
  op: d.op,
@@ -284,7 +302,9 @@ bucket_definitions:
284
302
 
285
303
  expect(data).toEqual([{ op: 'PUT', object_id: 'test1', checksum: c1 }]);
286
304
 
287
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
305
+ const checksums = [
306
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
307
+ ];
288
308
  expect(checksums).toEqual([
289
309
  {
290
310
  bucket: request.bucket,
@@ -296,7 +316,8 @@ bucket_definitions:
296
316
 
297
317
  test('(insert, delete, insert), (delete)', async () => {
298
318
  await using factory = await generateStorageFactory();
299
- const syncRules = await factory.updateSyncRules(
319
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
320
+ factory,
300
321
  updateSyncRulesFromYaml(
301
322
  `
302
323
  bucket_definitions:
@@ -309,7 +330,7 @@ bucket_definitions:
309
330
  }
310
331
  )
311
332
  );
312
- const bucketStorage = factory.getInstance(syncRules);
333
+ const bucketStorage = factory.getInstance(replicationStream);
313
334
  {
314
335
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
315
336
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -357,7 +378,9 @@ bucket_definitions:
357
378
  const { checkpoint } = await bucketStorage.getCheckpoint();
358
379
 
359
380
  const request = bucketRequest(syncRules, 'global[]');
360
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
381
+ const batch = await test_utils.fromAsync(
382
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
383
+ );
361
384
 
362
385
  expect(reduceBucket(batch[0].chunkData.data).slice(1)).toEqual([]);
363
386
 
@@ -374,7 +397,8 @@ bucket_definitions:
374
397
 
375
398
  test('changing client ids', async () => {
376
399
  await using factory = await generateStorageFactory();
377
- const syncRules = await factory.updateSyncRules(
400
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
401
+ factory,
378
402
  updateSyncRulesFromYaml(
379
403
  `
380
404
  bucket_definitions:
@@ -387,7 +411,7 @@ bucket_definitions:
387
411
  }
388
412
  )
389
413
  );
390
- const bucketStorage = factory.getInstance(syncRules);
414
+ const bucketStorage = factory.getInstance(replicationStream);
391
415
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
392
416
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
393
417
  await writer.markAllSnapshotDone('1/1');
@@ -426,7 +450,7 @@ bucket_definitions:
426
450
  await writer.commit('1/1');
427
451
  const { checkpoint } = await bucketStorage.getCheckpoint();
428
452
  const batch = await test_utils.fromAsync(
429
- bucketStorage.getBucketDataBatch(checkpoint, [bucketRequest(syncRules, 'global[]')])
453
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [bucketRequest(syncRules, 'global[]')])
430
454
  );
431
455
  const data = batch[0].chunkData.data.map((d) => {
432
456
  return {
@@ -445,7 +469,8 @@ bucket_definitions:
445
469
 
446
470
  test('re-apply delete', async () => {
447
471
  await using factory = await generateStorageFactory();
448
- const syncRules = await factory.updateSyncRules(
472
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
473
+ factory,
449
474
  updateSyncRulesFromYaml(
450
475
  `
451
476
  bucket_definitions:
@@ -458,7 +483,7 @@ bucket_definitions:
458
483
  }
459
484
  )
460
485
  );
461
- const bucketStorage = factory.getInstance(syncRules);
486
+ const bucketStorage = factory.getInstance(replicationStream);
462
487
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
463
488
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
464
489
  await writer.markAllSnapshotDone('1/1');
@@ -492,7 +517,9 @@ bucket_definitions:
492
517
  const { checkpoint } = await bucketStorage.getCheckpoint();
493
518
 
494
519
  const request = bucketRequest(syncRules, 'global[]');
495
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
520
+ const batch = await test_utils.fromAsync(
521
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
522
+ );
496
523
  const data = batch[0].chunkData.data.map((d) => {
497
524
  return {
498
525
  op: d.op,
@@ -509,7 +536,9 @@ bucket_definitions:
509
536
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
510
537
  ]);
511
538
 
512
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
539
+ const checksums = [
540
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
541
+ ];
513
542
  expect(checksums).toEqual([
514
543
  {
515
544
  bucket: bucketRequest(syncRules, 'global[]').bucket,
@@ -521,7 +550,8 @@ bucket_definitions:
521
550
 
522
551
  test('re-apply update + delete', async () => {
523
552
  await using factory = await generateStorageFactory();
524
- const syncRules = await factory.updateSyncRules(
553
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
554
+ factory,
525
555
  updateSyncRulesFromYaml(
526
556
  `
527
557
  bucket_definitions:
@@ -532,7 +562,7 @@ bucket_definitions:
532
562
  { storageVersion }
533
563
  )
534
564
  );
535
- const bucketStorage = factory.getInstance(syncRules);
565
+ const bucketStorage = factory.getInstance(replicationStream);
536
566
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
537
567
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
538
568
  await writer.markAllSnapshotDone('1/1');
@@ -611,7 +641,9 @@ bucket_definitions:
611
641
  const { checkpoint } = await bucketStorage.getCheckpoint();
612
642
 
613
643
  const request = bucketRequest(syncRules, 'global[]');
614
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
644
+ const batch = await test_utils.fromAsync(
645
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
646
+ );
615
647
 
616
648
  const data = batch[0].chunkData.data.map((d) => {
617
649
  return {
@@ -631,7 +663,9 @@ bucket_definitions:
631
663
  { op: 'REMOVE', object_id: 'test1', checksum: c2 }
632
664
  ]);
633
665
 
634
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
666
+ const checksums = [
667
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
668
+ ];
635
669
  expect(checksums).toEqual([
636
670
  {
637
671
  bucket: bucketRequest(syncRules, 'global[]').bucket,
@@ -651,7 +685,8 @@ bucket_definitions:
651
685
  // 2. Output order not being correct.
652
686
 
653
687
  await using factory = await generateStorageFactory();
654
- const syncRules = await factory.updateSyncRules(
688
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
689
+ factory,
655
690
  updateSyncRulesFromYaml(
656
691
  `
657
692
  bucket_definitions:
@@ -662,7 +697,7 @@ bucket_definitions:
662
697
  { storageVersion }
663
698
  )
664
699
  );
665
- const bucketStorage = factory.getInstance(syncRules);
700
+ const bucketStorage = factory.getInstance(replicationStream);
666
701
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
667
702
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
668
703
 
@@ -773,7 +808,9 @@ bucket_definitions:
773
808
  const checkpoint2 = result2!.flushed_op;
774
809
 
775
810
  const request = bucketRequest(syncRules, 'global[]', checkpoint1);
776
- const batch = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
811
+ const batch = await test_utils.fromAsync(
812
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint2), [request])
813
+ );
777
814
 
778
815
  const data = batch[0].chunkData.data.map((d) => {
779
816
  return {
@@ -810,7 +847,8 @@ bucket_definitions:
810
847
  ]);
811
848
  }
812
849
  await using factory = await generateStorageFactory();
813
- const syncRules = await factory.updateSyncRules(
850
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
851
+ factory,
814
852
  updateSyncRulesFromYaml(
815
853
  `
816
854
  bucket_definitions:
@@ -823,7 +861,7 @@ bucket_definitions:
823
861
  }
824
862
  )
825
863
  );
826
- const bucketStorage = factory.getInstance(syncRules);
864
+ const bucketStorage = factory.getInstance(replicationStream);
827
865
 
828
866
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
829
867
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
@@ -877,7 +915,7 @@ bucket_definitions:
877
915
 
878
916
  const request = bucketRequest(syncRules, 'global[]');
879
917
  const batch = await test_utils.fromAsync(
880
- bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }])
918
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }])
881
919
  );
882
920
  const data = batch[0].chunkData.data.map((d) => {
883
921
  return {
@@ -923,7 +961,8 @@ bucket_definitions:
923
961
  }
924
962
 
925
963
  await using factory = await generateStorageFactory();
926
- const syncRules = await factory.updateSyncRules(
964
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
965
+ factory,
927
966
  updateSyncRulesFromYaml(
928
967
  `
929
968
  bucket_definitions:
@@ -936,7 +975,7 @@ bucket_definitions:
936
975
  }
937
976
  )
938
977
  );
939
- const bucketStorage = factory.getInstance(syncRules);
978
+ const bucketStorage = factory.getInstance(replicationStream);
940
979
 
941
980
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
942
981
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id', 'description'], config);
@@ -990,7 +1029,7 @@ bucket_definitions:
990
1029
 
991
1030
  const request = bucketRequest(syncRules, 'global[]');
992
1031
  const batch = await test_utils.fromAsync(
993
- bucketStorage.getBucketDataBatch(checkpoint3, [{ ...request, start: checkpoint1 }])
1032
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint3), [{ ...request, start: checkpoint1 }])
994
1033
  );
995
1034
  const data = batch[0].chunkData.data.map((d) => {
996
1035
  return {
@@ -1026,7 +1065,8 @@ bucket_definitions:
1026
1065
  // The specific batch splits is an implementation detail of the storage driver,
1027
1066
  // and the test will have to updated when other implementations are added.
1028
1067
  await using factory = await generateStorageFactory();
1029
- const syncRules = await factory.updateSyncRules(
1068
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1069
+ factory,
1030
1070
  updateSyncRulesFromYaml(
1031
1071
  `
1032
1072
  bucket_definitions:
@@ -1039,7 +1079,7 @@ bucket_definitions:
1039
1079
  }
1040
1080
  )
1041
1081
  );
1042
- const bucketStorage = factory.getInstance(syncRules);
1082
+ const bucketStorage = factory.getInstance(replicationStream);
1043
1083
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1044
1084
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1045
1085
  await writer.markAllSnapshotDone('1/1');
@@ -1096,7 +1136,9 @@ bucket_definitions:
1096
1136
  };
1097
1137
 
1098
1138
  const request = bucketRequest(syncRules, 'global[]');
1099
- const batch1 = await test_utils.fromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], options));
1139
+ const batch1 = await test_utils.fromAsync(
1140
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request], options)
1141
+ );
1100
1142
  expect(test_utils.getBatchData(batch1)).toEqual([
1101
1143
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
1102
1144
  { op_id: '2', op: 'PUT', object_id: 'large1', checksum: 454746904 }
@@ -1109,7 +1151,7 @@ bucket_definitions:
1109
1151
 
1110
1152
  const batch2 = await test_utils.fromAsync(
1111
1153
  bucketStorage.getBucketDataBatch(
1112
- checkpoint,
1154
+ test_utils.testCheckpoint(checkpoint),
1113
1155
  [{ ...request, start: BigInt(batch1[0].chunkData.next_after) }],
1114
1156
  options
1115
1157
  )
@@ -1126,7 +1168,7 @@ bucket_definitions:
1126
1168
 
1127
1169
  const batch3 = await test_utils.fromAsync(
1128
1170
  bucketStorage.getBucketDataBatch(
1129
- checkpoint,
1171
+ test_utils.testCheckpoint(checkpoint),
1130
1172
  [{ ...request, start: BigInt(batch2[0].chunkData.next_after) }],
1131
1173
  options
1132
1174
  )
@@ -1138,7 +1180,8 @@ bucket_definitions:
1138
1180
  test('long batch', async () => {
1139
1181
  // Test syncing a batch of data that is limited by count.
1140
1182
  await using factory = await generateStorageFactory();
1141
- const syncRules = await factory.updateSyncRules(
1183
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1184
+ factory,
1142
1185
  updateSyncRulesFromYaml(
1143
1186
  `
1144
1187
  bucket_definitions:
@@ -1151,7 +1194,7 @@ bucket_definitions:
1151
1194
  }
1152
1195
  )
1153
1196
  );
1154
- const bucketStorage = factory.getInstance(syncRules);
1197
+ const bucketStorage = factory.getInstance(replicationStream);
1155
1198
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1156
1199
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1157
1200
  await writer.markAllSnapshotDone('1/1');
@@ -1173,7 +1216,9 @@ bucket_definitions:
1173
1216
  const { checkpoint } = await bucketStorage.getCheckpoint();
1174
1217
 
1175
1218
  const request = bucketRequest(syncRules, 'global[]');
1176
- const batch1 = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request], { limit: 4 }));
1219
+ const batch1 = await test_utils.oneFromAsync(
1220
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request], { limit: 4 })
1221
+ );
1177
1222
 
1178
1223
  expect(test_utils.getBatchData(batch1)).toEqual([
1179
1224
  { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 },
@@ -1189,9 +1234,13 @@ bucket_definitions:
1189
1234
  });
1190
1235
 
1191
1236
  const batch2 = await test_utils.oneFromAsync(
1192
- bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch1.chunkData.next_after) }], {
1193
- limit: 4
1194
- })
1237
+ bucketStorage.getBucketDataBatch(
1238
+ test_utils.testCheckpoint(checkpoint),
1239
+ [{ ...request, start: BigInt(batch1.chunkData.next_after) }],
1240
+ {
1241
+ limit: 4
1242
+ }
1243
+ )
1195
1244
  );
1196
1245
  expect(test_utils.getBatchData(batch2)).toEqual([
1197
1246
  { op_id: '5', op: 'PUT', object_id: 'test5', checksum: 3686902721 },
@@ -1205,9 +1254,13 @@ bucket_definitions:
1205
1254
  });
1206
1255
 
1207
1256
  const batch3 = await test_utils.fromAsync(
1208
- bucketStorage.getBucketDataBatch(checkpoint, [{ ...request, start: BigInt(batch2.chunkData.next_after) }], {
1209
- limit: 4
1210
- })
1257
+ bucketStorage.getBucketDataBatch(
1258
+ test_utils.testCheckpoint(checkpoint),
1259
+ [{ ...request, start: BigInt(batch2.chunkData.next_after) }],
1260
+ {
1261
+ limit: 4
1262
+ }
1263
+ )
1211
1264
  );
1212
1265
  expect(test_utils.getBatchData(batch3)).toEqual([]);
1213
1266
 
@@ -1217,7 +1270,8 @@ bucket_definitions:
1217
1270
  describe('batch has_more', () => {
1218
1271
  const setup = async (options: BucketDataBatchOptions) => {
1219
1272
  await using factory = await generateStorageFactory();
1220
- const syncRules = await factory.updateSyncRules(
1273
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1274
+ factory,
1221
1275
  updateSyncRulesFromYaml(
1222
1276
  `
1223
1277
  bucket_definitions:
@@ -1231,7 +1285,7 @@ bucket_definitions:
1231
1285
  { storageVersion }
1232
1286
  )
1233
1287
  );
1234
- const bucketStorage = factory.getInstance(syncRules);
1288
+ const bucketStorage = factory.getInstance(replicationStream);
1235
1289
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1236
1290
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1237
1291
  await writer.markAllSnapshotDone('1/1');
@@ -1255,7 +1309,11 @@ bucket_definitions:
1255
1309
  const global1Request = bucketRequest(syncRules, 'global1[]', 0n);
1256
1310
  const global2Request = bucketRequest(syncRules, 'global2[]', 0n);
1257
1311
  const batch = await test_utils.fromAsync(
1258
- bucketStorage.getBucketDataBatch(checkpoint, [global1Request, global2Request], options)
1312
+ bucketStorage.getBucketDataBatch(
1313
+ test_utils.testCheckpoint(checkpoint),
1314
+ [global1Request, global2Request],
1315
+ options
1316
+ )
1259
1317
  );
1260
1318
 
1261
1319
  return { batch, global1Request, global2Request };
@@ -1332,39 +1390,67 @@ bucket_definitions:
1332
1390
  // 50 bytes is more than 1 row, less than 2 rows
1333
1391
  const { batch, global1Request, global2Request } = await setup({ limit: 3, chunkLimitBytes: 50 });
1334
1392
 
1335
- expect(batch.length).toEqual(3);
1336
- expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1337
- expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1338
- expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1339
-
1340
- expect(test_utils.getBatchData(batch[0])).toEqual([
1341
- { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1342
- ]);
1343
-
1344
- expect(test_utils.getBatchData(batch[1])).toEqual([
1345
- { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1346
- ]);
1347
- expect(test_utils.getBatchData(batch[2])).toEqual([
1348
- { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1349
- ]);
1393
+ if (config.compressedBucketStorage) {
1394
+ // In v3+, ops in the same bucket share a document, so ops 2 and 3 (global2) are batched together
1395
+ expect(batch.length).toEqual(2);
1396
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1397
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1398
+
1399
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1400
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1401
+ ]);
1402
+
1403
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1404
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 },
1405
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1406
+ ]);
1407
+
1408
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1409
+ after: '0',
1410
+ has_more: false,
1411
+ next_after: '1'
1412
+ });
1350
1413
 
1351
- expect(test_utils.getBatchMeta(batch[0])).toEqual({
1352
- after: '0',
1353
- has_more: false,
1354
- next_after: '1'
1355
- });
1414
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1415
+ after: '0',
1416
+ has_more: true,
1417
+ next_after: '3'
1418
+ });
1419
+ } else {
1420
+ expect(batch.length).toEqual(3);
1421
+ expect(batch[0].chunkData.bucket).toEqual(global1Request.bucket);
1422
+ expect(batch[1].chunkData.bucket).toEqual(global2Request.bucket);
1423
+ expect(batch[2].chunkData.bucket).toEqual(global2Request.bucket);
1424
+
1425
+ expect(test_utils.getBatchData(batch[0])).toEqual([
1426
+ { op_id: '1', op: 'PUT', object_id: 'test1', checksum: 2871785649 }
1427
+ ]);
1428
+
1429
+ expect(test_utils.getBatchData(batch[1])).toEqual([
1430
+ { op_id: '2', op: 'PUT', object_id: 'test2', checksum: 730027011 }
1431
+ ]);
1432
+ expect(test_utils.getBatchData(batch[2])).toEqual([
1433
+ { op_id: '3', op: 'PUT', object_id: 'test3', checksum: 1359888332 }
1434
+ ]);
1435
+
1436
+ expect(test_utils.getBatchMeta(batch[0])).toEqual({
1437
+ after: '0',
1438
+ has_more: false,
1439
+ next_after: '1'
1440
+ });
1356
1441
 
1357
- expect(test_utils.getBatchMeta(batch[1])).toEqual({
1358
- after: '0',
1359
- has_more: true,
1360
- next_after: '2'
1361
- });
1442
+ expect(test_utils.getBatchMeta(batch[1])).toEqual({
1443
+ after: '0',
1444
+ has_more: true,
1445
+ next_after: '2'
1446
+ });
1362
1447
 
1363
- expect(test_utils.getBatchMeta(batch[2])).toEqual({
1364
- after: '2',
1365
- has_more: true,
1366
- next_after: '3'
1367
- });
1448
+ expect(test_utils.getBatchMeta(batch[2])).toEqual({
1449
+ after: '2',
1450
+ has_more: true,
1451
+ next_after: '3'
1452
+ });
1453
+ }
1368
1454
  });
1369
1455
  });
1370
1456
 
@@ -1392,7 +1478,8 @@ bucket_definitions:
1392
1478
  // but large enough in size to be split over multiple returned chunks.
1393
1479
  // Similar to the above test, but splits over 1MB chunks.
1394
1480
  await using factory = await generateStorageFactory();
1395
- const syncRules = await factory.updateSyncRules(
1481
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1482
+ factory,
1396
1483
  updateSyncRulesFromYaml(
1397
1484
  `
1398
1485
  bucket_definitions:
@@ -1406,7 +1493,7 @@ bucket_definitions:
1406
1493
  }
1407
1494
  )
1408
1495
  );
1409
- const bucketStorage = factory.getInstance(syncRules);
1496
+ const bucketStorage = factory.getInstance(replicationStream);
1410
1497
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1411
1498
 
1412
1499
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, 1);
@@ -1444,7 +1531,8 @@ bucket_definitions:
1444
1531
 
1445
1532
  test('unchanged checksums', async () => {
1446
1533
  await using factory = await generateStorageFactory();
1447
- const syncRules = await factory.updateSyncRules(
1534
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1535
+ factory,
1448
1536
  updateSyncRulesFromYaml(
1449
1537
  `
1450
1538
  bucket_definitions:
@@ -1457,7 +1545,7 @@ bucket_definitions:
1457
1545
  }
1458
1546
  )
1459
1547
  );
1460
- const bucketStorage = factory.getInstance(syncRules);
1548
+ const bucketStorage = factory.getInstance(replicationStream);
1461
1549
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1462
1550
 
1463
1551
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -1475,9 +1563,13 @@ bucket_definitions:
1475
1563
  const { checkpoint } = await bucketStorage.getCheckpoint();
1476
1564
 
1477
1565
  const request = bucketRequest(syncRules, 'global[]');
1478
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, [request])).values()];
1566
+ const checksums = [
1567
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request])).values()
1568
+ ];
1479
1569
  expect(checksums).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1480
- const checksums2 = [...(await bucketStorage.getChecksums(checkpoint + 1n, [request])).values()];
1570
+ const checksums2 = [
1571
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint + 1n), [request])).values()
1572
+ ];
1481
1573
  expect(checksums2).toEqual([{ bucket: request.bucket, checksum: 1917136889, count: 1 }]);
1482
1574
  });
1483
1575
 
@@ -1485,7 +1577,8 @@ bucket_definitions:
1485
1577
 
1486
1578
  test('empty checkpoints (1)', async () => {
1487
1579
  await using factory = await generateStorageFactory();
1488
- const syncRules = await factory.updateSyncRules(
1580
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1581
+ factory,
1489
1582
  updateSyncRulesFromYaml(
1490
1583
  `
1491
1584
  bucket_definitions:
@@ -1496,7 +1589,7 @@ bucket_definitions:
1496
1589
  { storageVersion }
1497
1590
  )
1498
1591
  );
1499
- const bucketStorage = factory.getInstance(syncRules);
1592
+ const bucketStorage = factory.getInstance(replicationStream);
1500
1593
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1501
1594
  await writer.markAllSnapshotDone('1/1');
1502
1595
  await writer.commit('1/1');
@@ -1521,7 +1614,8 @@ bucket_definitions:
1521
1614
 
1522
1615
  test('empty checkpoints (2)', async () => {
1523
1616
  await using factory = await generateStorageFactory();
1524
- const syncRules = await factory.updateSyncRules(
1617
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1618
+ factory,
1525
1619
  updateSyncRulesFromYaml(
1526
1620
  `
1527
1621
  bucket_definitions:
@@ -1534,7 +1628,7 @@ bucket_definitions:
1534
1628
  }
1535
1629
  )
1536
1630
  );
1537
- const bucketStorage = factory.getInstance(syncRules);
1631
+ const bucketStorage = factory.getInstance(replicationStream);
1538
1632
  await using writer1 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1539
1633
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1540
1634
  const sourceTable = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
@@ -1571,7 +1665,8 @@ bucket_definitions:
1571
1665
 
1572
1666
  test('empty checkpoints (sync rule activation)', async () => {
1573
1667
  await using factory = await generateStorageFactory();
1574
- const syncRules = await factory.updateSyncRules(
1668
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1669
+ factory,
1575
1670
  updateSyncRulesFromYaml(
1576
1671
  `
1577
1672
  bucket_definitions:
@@ -1584,7 +1679,7 @@ bucket_definitions:
1584
1679
  }
1585
1680
  )
1586
1681
  );
1587
- const bucketStorage = factory.getInstance(syncRules);
1682
+ const bucketStorage = factory.getInstance(replicationStream);
1588
1683
 
1589
1684
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1590
1685
  const result1 = await writer.commit('1/1', { createEmptyCheckpoints: false });
@@ -1609,8 +1704,8 @@ bucket_definitions:
1609
1704
  const cp2 = await bucketStorage.getCheckpoint();
1610
1705
  expect(cp2.lsn).toEqual('3/1');
1611
1706
 
1612
- const activeSyncRules = await factory.getActiveSyncRulesContent();
1613
- expect(activeSyncRules?.id).toEqual(syncRules.id);
1707
+ const activeSyncRules = await factory.getActiveSyncConfig();
1708
+ expect(activeSyncRules?.content.replicationStreamId).toEqual(syncRules.replicationStreamId);
1614
1709
 
1615
1710
  // At this point, it should be a truely empty checkpoint
1616
1711
  const result4 = await writer.commit('4/1', { createEmptyCheckpoints: false });
@@ -1623,7 +1718,8 @@ bucket_definitions:
1623
1718
 
1624
1719
  test.runIf(storageVersion >= 3)('deleting while streaming', async () => {
1625
1720
  await using factory = await generateStorageFactory();
1626
- const syncRules = await factory.updateSyncRules(
1721
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1722
+ factory,
1627
1723
  updateSyncRulesFromYaml(
1628
1724
  `
1629
1725
  bucket_definitions:
@@ -1636,7 +1732,7 @@ bucket_definitions:
1636
1732
  }
1637
1733
  )
1638
1734
  );
1639
- const bucketStorage = factory.getInstance(syncRules);
1735
+ const bucketStorage = factory.getInstance(replicationStream);
1640
1736
  await using snapshotWriter = await bucketStorage.createWriter({
1641
1737
  ...test_utils.BATCH_OPTIONS,
1642
1738
  skipExistingRows: true
@@ -1676,7 +1772,7 @@ bucket_definitions:
1676
1772
  const cp = await bucketStorage.getCheckpoint();
1677
1773
  expect(cp.lsn).toEqual('3/1');
1678
1774
  const data = await test_utils.fromAsync(
1679
- bucketStorage.getBucketDataBatch(cp.checkpoint, [bucketRequest(syncRules, 'global[]')])
1775
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(cp.checkpoint), [bucketRequest(syncRules, 'global[]')])
1680
1776
  );
1681
1777
 
1682
1778
  expect(data).toEqual([]);
@@ -1692,7 +1788,8 @@ export function testChecksumBatching(config: storage.TestStorageConfig) {
1692
1788
  const storageVersion = config.storageVersion ?? CURRENT_STORAGE_VERSION;
1693
1789
  test('checksums for multiple buckets', async () => {
1694
1790
  await using factory = await config.factory();
1695
- const syncRules = await factory.updateSyncRules(
1791
+ const { stream: replicationStream, content: syncRules } = await test_utils.deploySyncRules(
1792
+ factory,
1696
1793
  updateSyncRulesFromYaml(
1697
1794
  `
1698
1795
  bucket_definitions:
@@ -1706,7 +1803,7 @@ bucket_definitions:
1706
1803
  }
1707
1804
  )
1708
1805
  );
1709
- const bucketStorage = factory.getInstance(syncRules);
1806
+ const bucketStorage = factory.getInstance(replicationStream);
1710
1807
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
1711
1808
  const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
1712
1809
  await writer.markAllSnapshotDone('1/1');
@@ -1732,7 +1829,9 @@ bucket_definitions:
1732
1829
  const users = ['u1', 'u2', 'u3', 'u4'];
1733
1830
  const expectedChecksums = [346204588, 5261081, 134760718, -302639724];
1734
1831
  const bucketRequests = users.map((user) => bucketRequest(syncRules, `user["${user}"]`));
1735
- const checksums = [...(await bucketStorage.getChecksums(checkpoint, bucketRequests)).values()];
1832
+ const checksums = [
1833
+ ...(await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), bucketRequests)).values()
1834
+ ];
1736
1835
  checksums.sort((a, b) => a.bucket.localeCompare(b.bucket));
1737
1836
  const expected = bucketRequests.map((request, index) => ({
1738
1837
  bucket: request.bucket,
@@ -1756,7 +1855,11 @@ streams:
1756
1855
  `)
1757
1856
  );
1758
1857
 
1759
- const { errors } = deployed.parsed({ defaultSchema: 'ignored' }).syncConfigWithErrors;
1858
+ const [deployedContent] = deployed.syncConfigContent;
1859
+ expect(deployedContent).toBeDefined();
1860
+ const [deployedConfig] = deployedContent.parsed({ defaultSchema: 'ignored' }).syncConfigs;
1861
+ expect(deployedConfig).toBeDefined();
1862
+ const { errors } = deployedConfig;
1760
1863
  expect(errors).toHaveLength(1);
1761
1864
  expect(errors[0].message).toStrictEqual('Expected a SELECT statement');
1762
1865
  expect(errors[0].location).toStrictEqual({