@powersync/service-core-tests 0.17.2 → 0.18.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.
- package/CHANGELOG.md +52 -0
- package/dist/test-utils/AbstractStreamTestContext.d.ts +1 -1
- package/dist/test-utils/AbstractStreamTestContext.js +2 -3
- package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
- package/dist/test-utils/StorageDataHelpers.d.ts +3 -2
- package/dist/test-utils/StorageDataHelpers.js +40 -2
- package/dist/test-utils/StorageDataHelpers.js.map +1 -1
- package/dist/test-utils/general-utils.d.ts +3 -1
- package/dist/test-utils/general-utils.js +13 -1
- 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 +15 -15
- package/dist/tests/register-compacting-tests.js.map +1 -1
- package/dist/tests/register-data-storage-checkpoint-tests.js +132 -14
- package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
- package/dist/tests/register-data-storage-data-tests.js +116 -96
- package/dist/tests/register-data-storage-data-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 +267 -82
- package/dist/tests/register-sync-tests.js.map +1 -1
- package/dist/tests/util.d.ts +6 -0
- package/dist/tests/util.js +12 -0
- package/dist/tests/util.js.map +1 -1
- package/package.json +4 -4
- package/src/test-utils/AbstractStreamTestContext.ts +2 -3
- package/src/test-utils/StorageDataHelpers.ts +45 -2
- package/src/test-utils/general-utils.ts +27 -3
- 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 +15 -15
- package/src/tests/register-data-storage-checkpoint-tests.ts +161 -14
- package/src/tests/register-data-storage-data-tests.ts +132 -134
- package/src/tests/register-parameter-compacting-tests.ts +3 -2
- package/src/tests/register-sync-tests.ts +288 -84
- package/src/tests/util.ts +13 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { 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 { compactActive } from './util.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @example
|
|
@@ -36,7 +37,10 @@ bucket_definitions:
|
|
|
36
37
|
const abortController = new AbortController();
|
|
37
38
|
context.onTestFinished(() => abortController.abort());
|
|
38
39
|
const iter = bucketStorage
|
|
39
|
-
.watchCheckpointChanges({
|
|
40
|
+
.watchCheckpointChanges({
|
|
41
|
+
user_id: 'user1',
|
|
42
|
+
signal: abortController.signal
|
|
43
|
+
})
|
|
40
44
|
[Symbol.asyncIterator]();
|
|
41
45
|
|
|
42
46
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
@@ -85,7 +89,10 @@ bucket_definitions:
|
|
|
85
89
|
const abortController = new AbortController();
|
|
86
90
|
context.onTestFinished(() => abortController.abort());
|
|
87
91
|
const iter = bucketStorage
|
|
88
|
-
.watchCheckpointChanges({
|
|
92
|
+
.watchCheckpointChanges({
|
|
93
|
+
user_id: 'user1',
|
|
94
|
+
signal: abortController.signal
|
|
95
|
+
})
|
|
89
96
|
[Symbol.asyncIterator]();
|
|
90
97
|
|
|
91
98
|
await writer.keepalive('5/0');
|
|
@@ -107,7 +114,7 @@ bucket_definitions:
|
|
|
107
114
|
user_id: 'user1'
|
|
108
115
|
});
|
|
109
116
|
// We have to trigger a new keepalive after the checkpoint, at least to cover postgres storage.
|
|
110
|
-
// This is what is
|
|
117
|
+
// This is what is effectively triggered by RouteAPI.createReplicationHead().
|
|
111
118
|
// MongoDB storage doesn't explicitly need this anymore.
|
|
112
119
|
await writer.keepalive('6/0');
|
|
113
120
|
|
|
@@ -128,7 +135,7 @@ bucket_definitions:
|
|
|
128
135
|
});
|
|
129
136
|
});
|
|
130
137
|
|
|
131
|
-
test('
|
|
138
|
+
test('managed write checkpoints - client supplied ids are monotonic', async () => {
|
|
132
139
|
await using factory = await generateStorageFactory();
|
|
133
140
|
const r = await factory.configureSyncRules(
|
|
134
141
|
updateSyncRulesFromYaml(
|
|
@@ -144,7 +151,75 @@ bucket_definitions:
|
|
|
144
151
|
)
|
|
145
152
|
);
|
|
146
153
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
147
|
-
|
|
154
|
+
|
|
155
|
+
const first = await createManagedWriteCheckpointResult(bucketStorage, {
|
|
156
|
+
user_id: 'user1',
|
|
157
|
+
heads: { '1': '5/0' },
|
|
158
|
+
checkpoint_request_id: 42n
|
|
159
|
+
});
|
|
160
|
+
expect(first.writeCheckpoints.get('user1')).toEqual(42n);
|
|
161
|
+
expect(first.shouldAdvance).toBe(true);
|
|
162
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'user1', heads: { '1': '5/0' } })).resolves.toEqual(42n);
|
|
163
|
+
|
|
164
|
+
const stale = await createManagedWriteCheckpointResult(bucketStorage, {
|
|
165
|
+
user_id: 'user1',
|
|
166
|
+
heads: { '1': '8/0' },
|
|
167
|
+
checkpoint_request_id: 41n
|
|
168
|
+
});
|
|
169
|
+
expect(stale.writeCheckpoints.get('user1')).toEqual(42n);
|
|
170
|
+
// The stored checkpoint is unchanged but has not been processed by replication
|
|
171
|
+
// yet, so the source marker must still be forced (e.g. for a retry after a
|
|
172
|
+
// previous attempt failed to advance the marker).
|
|
173
|
+
expect(stale.shouldAdvance).toBe(true);
|
|
174
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'user1', heads: { '1': '6/0' } })).resolves.toEqual(42n);
|
|
175
|
+
|
|
176
|
+
const retried = await createManagedWriteCheckpointResult(bucketStorage, {
|
|
177
|
+
user_id: 'user1',
|
|
178
|
+
heads: { '1': '8/0' },
|
|
179
|
+
checkpoint_request_id: 42n
|
|
180
|
+
});
|
|
181
|
+
expect(retried.writeCheckpoints.get('user1')).toEqual(42n);
|
|
182
|
+
// Same as above: the duplicate request still points at a pending checkpoint.
|
|
183
|
+
expect(retried.shouldAdvance).toBe(true);
|
|
184
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'user1', heads: { '1': '6/0' } })).resolves.toEqual(42n);
|
|
185
|
+
|
|
186
|
+
const advanced = await createManagedWriteCheckpointResult(bucketStorage, {
|
|
187
|
+
user_id: 'user1',
|
|
188
|
+
heads: { '1': '8/0' },
|
|
189
|
+
checkpoint_request_id: 43n
|
|
190
|
+
});
|
|
191
|
+
expect(advanced.writeCheckpoints.get('user1')).toEqual(43n);
|
|
192
|
+
expect(advanced.shouldAdvance).toBe(true);
|
|
193
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'user1', heads: { '1': '7/0' } })).resolves.toBeNull();
|
|
194
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'user1', heads: { '1': '8/0' } })).resolves.toEqual(43n);
|
|
195
|
+
|
|
196
|
+
const generated = await createManagedWriteCheckpointResult(bucketStorage, {
|
|
197
|
+
user_id: 'user1',
|
|
198
|
+
heads: { '1': '9/0' }
|
|
199
|
+
});
|
|
200
|
+
expect(generated.writeCheckpoints.get('user1')).toEqual(44n);
|
|
201
|
+
expect(generated.shouldAdvance).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - checkpoint after write', async (context) => {
|
|
205
|
+
await using factory = await generateStorageFactory();
|
|
206
|
+
const r = await factory.configureSyncRules(
|
|
207
|
+
updateSyncRulesFromYaml(
|
|
208
|
+
`
|
|
209
|
+
bucket_definitions:
|
|
210
|
+
mybucket:
|
|
211
|
+
data: []
|
|
212
|
+
`,
|
|
213
|
+
{
|
|
214
|
+
validate: false,
|
|
215
|
+
storageVersion
|
|
216
|
+
}
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
220
|
+
bucketStorage.setWriteCheckpointMode({
|
|
221
|
+
mode: storage.WriteCheckpointMode.CUSTOM
|
|
222
|
+
});
|
|
148
223
|
|
|
149
224
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
150
225
|
await writer.markAllSnapshotDone('1/1');
|
|
@@ -152,7 +227,10 @@ bucket_definitions:
|
|
|
152
227
|
const abortController = new AbortController();
|
|
153
228
|
context.onTestFinished(() => abortController.abort());
|
|
154
229
|
const iter = bucketStorage
|
|
155
|
-
.watchCheckpointChanges({
|
|
230
|
+
.watchCheckpointChanges({
|
|
231
|
+
user_id: 'user1',
|
|
232
|
+
signal: abortController.signal
|
|
233
|
+
})
|
|
156
234
|
[Symbol.asyncIterator]();
|
|
157
235
|
|
|
158
236
|
writer.addCustomWriteCheckpoint({
|
|
@@ -174,7 +252,7 @@ bucket_definitions:
|
|
|
174
252
|
});
|
|
175
253
|
});
|
|
176
254
|
|
|
177
|
-
test('custom write checkpoints - standalone checkpoint', async (context) => {
|
|
255
|
+
test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - standalone checkpoint', async (context) => {
|
|
178
256
|
await using factory = await generateStorageFactory();
|
|
179
257
|
const r = await factory.configureSyncRules(
|
|
180
258
|
updateSyncRulesFromYaml(
|
|
@@ -190,7 +268,9 @@ bucket_definitions:
|
|
|
190
268
|
)
|
|
191
269
|
);
|
|
192
270
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
193
|
-
bucketStorage.setWriteCheckpointMode(
|
|
271
|
+
bucketStorage.setWriteCheckpointMode({
|
|
272
|
+
mode: storage.WriteCheckpointMode.CUSTOM
|
|
273
|
+
});
|
|
194
274
|
|
|
195
275
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
196
276
|
await writer.markAllSnapshotDone('1/1');
|
|
@@ -198,7 +278,10 @@ bucket_definitions:
|
|
|
198
278
|
const abortController = new AbortController();
|
|
199
279
|
context.onTestFinished(() => abortController.abort());
|
|
200
280
|
const iter = bucketStorage
|
|
201
|
-
.watchCheckpointChanges({
|
|
281
|
+
.watchCheckpointChanges({
|
|
282
|
+
user_id: 'user1',
|
|
283
|
+
signal: abortController.signal
|
|
284
|
+
})
|
|
202
285
|
[Symbol.asyncIterator]();
|
|
203
286
|
|
|
204
287
|
// Flush to clear state
|
|
@@ -223,7 +306,7 @@ bucket_definitions:
|
|
|
223
306
|
});
|
|
224
307
|
});
|
|
225
308
|
|
|
226
|
-
test('custom write checkpoints - write after checkpoint', async (context) => {
|
|
309
|
+
test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - write after checkpoint', async (context) => {
|
|
227
310
|
await using factory = await generateStorageFactory();
|
|
228
311
|
const r = await factory.configureSyncRules(
|
|
229
312
|
updateSyncRulesFromYaml(
|
|
@@ -239,7 +322,9 @@ bucket_definitions:
|
|
|
239
322
|
)
|
|
240
323
|
);
|
|
241
324
|
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
242
|
-
bucketStorage.setWriteCheckpointMode(
|
|
325
|
+
bucketStorage.setWriteCheckpointMode({
|
|
326
|
+
mode: storage.WriteCheckpointMode.CUSTOM
|
|
327
|
+
});
|
|
243
328
|
|
|
244
329
|
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
245
330
|
await writer.markAllSnapshotDone('1/1');
|
|
@@ -247,7 +332,10 @@ bucket_definitions:
|
|
|
247
332
|
const abortController = new AbortController();
|
|
248
333
|
context.onTestFinished(() => abortController.abort());
|
|
249
334
|
const iter = bucketStorage
|
|
250
|
-
.watchCheckpointChanges({
|
|
335
|
+
.watchCheckpointChanges({
|
|
336
|
+
user_id: 'user1',
|
|
337
|
+
signal: abortController.signal
|
|
338
|
+
})
|
|
251
339
|
[Symbol.asyncIterator]();
|
|
252
340
|
|
|
253
341
|
await writer.keepalive('5/0');
|
|
@@ -301,14 +389,73 @@ bucket_definitions:
|
|
|
301
389
|
}
|
|
302
390
|
});
|
|
303
391
|
});
|
|
392
|
+
|
|
393
|
+
test.runIf((storageVersion ?? 1) < 3)(
|
|
394
|
+
'custom write checkpoints - checkpoint request markers are temporary',
|
|
395
|
+
async () => {
|
|
396
|
+
await using factory = await generateStorageFactory();
|
|
397
|
+
const r = await factory.configureSyncRules(
|
|
398
|
+
updateSyncRulesFromYaml(
|
|
399
|
+
`
|
|
400
|
+
bucket_definitions:
|
|
401
|
+
mybucket:
|
|
402
|
+
data: []
|
|
403
|
+
`,
|
|
404
|
+
{
|
|
405
|
+
validate: false,
|
|
406
|
+
storageVersion
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
);
|
|
410
|
+
const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
|
|
411
|
+
bucketStorage.setWriteCheckpointMode({
|
|
412
|
+
mode: storage.WriteCheckpointMode.CUSTOM
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
|
|
416
|
+
await writer.markAllSnapshotDone('1/1');
|
|
417
|
+
|
|
418
|
+
writer.addCustomWriteCheckpoint({
|
|
419
|
+
checkpoint: 5n,
|
|
420
|
+
user_id: 'persistent'
|
|
421
|
+
});
|
|
422
|
+
writer.addCustomWriteCheckpoint({
|
|
423
|
+
checkpoint: 6n,
|
|
424
|
+
user_id: 'temporary',
|
|
425
|
+
checkpoint_requested_at: new Date('2024-01-01T00:00:00.000Z')
|
|
426
|
+
});
|
|
427
|
+
await writer.flush();
|
|
428
|
+
await writer.keepalive('1/1');
|
|
429
|
+
|
|
430
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
|
|
431
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toEqual(6n);
|
|
432
|
+
|
|
433
|
+
await compactActive(factory, {
|
|
434
|
+
compactBuckets: [],
|
|
435
|
+
deleteCheckpointRequestsBefore: new Date(Date.now() + 1_000)
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
|
|
439
|
+
await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toBeNull();
|
|
440
|
+
}
|
|
441
|
+
);
|
|
304
442
|
}
|
|
305
443
|
|
|
306
444
|
async function createManagedWriteCheckpoint(
|
|
307
445
|
bucketStorage: storage.SyncRulesBucketStorage,
|
|
308
446
|
checkpoint: storage.ManagedWriteCheckpointOptions
|
|
309
447
|
) {
|
|
310
|
-
const
|
|
311
|
-
const writeCheckpoint =
|
|
448
|
+
const result = await createManagedWriteCheckpointResult(bucketStorage, checkpoint);
|
|
449
|
+
const writeCheckpoint = result.writeCheckpoints.get(checkpoint.user_id);
|
|
312
450
|
expect(writeCheckpoint).not.toBeUndefined();
|
|
313
451
|
return writeCheckpoint!;
|
|
314
452
|
}
|
|
453
|
+
|
|
454
|
+
async function createManagedWriteCheckpointResult(
|
|
455
|
+
bucketStorage: storage.SyncRulesBucketStorage,
|
|
456
|
+
checkpoint: storage.ManagedWriteCheckpointOptions
|
|
457
|
+
) {
|
|
458
|
+
const result = await bucketStorage.createManagedWriteCheckpoints([checkpoint]);
|
|
459
|
+
expect(result.writeCheckpoints.get(checkpoint.user_id)).not.toBeUndefined();
|
|
460
|
+
return result;
|
|
461
|
+
}
|