@powersync/service-core-tests 0.14.0 → 0.15.0
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 +19 -0
- package/dist/test-utils/general-utils.d.ts +9 -2
- package/dist/test-utils/general-utils.js +26 -2
- package/dist/test-utils/general-utils.js.map +1 -1
- package/dist/tests/register-compacting-tests.d.ts +1 -1
- package/dist/tests/register-compacting-tests.js +122 -68
- package/dist/tests/register-compacting-tests.js.map +1 -1
- package/dist/tests/register-data-storage-checkpoint-tests.d.ts +1 -1
- package/dist/tests/register-data-storage-checkpoint-tests.js +38 -6
- package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
- package/dist/tests/register-data-storage-data-tests.d.ts +2 -2
- package/dist/tests/register-data-storage-data-tests.js +666 -142
- package/dist/tests/register-data-storage-data-tests.js.map +1 -1
- package/dist/tests/register-data-storage-parameter-tests.d.ts +1 -1
- package/dist/tests/register-data-storage-parameter-tests.js +60 -33
- package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
- package/dist/tests/register-parameter-compacting-tests.d.ts +1 -1
- package/dist/tests/register-parameter-compacting-tests.js +8 -4
- package/dist/tests/register-parameter-compacting-tests.js.map +1 -1
- package/dist/tests/register-sync-tests.d.ts +2 -1
- package/dist/tests/register-sync-tests.js +40 -18
- package/dist/tests/register-sync-tests.js.map +1 -1
- package/dist/tests/util.d.ts +5 -4
- package/dist/tests/util.js +27 -12
- package/dist/tests/util.js.map +1 -1
- package/package.json +3 -3
- package/src/test-utils/general-utils.ts +41 -3
- package/src/tests/register-compacting-tests.ts +127 -82
- package/src/tests/register-data-storage-checkpoint-tests.ts +64 -11
- package/src/tests/register-data-storage-data-tests.ts +640 -52
- package/src/tests/register-data-storage-parameter-tests.ts +101 -47
- package/src/tests/register-parameter-compacting-tests.ts +9 -4
- package/src/tests/register-sync-tests.ts +45 -19
- package/src/tests/util.ts +46 -17
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { storage, utils } from '@powersync/service-core';
|
|
1
|
+
import { BucketDataRequest, InternalOpId, storage, utils } from '@powersync/service-core';
|
|
2
2
|
import { GetQuerierOptions, RequestParameters } from '@powersync/service-sync-rules';
|
|
3
3
|
import * as bson from 'bson';
|
|
4
4
|
|
|
@@ -14,9 +14,14 @@ export const BATCH_OPTIONS: storage.StartBatchOptions = {
|
|
|
14
14
|
storeCurrentData: true
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export function makeTestTable(
|
|
17
|
+
export function makeTestTable(
|
|
18
|
+
name: string,
|
|
19
|
+
replicaIdColumns?: string[] | undefined,
|
|
20
|
+
options?: { tableIdStrings: boolean }
|
|
21
|
+
) {
|
|
18
22
|
const relId = utils.hashData('table', name, (replicaIdColumns ?? ['id']).join(','));
|
|
19
|
-
const id =
|
|
23
|
+
const id =
|
|
24
|
+
options?.tableIdStrings == false ? new bson.ObjectId('6544e3899293153fa7b38331') : '6544e3899293153fa7b38331';
|
|
20
25
|
return new storage.SourceTable({
|
|
21
26
|
id: id,
|
|
22
27
|
connectionTag: storage.SourceTable.DEFAULT_TAG,
|
|
@@ -45,6 +50,39 @@ export function getBatchData(
|
|
|
45
50
|
});
|
|
46
51
|
}
|
|
47
52
|
|
|
53
|
+
function isParsedSyncRules(
|
|
54
|
+
syncRules: storage.PersistedSyncRulesContent | storage.PersistedSyncRules
|
|
55
|
+
): syncRules is storage.PersistedSyncRules {
|
|
56
|
+
return (syncRules as storage.PersistedSyncRules).sync_rules !== undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Bucket names no longer purely depend on the sync rules.
|
|
61
|
+
* This converts a bucket name like "global[]" into the actual bucket name, for use in tests.
|
|
62
|
+
*/
|
|
63
|
+
export function bucketRequest(
|
|
64
|
+
syncRules: storage.PersistedSyncRulesContent | storage.PersistedSyncRules,
|
|
65
|
+
bucket: string,
|
|
66
|
+
start?: InternalOpId | string | number
|
|
67
|
+
): BucketDataRequest {
|
|
68
|
+
const parsed = isParsedSyncRules(syncRules) ? syncRules : syncRules.parsed(PARSE_OPTIONS);
|
|
69
|
+
const hydrationState = parsed.hydrationState;
|
|
70
|
+
const parameterStart = bucket.indexOf('[');
|
|
71
|
+
const definitionName = bucket.substring(0, parameterStart);
|
|
72
|
+
const parameters = bucket.substring(parameterStart);
|
|
73
|
+
const source = parsed.sync_rules.config.bucketDataSources.find((b) => b.uniqueName === definitionName);
|
|
74
|
+
|
|
75
|
+
if (source == null) {
|
|
76
|
+
throw new Error(`Failed to find global bucket ${bucket}`);
|
|
77
|
+
}
|
|
78
|
+
const bucketName = hydrationState.getBucketSourceScope(source).bucketPrefix + parameters;
|
|
79
|
+
return {
|
|
80
|
+
bucket: bucketName,
|
|
81
|
+
start: BigInt(start ?? 0n),
|
|
82
|
+
source: source
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
48
86
|
export function getBatchMeta(
|
|
49
87
|
batch: utils.SyncBucketData[] | storage.SyncBucketDataChunk[] | storage.SyncBucketDataChunk
|
|
50
88
|
) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
1
|
+
import { addChecksums, storage, updateSyncRulesFromYaml } from '@powersync/service-core';
|
|
2
2
|
import { expect, test } from 'vitest';
|
|
3
3
|
import * as test_utils from '../test-utils/test-utils-index.js';
|
|
4
|
-
import { bucketRequest
|
|
4
|
+
import { bucketRequest } from '../test-utils/test-utils-index.js';
|
|
5
|
+
import { bucketRequestMap, bucketRequests } from './util.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
export function registerCompactTests(config: storage.TestStorageConfig) {
|
|
8
|
+
const generateStorageFactory = config.factory;
|
|
9
|
+
const TEST_TABLE = test_utils.makeTestTable('test', ['id'], config);
|
|
7
10
|
|
|
8
|
-
export function registerCompactTests(generateStorageFactory: storage.TestStorageFactory) {
|
|
9
11
|
test('compacting (1)', async () => {
|
|
10
12
|
await using factory = await generateStorageFactory();
|
|
11
13
|
const syncRules = await factory.updateSyncRules(
|
|
@@ -18,6 +20,7 @@ bucket_definitions:
|
|
|
18
20
|
const bucketStorage = factory.getInstance(syncRules);
|
|
19
21
|
|
|
20
22
|
const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
23
|
+
await batch.markAllSnapshotDone('1/1');
|
|
21
24
|
await batch.save({
|
|
22
25
|
sourceTable: TEST_TABLE,
|
|
23
26
|
tag: storage.SaveOperationTag.INSERT,
|
|
@@ -50,27 +53,24 @@ bucket_definitions:
|
|
|
50
53
|
|
|
51
54
|
const checkpoint = result!.flushed_op;
|
|
52
55
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
);
|
|
56
|
+
const request = bucketRequest(syncRules, 'global[]');
|
|
57
|
+
|
|
58
|
+
const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
|
|
56
59
|
const dataBefore = batchBefore.chunkData.data;
|
|
57
|
-
const checksumBefore = await bucketStorage.getChecksums(checkpoint,
|
|
60
|
+
const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
|
|
58
61
|
|
|
59
62
|
expect(dataBefore).toMatchObject([
|
|
60
63
|
{
|
|
61
|
-
checksum: 2634521662,
|
|
62
64
|
object_id: 't1',
|
|
63
65
|
op: 'PUT',
|
|
64
66
|
op_id: '1'
|
|
65
67
|
},
|
|
66
68
|
{
|
|
67
|
-
checksum: 4243212114,
|
|
68
69
|
object_id: 't2',
|
|
69
70
|
op: 'PUT',
|
|
70
71
|
op_id: '2'
|
|
71
72
|
},
|
|
72
73
|
{
|
|
73
|
-
checksum: 4243212114,
|
|
74
74
|
object_id: 't2',
|
|
75
75
|
op: 'PUT',
|
|
76
76
|
op_id: '3'
|
|
@@ -86,41 +86,30 @@ bucket_definitions:
|
|
|
86
86
|
minChangeRatio: 0
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
const batchAfter = await test_utils.oneFromAsync(
|
|
90
|
-
bucketStorage.getBucketDataBatch(checkpoint, bucketRequestMap(syncRules, [['global[]', 0n]]))
|
|
91
|
-
);
|
|
89
|
+
const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
|
|
92
90
|
const dataAfter = batchAfter.chunkData.data;
|
|
93
|
-
const checksumAfter = await bucketStorage.getChecksums(checkpoint,
|
|
91
|
+
const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
|
|
94
92
|
bucketStorage.clearChecksumCache();
|
|
95
|
-
const checksumAfter2 = await bucketStorage.getChecksums(checkpoint,
|
|
93
|
+
const checksumAfter2 = await bucketStorage.getChecksums(checkpoint, [request]);
|
|
96
94
|
|
|
97
95
|
expect(batchAfter.targetOp).toEqual(3n);
|
|
98
96
|
expect(dataAfter).toMatchObject([
|
|
97
|
+
dataBefore[0],
|
|
99
98
|
{
|
|
100
|
-
checksum:
|
|
101
|
-
object_id: 't1',
|
|
102
|
-
op: 'PUT',
|
|
103
|
-
op_id: '1'
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
checksum: 4243212114,
|
|
99
|
+
checksum: dataBefore[1].checksum,
|
|
107
100
|
op: 'MOVE',
|
|
108
101
|
op_id: '2'
|
|
109
102
|
},
|
|
110
103
|
{
|
|
111
|
-
checksum:
|
|
104
|
+
checksum: dataBefore[2].checksum,
|
|
112
105
|
object_id: 't2',
|
|
113
106
|
op: 'PUT',
|
|
114
107
|
op_id: '3'
|
|
115
108
|
}
|
|
116
109
|
]);
|
|
117
110
|
|
|
118
|
-
expect(checksumAfter.get(
|
|
119
|
-
|
|
120
|
-
);
|
|
121
|
-
expect(checksumAfter2.get(bucketRequest(syncRules, 'global[]'))).toEqual(
|
|
122
|
-
checksumBefore.get(bucketRequest(syncRules, 'global[]'))
|
|
123
|
-
);
|
|
111
|
+
expect(checksumAfter.get(request.bucket)).toEqual(checksumBefore.get(request.bucket));
|
|
112
|
+
expect(checksumAfter2.get(request.bucket)).toEqual(checksumBefore.get(request.bucket));
|
|
124
113
|
|
|
125
114
|
test_utils.validateCompactedBucket(dataBefore, dataAfter);
|
|
126
115
|
});
|
|
@@ -137,6 +126,7 @@ bucket_definitions:
|
|
|
137
126
|
const bucketStorage = factory.getInstance(syncRules);
|
|
138
127
|
|
|
139
128
|
const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
129
|
+
await batch.markAllSnapshotDone('1/1');
|
|
140
130
|
await batch.save({
|
|
141
131
|
sourceTable: TEST_TABLE,
|
|
142
132
|
tag: storage.SaveOperationTag.INSERT,
|
|
@@ -177,37 +167,29 @@ bucket_definitions:
|
|
|
177
167
|
});
|
|
178
168
|
|
|
179
169
|
const checkpoint = result!.flushed_op;
|
|
170
|
+
const request = bucketRequest(syncRules, 'global[]');
|
|
180
171
|
|
|
181
|
-
const batchBefore = await test_utils.oneFromAsync(
|
|
182
|
-
bucketStorage.getBucketDataBatch(checkpoint, bucketRequestMap(syncRules, [['global[]', 0n]]))
|
|
183
|
-
);
|
|
172
|
+
const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
|
|
184
173
|
const dataBefore = batchBefore.chunkData.data;
|
|
185
|
-
const checksumBefore = await bucketStorage.getChecksums(checkpoint,
|
|
174
|
+
const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
|
|
186
175
|
|
|
176
|
+
// op_id sequence depends on the storage implementation
|
|
187
177
|
expect(dataBefore).toMatchObject([
|
|
188
178
|
{
|
|
189
|
-
checksum: 2634521662,
|
|
190
179
|
object_id: 't1',
|
|
191
|
-
op: 'PUT'
|
|
192
|
-
op_id: '1'
|
|
180
|
+
op: 'PUT'
|
|
193
181
|
},
|
|
194
182
|
{
|
|
195
|
-
checksum: 4243212114,
|
|
196
183
|
object_id: 't2',
|
|
197
|
-
op: 'PUT'
|
|
198
|
-
op_id: '2'
|
|
184
|
+
op: 'PUT'
|
|
199
185
|
},
|
|
200
186
|
{
|
|
201
|
-
checksum: 4228978084,
|
|
202
187
|
object_id: 't1',
|
|
203
|
-
op: 'REMOVE'
|
|
204
|
-
op_id: '3'
|
|
188
|
+
op: 'REMOVE'
|
|
205
189
|
},
|
|
206
190
|
{
|
|
207
|
-
checksum: 4243212114,
|
|
208
191
|
object_id: 't2',
|
|
209
|
-
op: 'PUT'
|
|
210
|
-
op_id: '4'
|
|
192
|
+
op: 'PUT'
|
|
211
193
|
}
|
|
212
194
|
]);
|
|
213
195
|
|
|
@@ -219,29 +201,28 @@ bucket_definitions:
|
|
|
219
201
|
minChangeRatio: 0
|
|
220
202
|
});
|
|
221
203
|
|
|
222
|
-
const batchAfter = await test_utils.oneFromAsync(
|
|
223
|
-
bucketStorage.getBucketDataBatch(checkpoint, bucketRequestMap(syncRules, [['global[]', 0n]]))
|
|
224
|
-
);
|
|
204
|
+
const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
|
|
225
205
|
const dataAfter = batchAfter.chunkData.data;
|
|
226
206
|
bucketStorage.clearChecksumCache();
|
|
227
|
-
const checksumAfter = await bucketStorage.getChecksums(checkpoint,
|
|
207
|
+
const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
|
|
228
208
|
|
|
229
|
-
expect(batchAfter.targetOp).
|
|
209
|
+
expect(batchAfter.targetOp).toBeLessThanOrEqual(checkpoint);
|
|
230
210
|
expect(dataAfter).toMatchObject([
|
|
231
211
|
{
|
|
232
|
-
checksum:
|
|
233
|
-
|
|
234
|
-
|
|
212
|
+
checksum: addChecksums(
|
|
213
|
+
addChecksums(dataBefore[0].checksum as number, dataBefore[1].checksum as number),
|
|
214
|
+
dataBefore[2].checksum as number
|
|
215
|
+
),
|
|
216
|
+
op: 'CLEAR'
|
|
235
217
|
},
|
|
236
218
|
{
|
|
237
|
-
checksum:
|
|
219
|
+
checksum: dataBefore[3].checksum,
|
|
238
220
|
object_id: 't2',
|
|
239
|
-
op: 'PUT'
|
|
240
|
-
op_id: '4'
|
|
221
|
+
op: 'PUT'
|
|
241
222
|
}
|
|
242
223
|
]);
|
|
243
|
-
expect(checksumAfter.get(
|
|
244
|
-
...checksumBefore.get(
|
|
224
|
+
expect(checksumAfter.get(request.bucket)).toEqual({
|
|
225
|
+
...checksumBefore.get(request.bucket),
|
|
245
226
|
count: 2
|
|
246
227
|
});
|
|
247
228
|
|
|
@@ -260,6 +241,7 @@ bucket_definitions:
|
|
|
260
241
|
const bucketStorage = factory.getInstance(syncRules);
|
|
261
242
|
|
|
262
243
|
const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
244
|
+
await batch.markAllSnapshotDone('1/1');
|
|
263
245
|
await batch.save({
|
|
264
246
|
sourceTable: TEST_TABLE,
|
|
265
247
|
tag: storage.SaveOperationTag.INSERT,
|
|
@@ -291,7 +273,8 @@ bucket_definitions:
|
|
|
291
273
|
});
|
|
292
274
|
|
|
293
275
|
const checkpoint1 = result!.flushed_op;
|
|
294
|
-
const
|
|
276
|
+
const request = bucketRequest(syncRules, 'global[]');
|
|
277
|
+
const checksumBefore = await bucketStorage.getChecksums(checkpoint1, [request]);
|
|
295
278
|
|
|
296
279
|
const result2 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
297
280
|
await batch.save({
|
|
@@ -314,25 +297,20 @@ bucket_definitions:
|
|
|
314
297
|
minChangeRatio: 0
|
|
315
298
|
});
|
|
316
299
|
|
|
317
|
-
const batchAfter = await test_utils.oneFromAsync(
|
|
318
|
-
bucketStorage.getBucketDataBatch(checkpoint2, bucketRequestMap(syncRules, [['global[]', 0n]]))
|
|
319
|
-
);
|
|
300
|
+
const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
|
|
320
301
|
const dataAfter = batchAfter.chunkData.data;
|
|
321
302
|
await bucketStorage.clearChecksumCache();
|
|
322
|
-
const checksumAfter = await bucketStorage.getChecksums(checkpoint2,
|
|
303
|
+
const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
|
|
323
304
|
|
|
324
|
-
expect(batchAfter.targetOp).toEqual(4n);
|
|
325
305
|
expect(dataAfter).toMatchObject([
|
|
326
306
|
{
|
|
327
|
-
|
|
328
|
-
op: 'CLEAR',
|
|
329
|
-
op_id: '4'
|
|
307
|
+
op: 'CLEAR'
|
|
330
308
|
}
|
|
331
309
|
]);
|
|
332
|
-
expect(checksumAfter.get(
|
|
333
|
-
bucket:
|
|
310
|
+
expect(checksumAfter.get(request.bucket)).toEqual({
|
|
311
|
+
bucket: request.bucket,
|
|
334
312
|
count: 1,
|
|
335
|
-
checksum:
|
|
313
|
+
checksum: dataAfter[0].checksum
|
|
336
314
|
});
|
|
337
315
|
});
|
|
338
316
|
|
|
@@ -351,6 +329,7 @@ bucket_definitions:
|
|
|
351
329
|
const bucketStorage = factory.getInstance(syncRules);
|
|
352
330
|
|
|
353
331
|
const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
332
|
+
await batch.markAllSnapshotDone('1/1');
|
|
354
333
|
/**
|
|
355
334
|
* Repeatedly create operations which fall into different buckets.
|
|
356
335
|
* The bucket operations are purposely interleaved as the op_id increases.
|
|
@@ -477,7 +456,8 @@ bucket_definitions:
|
|
|
477
456
|
);
|
|
478
457
|
const bucketStorage = factory.getInstance(syncRules);
|
|
479
458
|
|
|
480
|
-
|
|
459
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
460
|
+
await batch.markAllSnapshotDone('1/1');
|
|
481
461
|
await batch.save({
|
|
482
462
|
sourceTable: TEST_TABLE,
|
|
483
463
|
tag: storage.SaveOperationTag.INSERT,
|
|
@@ -528,13 +508,17 @@ bucket_definitions:
|
|
|
528
508
|
await batch.commit('2/1');
|
|
529
509
|
});
|
|
530
510
|
const checkpoint2 = result2!.flushed_op;
|
|
511
|
+
const request = bucketRequest(syncRules, 'global[]');
|
|
531
512
|
await bucketStorage.clearChecksumCache();
|
|
532
|
-
const checksumAfter = await bucketStorage.getChecksums(checkpoint2,
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
513
|
+
const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
|
|
514
|
+
const globalChecksum = checksumAfter.get(request.bucket);
|
|
515
|
+
expect(globalChecksum).toMatchObject({
|
|
516
|
+
bucket: request.bucket,
|
|
517
|
+
count: 4
|
|
537
518
|
});
|
|
519
|
+
|
|
520
|
+
// storage-specific checksum - just check that it does not change
|
|
521
|
+
expect(globalChecksum).toMatchSnapshot();
|
|
538
522
|
});
|
|
539
523
|
|
|
540
524
|
test('partial checksums after compacting (2)', async () => {
|
|
@@ -549,6 +533,7 @@ bucket_definitions:
|
|
|
549
533
|
const bucketStorage = factory.getInstance(syncRules);
|
|
550
534
|
|
|
551
535
|
const result = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
536
|
+
await batch.markAllSnapshotDone('1/1');
|
|
552
537
|
await batch.save({
|
|
553
538
|
sourceTable: TEST_TABLE,
|
|
554
539
|
tag: storage.SaveOperationTag.INSERT,
|
|
@@ -593,12 +578,72 @@ bucket_definitions:
|
|
|
593
578
|
});
|
|
594
579
|
|
|
595
580
|
const checkpoint2 = result2!.flushed_op;
|
|
581
|
+
const request = bucketRequest(syncRules, 'global[]');
|
|
596
582
|
// Check that the checksum was correctly updated with the clear operation after having a cached checksum
|
|
597
|
-
const checksumAfter = await bucketStorage.getChecksums(checkpoint2,
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
583
|
+
const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
|
|
584
|
+
const globalChecksum = checksumAfter.get(request.bucket);
|
|
585
|
+
expect(globalChecksum).toMatchObject({
|
|
586
|
+
bucket: request.bucket,
|
|
587
|
+
count: 1
|
|
588
|
+
});
|
|
589
|
+
// storage-specific checksum - just check that it does not change
|
|
590
|
+
expect(globalChecksum).toMatchSnapshot();
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
test('defaults maxOpId to current checkpoint', async () => {
|
|
594
|
+
await using factory = await generateStorageFactory();
|
|
595
|
+
const syncRules = await factory.updateSyncRules(
|
|
596
|
+
updateSyncRulesFromYaml(`
|
|
597
|
+
bucket_definitions:
|
|
598
|
+
global:
|
|
599
|
+
data: [select * from test]
|
|
600
|
+
`)
|
|
601
|
+
);
|
|
602
|
+
const bucketStorage = factory.getInstance(syncRules);
|
|
603
|
+
|
|
604
|
+
const result1 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
605
|
+
await batch.markAllSnapshotDone('1/1');
|
|
606
|
+
await batch.save({
|
|
607
|
+
sourceTable: TEST_TABLE,
|
|
608
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
609
|
+
after: { id: 't1' },
|
|
610
|
+
afterReplicaId: test_utils.rid('t1')
|
|
611
|
+
});
|
|
612
|
+
await batch.commit('1/1');
|
|
602
613
|
});
|
|
614
|
+
|
|
615
|
+
const checkpoint1 = result1!.flushed_op;
|
|
616
|
+
|
|
617
|
+
const result2 = await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
618
|
+
// This is flushed but not committed (does not advance the checkpoint)
|
|
619
|
+
await batch.save({
|
|
620
|
+
sourceTable: TEST_TABLE,
|
|
621
|
+
tag: storage.SaveOperationTag.UPDATE,
|
|
622
|
+
after: { id: 't1' },
|
|
623
|
+
afterReplicaId: test_utils.rid('t1')
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
const checkpoint2 = result2!.flushed_op;
|
|
627
|
+
|
|
628
|
+
const checkpointBeforeCompact = await bucketStorage.getCheckpoint();
|
|
629
|
+
expect(checkpointBeforeCompact.checkpoint).toEqual(checkpoint1);
|
|
630
|
+
|
|
631
|
+
// With default options, Postgres compaction should use the active checkpoint.
|
|
632
|
+
await bucketStorage.compact({
|
|
633
|
+
moveBatchLimit: 1,
|
|
634
|
+
moveBatchQueryLimit: 1,
|
|
635
|
+
minBucketChanges: 1,
|
|
636
|
+
minChangeRatio: 0
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
const batchAfterDefaultCompact = await test_utils.oneFromAsync(
|
|
640
|
+
bucketStorage.getBucketDataBatch(checkpoint2, bucketRequestMap(syncRules, [['global[]', 0n]]))
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
// Operation 1 should remain a PUT because op_id=2 is above the default maxOpId checkpoint.
|
|
644
|
+
expect(batchAfterDefaultCompact.chunkData.data).toMatchObject([
|
|
645
|
+
{ op_id: '1', op: 'PUT', object_id: 't1' },
|
|
646
|
+
{ op_id: '2', op: 'PUT', object_id: 't1' }
|
|
647
|
+
]);
|
|
603
648
|
});
|
|
604
649
|
}
|
|
@@ -12,15 +12,24 @@ import * as test_utils from '../test-utils/test-utils-index.js';
|
|
|
12
12
|
*
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
|
-
export function registerDataStorageCheckpointTests(
|
|
15
|
+
export function registerDataStorageCheckpointTests(config: storage.TestStorageConfig) {
|
|
16
|
+
const generateStorageFactory = config.factory;
|
|
17
|
+
const storageVersion = config.storageVersion;
|
|
18
|
+
|
|
16
19
|
test('managed write checkpoints - checkpoint after write', async (context) => {
|
|
17
20
|
await using factory = await generateStorageFactory();
|
|
18
21
|
const r = await factory.configureSyncRules(
|
|
19
|
-
updateSyncRulesFromYaml(
|
|
22
|
+
updateSyncRulesFromYaml(
|
|
23
|
+
`
|
|
20
24
|
bucket_definitions:
|
|
21
25
|
mybucket:
|
|
22
26
|
data: []
|
|
23
|
-
|
|
27
|
+
`,
|
|
28
|
+
{
|
|
29
|
+
validate: false,
|
|
30
|
+
storageVersion
|
|
31
|
+
}
|
|
32
|
+
)
|
|
24
33
|
);
|
|
25
34
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
26
35
|
|
|
@@ -30,6 +39,10 @@ bucket_definitions:
|
|
|
30
39
|
.watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
|
|
31
40
|
[Symbol.asyncIterator]();
|
|
32
41
|
|
|
42
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
43
|
+
await batch.markAllSnapshotDone('1/1');
|
|
44
|
+
});
|
|
45
|
+
|
|
33
46
|
const writeCheckpoint = await bucketStorage.createManagedWriteCheckpoint({
|
|
34
47
|
heads: { '1': '5/0' },
|
|
35
48
|
user_id: 'user1'
|
|
@@ -55,14 +68,24 @@ bucket_definitions:
|
|
|
55
68
|
test('managed write checkpoints - write after checkpoint', async (context) => {
|
|
56
69
|
await using factory = await generateStorageFactory();
|
|
57
70
|
const r = await factory.configureSyncRules(
|
|
58
|
-
updateSyncRulesFromYaml(
|
|
71
|
+
updateSyncRulesFromYaml(
|
|
72
|
+
`
|
|
59
73
|
bucket_definitions:
|
|
60
74
|
mybucket:
|
|
61
75
|
data: []
|
|
62
|
-
|
|
76
|
+
`,
|
|
77
|
+
{
|
|
78
|
+
validate: false,
|
|
79
|
+
storageVersion
|
|
80
|
+
}
|
|
81
|
+
)
|
|
63
82
|
);
|
|
64
83
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
65
84
|
|
|
85
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
86
|
+
await batch.markAllSnapshotDone('1/1');
|
|
87
|
+
});
|
|
88
|
+
|
|
66
89
|
const abortController = new AbortController();
|
|
67
90
|
context.onTestFinished(() => abortController.abort());
|
|
68
91
|
const iter = bucketStorage
|
|
@@ -116,15 +139,25 @@ bucket_definitions:
|
|
|
116
139
|
test('custom write checkpoints - checkpoint after write', async (context) => {
|
|
117
140
|
await using factory = await generateStorageFactory();
|
|
118
141
|
const r = await factory.configureSyncRules(
|
|
119
|
-
updateSyncRulesFromYaml(
|
|
142
|
+
updateSyncRulesFromYaml(
|
|
143
|
+
`
|
|
120
144
|
bucket_definitions:
|
|
121
145
|
mybucket:
|
|
122
146
|
data: []
|
|
123
|
-
|
|
147
|
+
`,
|
|
148
|
+
{
|
|
149
|
+
validate: false,
|
|
150
|
+
storageVersion
|
|
151
|
+
}
|
|
152
|
+
)
|
|
124
153
|
);
|
|
125
154
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
126
155
|
bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
|
|
127
156
|
|
|
157
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
158
|
+
await batch.markAllSnapshotDone('1/1');
|
|
159
|
+
});
|
|
160
|
+
|
|
128
161
|
const abortController = new AbortController();
|
|
129
162
|
context.onTestFinished(() => abortController.abort());
|
|
130
163
|
const iter = bucketStorage
|
|
@@ -155,15 +188,25 @@ bucket_definitions:
|
|
|
155
188
|
test('custom write checkpoints - standalone checkpoint', async (context) => {
|
|
156
189
|
await using factory = await generateStorageFactory();
|
|
157
190
|
const r = await factory.configureSyncRules(
|
|
158
|
-
updateSyncRulesFromYaml(
|
|
191
|
+
updateSyncRulesFromYaml(
|
|
192
|
+
`
|
|
159
193
|
bucket_definitions:
|
|
160
194
|
mybucket:
|
|
161
195
|
data: []
|
|
162
|
-
|
|
196
|
+
`,
|
|
197
|
+
{
|
|
198
|
+
validate: false,
|
|
199
|
+
storageVersion
|
|
200
|
+
}
|
|
201
|
+
)
|
|
163
202
|
);
|
|
164
203
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
165
204
|
bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
|
|
166
205
|
|
|
206
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
207
|
+
await batch.markAllSnapshotDone('1/1');
|
|
208
|
+
});
|
|
209
|
+
|
|
167
210
|
const abortController = new AbortController();
|
|
168
211
|
context.onTestFinished(() => abortController.abort());
|
|
169
212
|
const iter = bucketStorage
|
|
@@ -197,15 +240,25 @@ bucket_definitions:
|
|
|
197
240
|
test('custom write checkpoints - write after checkpoint', async (context) => {
|
|
198
241
|
await using factory = await generateStorageFactory();
|
|
199
242
|
const r = await factory.configureSyncRules(
|
|
200
|
-
updateSyncRulesFromYaml(
|
|
243
|
+
updateSyncRulesFromYaml(
|
|
244
|
+
`
|
|
201
245
|
bucket_definitions:
|
|
202
246
|
mybucket:
|
|
203
247
|
data: []
|
|
204
|
-
|
|
248
|
+
`,
|
|
249
|
+
{
|
|
250
|
+
validate: false,
|
|
251
|
+
storageVersion
|
|
252
|
+
}
|
|
253
|
+
)
|
|
205
254
|
);
|
|
206
255
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
207
256
|
bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
|
|
208
257
|
|
|
258
|
+
await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
|
|
259
|
+
await batch.markAllSnapshotDone('1/1');
|
|
260
|
+
});
|
|
261
|
+
|
|
209
262
|
const abortController = new AbortController();
|
|
210
263
|
context.onTestFinished(() => abortController.abort());
|
|
211
264
|
const iter = bucketStorage
|