@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.
- package/CHANGELOG.md +112 -4
- package/dist/test-utils/AbstractStreamTestContext.d.ts +7 -6
- package/dist/test-utils/AbstractStreamTestContext.js +28 -25
- package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
- package/dist/test-utils/StorageDataHelpers.d.ts +6 -5
- package/dist/test-utils/StorageDataHelpers.js +40 -2
- package/dist/test-utils/StorageDataHelpers.js.map +1 -1
- package/dist/test-utils/bucket-validation.d.ts +3 -3
- package/dist/test-utils/bucket-validation.js +3 -3
- package/dist/test-utils/general-utils.d.ts +16 -3
- package/dist/test-utils/general-utils.js +37 -4
- package/dist/test-utils/general-utils.js.map +1 -1
- package/dist/test-utils/storage-combinations.d.ts +13 -0
- package/dist/test-utils/storage-combinations.js +26 -0
- package/dist/test-utils/storage-combinations.js.map +1 -0
- package/dist/test-utils/stream_utils.d.ts +0 -1
- package/dist/test-utils/stream_utils.js +0 -10
- package/dist/test-utils/stream_utils.js.map +1 -1
- package/dist/test-utils/test-utils-index.d.ts +1 -0
- package/dist/test-utils/test-utils-index.js +1 -0
- package/dist/test-utils/test-utils-index.js.map +1 -1
- package/dist/tests/register-compacting-tests.js +36 -29
- package/dist/tests/register-compacting-tests.js.map +1 -1
- package/dist/tests/register-data-storage-checkpoint-tests.js +138 -14
- package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
- package/dist/tests/register-data-storage-data-tests.js +205 -138
- package/dist/tests/register-data-storage-data-tests.js.map +1 -1
- package/dist/tests/register-data-storage-parameter-tests.js +44 -42
- package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
- package/dist/tests/register-parameter-compacting-tests.js +3 -2
- package/dist/tests/register-parameter-compacting-tests.js.map +1 -1
- package/dist/tests/register-sync-tests.js +404 -86
- package/dist/tests/register-sync-tests.js.map +1 -1
- package/dist/tests/util.d.ts +8 -2
- package/dist/tests/util.js +12 -0
- package/dist/tests/util.js.map +1 -1
- package/package.json +5 -6
- package/src/test-utils/AbstractStreamTestContext.ts +31 -27
- package/src/test-utils/StorageDataHelpers.ts +52 -8
- package/src/test-utils/bucket-validation.ts +3 -3
- package/src/test-utils/general-utils.ts +62 -10
- package/src/test-utils/storage-combinations.ts +51 -0
- package/src/test-utils/stream_utils.ts +0 -11
- package/src/test-utils/test-utils-index.ts +1 -0
- package/src/tests/register-compacting-tests.ts +55 -32
- package/src/tests/register-data-storage-checkpoint-tests.ts +171 -14
- package/src/tests/register-data-storage-data-tests.ts +251 -150
- package/src/tests/register-data-storage-parameter-tests.ts +58 -42
- package/src/tests/register-parameter-compacting-tests.ts +3 -2
- package/src/tests/register-sync-tests.ts +443 -88
- package/src/tests/util.ts +15 -2
- package/tsconfig.json +1 -4
- 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
|
|
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(
|
|
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
|
|
55
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
56
56
|
const request = bucketRequest(syncRules, 'global[]');
|
|
57
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
108
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
109
109
|
const request = bucketRequest(syncRules, 'global[]');
|
|
110
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
162
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
163
163
|
const request = bucketRequest(syncRules, 'global[]');
|
|
164
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
212
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
213
213
|
const request = bucketRequest(syncRules, 'global[]');
|
|
214
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
284
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
285
285
|
const request = bucketRequest(syncRules, 'global[]');
|
|
286
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
343
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
393
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
394
394
|
const request = bucketRequest(syncRules, 'global[]');
|
|
395
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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
|
|
490
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
491
491
|
const request = bucketRequest(syncRules, 'global[]');
|
|
492
|
-
const batch = await test_utils.
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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(
|
|
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
|
|
953
|
+
const checkpoint = await bucketStorage.getCheckpoint();
|
|
953
954
|
const request = bucketRequest(syncRules, 'global[]');
|
|
954
|
-
const batch1 = await test_utils.
|
|
955
|
-
|
|
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
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
|
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(
|
|
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
|
|
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.
|
|
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
|
-
|
|
1021
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
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).
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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 = [
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
1294
|
-
expect(activeSyncRules?.
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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({
|