@powersync/service-core-tests 0.0.0-dev-20260803144812 → 0.0.0-dev-20260929095716

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 (40) hide show
  1. package/CHANGELOG.md +60 -5
  2. package/dist/test-utils/AbstractStreamTestContext.js +4 -3
  3. package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
  4. package/dist/test-utils/leased-storage.d.ts +9 -0
  5. package/dist/test-utils/leased-storage.js +53 -0
  6. package/dist/test-utils/leased-storage.js.map +1 -0
  7. package/dist/test-utils/storage-combinations.d.ts +13 -0
  8. package/dist/test-utils/storage-combinations.js +26 -0
  9. package/dist/test-utils/storage-combinations.js.map +1 -0
  10. package/dist/test-utils/test-utils-index.d.ts +2 -0
  11. package/dist/test-utils/test-utils-index.js +2 -0
  12. package/dist/test-utils/test-utils-index.js.map +1 -1
  13. package/dist/tests/register-compacting-tests.js +16 -15
  14. package/dist/tests/register-compacting-tests.js.map +1 -1
  15. package/dist/tests/register-data-storage-checkpoint-tests.js +47 -21
  16. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  17. package/dist/tests/register-data-storage-data-tests.js +37 -24
  18. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  19. package/dist/tests/register-data-storage-parameter-tests.js +16 -15
  20. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  21. package/dist/tests/register-parameter-compacting-tests.js +6 -4
  22. package/dist/tests/register-parameter-compacting-tests.js.map +1 -1
  23. package/dist/tests/register-sync-tests.js +28 -26
  24. package/dist/tests/register-sync-tests.js.map +1 -1
  25. package/dist/tests/util.d.ts +6 -0
  26. package/dist/tests/util.js +12 -0
  27. package/dist/tests/util.js.map +1 -1
  28. package/package.json +4 -4
  29. package/src/test-utils/AbstractStreamTestContext.ts +4 -3
  30. package/src/test-utils/leased-storage.ts +58 -0
  31. package/src/test-utils/storage-combinations.ts +51 -0
  32. package/src/test-utils/test-utils-index.ts +2 -0
  33. package/src/tests/register-compacting-tests.ts +16 -15
  34. package/src/tests/register-data-storage-checkpoint-tests.ts +85 -56
  35. package/src/tests/register-data-storage-data-tests.ts +41 -24
  36. package/src/tests/register-data-storage-parameter-tests.ts +16 -15
  37. package/src/tests/register-parameter-compacting-tests.ts +6 -4
  38. package/src/tests/register-sync-tests.ts +28 -26
  39. package/src/tests/util.ts +13 -0
  40. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,58 @@
1
+ import { storage } from '@powersync/service-core';
2
+
3
+ const leases = new WeakMap<storage.BucketStorageFactory, Map<number, Promise<storage.ReplicationLock>>>();
4
+
5
+ /**
6
+ * Acquire a real replication lease before constructing writable test storage.
7
+ * Writers in the same test job share a lease per factory/stream. The factory owns
8
+ * these leases and releases them at teardown; takeover tests manage their own leases.
9
+ */
10
+ export async function getTestStorage<T extends storage.BucketStorageFactory>(
11
+ factory: T,
12
+ stream: storage.PersistedReplicationStream,
13
+ options?: Parameters<T['getInstance']>[1]
14
+ ): Promise<ReturnType<T['getInstance']>> {
15
+ let owned = leases.get(factory);
16
+ if (owned == null) {
17
+ owned = new Map();
18
+ leases.set(factory, owned);
19
+ const factoryLeases = owned;
20
+ // `await using` captures the disposer before this helper runs. Register a
21
+ // lifecycle callback instead of replacing that already-captured method.
22
+ const unregister = factory.registerListener({
23
+ beforeDispose: async () => {
24
+ unregister();
25
+ try {
26
+ for (const lock of factoryLeases.values()) {
27
+ await (await lock).release();
28
+ }
29
+ } finally {
30
+ factoryLeases.clear();
31
+ }
32
+ }
33
+ });
34
+ }
35
+ let pending = owned.get(stream.replicationStreamId);
36
+ if (pending == null) {
37
+ pending = stream.lock();
38
+ owned.set(stream.replicationStreamId, pending);
39
+ }
40
+ let lock: storage.ReplicationLock;
41
+ try {
42
+ lock = await pending;
43
+ } catch (error) {
44
+ owned.delete(stream.replicationStreamId);
45
+ throw error;
46
+ }
47
+ return factory.getInstance(stream, { ...options, replicationLock: lock }) as ReturnType<T['getInstance']>;
48
+ }
49
+
50
+ /** End a test job before starting a replacement through another factory. */
51
+ export async function releaseTestStorageLease(factory: storage.BucketStorageFactory, streamId: number) {
52
+ const owned = leases.get(factory);
53
+ const pending = owned?.get(streamId);
54
+ if (pending != null) {
55
+ await (await pending).release();
56
+ owned!.delete(streamId);
57
+ }
58
+ }
@@ -0,0 +1,51 @@
1
+ import {
2
+ STORAGE_VERSION_1,
3
+ STORAGE_VERSION_2,
4
+ STORAGE_VERSION_4,
5
+ TestStorageConfig,
6
+ TestStorageFactory
7
+ } from '@powersync/service-core';
8
+ import { describe, TestOptions } from 'vitest';
9
+
10
+ const MONGO_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2, STORAGE_VERSION_4];
11
+ const POSTGRES_STORAGE_VERSIONS = [STORAGE_VERSION_1, STORAGE_VERSION_2];
12
+
13
+ export interface StorageVersionTestContext {
14
+ factory: TestStorageFactory;
15
+ storageVersion: number;
16
+ }
17
+
18
+ export interface StorageCombinationTestConfig {
19
+ mongodb?: TestStorageConfig;
20
+ postgres?: TestStorageConfig;
21
+ }
22
+
23
+ export function describeStorageCombinations(
24
+ config: StorageCombinationTestConfig,
25
+ options: TestOptions & { storageVersions?: number[] },
26
+ fn: (context: StorageVersionTestContext) => void
27
+ ) {
28
+ const describeFactory = (storageName: string, storage: TestStorageConfig, supportedStorageVersions: number[]) => {
29
+ const storageVersions = (options.storageVersions ?? supportedStorageVersions).filter((version) =>
30
+ supportedStorageVersions.includes(version)
31
+ );
32
+ describe(`${storageName} storage`, options, function () {
33
+ for (const storageVersion of storageVersions) {
34
+ describe(`storage v${storageVersion}`, function () {
35
+ fn({
36
+ factory: storage.factory,
37
+ storageVersion
38
+ });
39
+ });
40
+ }
41
+ });
42
+ };
43
+
44
+ if (config.mongodb) {
45
+ describeFactory('mongodb', config.mongodb, MONGO_STORAGE_VERSIONS);
46
+ }
47
+
48
+ if (config.postgres) {
49
+ describeFactory('postgres', config.postgres, POSTGRES_STORAGE_VERSIONS);
50
+ }
51
+ }
@@ -1,6 +1,8 @@
1
1
  export * from './AbstractStreamTestContext.js';
2
2
  export * from './bucket-validation.js';
3
3
  export * from './general-utils.js';
4
+ export * from './leased-storage.js';
4
5
  export * from './MetricsHelper.js';
6
+ export * from './storage-combinations.js';
5
7
  export * from './StorageDataHelpers.js';
6
8
  export * from './stream_utils.js';
@@ -1,8 +1,9 @@
1
1
  import { addChecksums, storage, updateSyncRulesFromYaml } from '@powersync/service-core';
2
2
  import { expect, test } from 'vitest';
3
+ import { getTestStorage } from '../test-utils/leased-storage.js';
3
4
  import * as test_utils from '../test-utils/test-utils-index.js';
4
5
  import { bucketRequest } from '../test-utils/test-utils-index.js';
5
- import { bucketRequestMap, bucketRequests } from './util.js';
6
+ import { bucketRequestMap, bucketRequests, compactActive } from './util.js';
6
7
 
7
8
  export function registerCompactTests(config: storage.TestStorageConfig) {
8
9
  const generateStorageFactory = config.factory;
@@ -16,7 +17,7 @@ bucket_definitions:
16
17
  data: [select * from test]
17
18
  `)
18
19
  );
19
- const bucketStorage = factory.getInstance(syncRules);
20
+ const bucketStorage = await getTestStorage(factory, syncRules);
20
21
  const syncRulesContent = syncRules.syncConfigContent[0];
21
22
 
22
23
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -81,7 +82,7 @@ bucket_definitions:
81
82
  ]);
82
83
  expect(batchBefore.targetOp).toEqual(null);
83
84
 
84
- await bucketStorage.compact({
85
+ await compactActive(factory, {
85
86
  clearBatchLimit: 2,
86
87
  moveBatchLimit: 1,
87
88
  moveBatchQueryLimit: 1,
@@ -128,7 +129,7 @@ bucket_definitions:
128
129
  data: [select * from test]
129
130
  `)
130
131
  );
131
- const bucketStorage = factory.getInstance(syncRules);
132
+ const bucketStorage = await getTestStorage(factory, syncRules);
132
133
  const syncRulesContent = syncRules.syncConfigContent[0];
133
134
 
134
135
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -202,7 +203,7 @@ bucket_definitions:
202
203
  }
203
204
  ]);
204
205
 
205
- await bucketStorage.compact({
206
+ await compactActive(factory, {
206
207
  clearBatchLimit: 2,
207
208
  moveBatchLimit: 1,
208
209
  moveBatchQueryLimit: 1,
@@ -249,7 +250,7 @@ bucket_definitions:
249
250
  data: [select * from test]
250
251
  `)
251
252
  );
252
- const bucketStorage = factory.getInstance(syncRules);
253
+ const bucketStorage = await getTestStorage(factory, syncRules);
253
254
  const syncRulesContent = syncRules.syncConfigContent[0];
254
255
 
255
256
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -301,7 +302,7 @@ bucket_definitions:
301
302
  await writer2.flush();
302
303
  const checkpoint2 = writer2.last_flushed_op!;
303
304
 
304
- await bucketStorage.compact({
305
+ await compactActive(factory, {
305
306
  clearBatchLimit: 2,
306
307
  moveBatchLimit: 1,
307
308
  moveBatchQueryLimit: 1,
@@ -340,7 +341,7 @@ bucket_definitions:
340
341
  data:
341
342
  - select * from test where b = bucket.b`)
342
343
  );
343
- const bucketStorage = factory.getInstance(syncRules);
344
+ const bucketStorage = await getTestStorage(factory, syncRules);
344
345
  const syncRulesContent = syncRules.syncConfigContent[0];
345
346
 
346
347
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -416,7 +417,7 @@ bucket_definitions:
416
417
 
417
418
  const checkpoint = writer.last_flushed_op!;
418
419
 
419
- await bucketStorage.compact({
420
+ await compactActive(factory, {
420
421
  clearBatchLimit: 100,
421
422
  moveBatchLimit: 100,
422
423
  moveBatchQueryLimit: 100, // Larger limit for a larger window of operations
@@ -471,7 +472,7 @@ bucket_definitions:
471
472
  data: [select * from test]
472
473
  `)
473
474
  );
474
- const bucketStorage = factory.getInstance(syncRules);
475
+ const bucketStorage = await getTestStorage(factory, syncRules);
475
476
  const syncRulesContent = syncRules.syncConfigContent[0];
476
477
 
477
478
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -507,7 +508,7 @@ bucket_definitions:
507
508
  await writer.commit('1/1');
508
509
  await writer.flush();
509
510
 
510
- await bucketStorage.compact({
511
+ await compactActive(factory, {
511
512
  clearBatchLimit: 2,
512
513
  moveBatchLimit: 1,
513
514
  moveBatchQueryLimit: 1,
@@ -550,7 +551,7 @@ bucket_definitions:
550
551
  data: [select * from test]
551
552
  `)
552
553
  );
553
- const bucketStorage = factory.getInstance(syncRules);
554
+ const bucketStorage = await getTestStorage(factory, syncRules);
554
555
  const syncRulesContent = syncRules.syncConfigContent[0];
555
556
 
556
557
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -595,7 +596,7 @@ bucket_definitions:
595
596
  await writer2.commit('2/1');
596
597
  await writer2.flush();
597
598
 
598
- await bucketStorage.compact({
599
+ await compactActive(factory, {
599
600
  clearBatchLimit: 20,
600
601
  moveBatchLimit: 10,
601
602
  moveBatchQueryLimit: 10,
@@ -625,7 +626,7 @@ bucket_definitions:
625
626
  data: [select * from test]
626
627
  `)
627
628
  );
628
- const bucketStorage = factory.getInstance(syncRules);
629
+ const bucketStorage = await getTestStorage(factory, syncRules);
629
630
  const syncRulesContent = syncRules.syncConfigContent[0];
630
631
 
631
632
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -658,7 +659,7 @@ bucket_definitions:
658
659
  expect(checkpointBeforeCompact.checkpoint).toEqual(checkpoint1);
659
660
 
660
661
  // With default options, Postgres compaction should use the active checkpoint.
661
- await bucketStorage.compact({
662
+ await compactActive(factory, {
662
663
  moveBatchLimit: 1,
663
664
  moveBatchQueryLimit: 1,
664
665
  minBucketChanges: 1,
@@ -1,6 +1,8 @@
1
1
  import { storage, updateSyncRulesFromYaml } from '@powersync/service-core';
2
2
  import { expect, test } from 'vitest';
3
+ import { getTestStorage } from '../test-utils/leased-storage.js';
3
4
  import * as test_utils from '../test-utils/test-utils-index.js';
5
+ import { compactActive } from './util.js';
4
6
 
5
7
  /**
6
8
  * @example
@@ -31,12 +33,15 @@ bucket_definitions:
31
33
  }
32
34
  )
33
35
  );
34
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
36
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
35
37
 
36
38
  const abortController = new AbortController();
37
39
  context.onTestFinished(() => abortController.abort());
38
40
  const iter = bucketStorage
39
- .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
41
+ .watchCheckpointChanges({
42
+ user_id: 'user1',
43
+ signal: abortController.signal
44
+ })
40
45
  [Symbol.asyncIterator]();
41
46
 
42
47
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
@@ -77,7 +82,7 @@ bucket_definitions:
77
82
  }
78
83
  )
79
84
  );
80
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
85
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
81
86
 
82
87
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
83
88
  await writer.markAllSnapshotDone('1/1');
@@ -85,7 +90,10 @@ bucket_definitions:
85
90
  const abortController = new AbortController();
86
91
  context.onTestFinished(() => abortController.abort());
87
92
  const iter = bucketStorage
88
- .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
93
+ .watchCheckpointChanges({
94
+ user_id: 'user1',
95
+ signal: abortController.signal
96
+ })
89
97
  [Symbol.asyncIterator]();
90
98
 
91
99
  await writer.keepalive('5/0');
@@ -143,7 +151,7 @@ bucket_definitions:
143
151
  }
144
152
  )
145
153
  );
146
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
154
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
147
155
 
148
156
  const first = await createManagedWriteCheckpointResult(bucketStorage, {
149
157
  user_id: 'user1',
@@ -194,7 +202,7 @@ bucket_definitions:
194
202
  expect(generated.shouldAdvance).toBe(true);
195
203
  });
196
204
 
197
- test('custom write checkpoints - checkpoint after write', async (context) => {
205
+ test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - checkpoint after write', async (context) => {
198
206
  await using factory = await generateStorageFactory();
199
207
  const r = await factory.configureSyncRules(
200
208
  updateSyncRulesFromYaml(
@@ -209,8 +217,10 @@ bucket_definitions:
209
217
  }
210
218
  )
211
219
  );
212
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
213
- bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
220
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
221
+ bucketStorage.setWriteCheckpointMode({
222
+ mode: storage.WriteCheckpointMode.CUSTOM
223
+ });
214
224
 
215
225
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
216
226
  await writer.markAllSnapshotDone('1/1');
@@ -218,7 +228,10 @@ bucket_definitions:
218
228
  const abortController = new AbortController();
219
229
  context.onTestFinished(() => abortController.abort());
220
230
  const iter = bucketStorage
221
- .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
231
+ .watchCheckpointChanges({
232
+ user_id: 'user1',
233
+ signal: abortController.signal
234
+ })
222
235
  [Symbol.asyncIterator]();
223
236
 
224
237
  writer.addCustomWriteCheckpoint({
@@ -240,7 +253,7 @@ bucket_definitions:
240
253
  });
241
254
  });
242
255
 
243
- test('custom write checkpoints - standalone checkpoint', async (context) => {
256
+ test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - standalone checkpoint', async (context) => {
244
257
  await using factory = await generateStorageFactory();
245
258
  const r = await factory.configureSyncRules(
246
259
  updateSyncRulesFromYaml(
@@ -255,8 +268,10 @@ bucket_definitions:
255
268
  }
256
269
  )
257
270
  );
258
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
259
- bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
271
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
272
+ bucketStorage.setWriteCheckpointMode({
273
+ mode: storage.WriteCheckpointMode.CUSTOM
274
+ });
260
275
 
261
276
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
262
277
  await writer.markAllSnapshotDone('1/1');
@@ -264,7 +279,10 @@ bucket_definitions:
264
279
  const abortController = new AbortController();
265
280
  context.onTestFinished(() => abortController.abort());
266
281
  const iter = bucketStorage
267
- .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
282
+ .watchCheckpointChanges({
283
+ user_id: 'user1',
284
+ signal: abortController.signal
285
+ })
268
286
  [Symbol.asyncIterator]();
269
287
 
270
288
  // Flush to clear state
@@ -289,7 +307,7 @@ bucket_definitions:
289
307
  });
290
308
  });
291
309
 
292
- test('custom write checkpoints - write after checkpoint', async (context) => {
310
+ test.runIf((storageVersion ?? 1) < 3)('custom write checkpoints - write after checkpoint', async (context) => {
293
311
  await using factory = await generateStorageFactory();
294
312
  const r = await factory.configureSyncRules(
295
313
  updateSyncRulesFromYaml(
@@ -304,8 +322,10 @@ bucket_definitions:
304
322
  }
305
323
  )
306
324
  );
307
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
308
- bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
325
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
326
+ bucketStorage.setWriteCheckpointMode({
327
+ mode: storage.WriteCheckpointMode.CUSTOM
328
+ });
309
329
 
310
330
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
311
331
  await writer.markAllSnapshotDone('1/1');
@@ -313,7 +333,10 @@ bucket_definitions:
313
333
  const abortController = new AbortController();
314
334
  context.onTestFinished(() => abortController.abort());
315
335
  const iter = bucketStorage
316
- .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
336
+ .watchCheckpointChanges({
337
+ user_id: 'user1',
338
+ signal: abortController.signal
339
+ })
317
340
  [Symbol.asyncIterator]();
318
341
 
319
342
  await writer.keepalive('5/0');
@@ -368,49 +391,55 @@ bucket_definitions:
368
391
  });
369
392
  });
370
393
 
371
- test('custom write checkpoints - checkpoint request markers are temporary', async () => {
372
- await using factory = await generateStorageFactory();
373
- const r = await factory.configureSyncRules(
374
- updateSyncRulesFromYaml(
375
- `
394
+ test.runIf((storageVersion ?? 1) < 3)(
395
+ 'custom write checkpoints - checkpoint request markers are temporary',
396
+ async () => {
397
+ await using factory = await generateStorageFactory();
398
+ const r = await factory.configureSyncRules(
399
+ updateSyncRulesFromYaml(
400
+ `
376
401
  bucket_definitions:
377
402
  mybucket:
378
403
  data: []
379
404
  `,
380
- {
381
- validate: false,
382
- storageVersion
383
- }
384
- )
385
- );
386
- const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
387
- bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
388
-
389
- await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
390
- await writer.markAllSnapshotDone('1/1');
391
-
392
- writer.addCustomWriteCheckpoint({
393
- checkpoint: 5n,
394
- user_id: 'persistent'
395
- });
396
- writer.addCustomWriteCheckpoint({
397
- checkpoint: 6n,
398
- user_id: 'temporary',
399
- checkpoint_requested_at: new Date('2024-01-01T00:00:00.000Z')
400
- });
401
- await writer.flush();
402
-
403
- await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
404
- await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toEqual(6n);
405
-
406
- await bucketStorage.compact({
407
- compactBuckets: [],
408
- deleteCheckpointRequestsBefore: new Date(Date.now() + 1_000)
409
- });
410
-
411
- await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
412
- await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toBeNull();
413
- });
405
+ {
406
+ validate: false,
407
+ storageVersion
408
+ }
409
+ )
410
+ );
411
+ const bucketStorage = await getTestStorage(factory, r.persisted_sync_rules!);
412
+ bucketStorage.setWriteCheckpointMode({
413
+ mode: storage.WriteCheckpointMode.CUSTOM
414
+ });
415
+
416
+ await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
417
+ await writer.markAllSnapshotDone('1/1');
418
+
419
+ writer.addCustomWriteCheckpoint({
420
+ checkpoint: 5n,
421
+ user_id: 'persistent'
422
+ });
423
+ writer.addCustomWriteCheckpoint({
424
+ checkpoint: 6n,
425
+ user_id: 'temporary',
426
+ checkpoint_requested_at: new Date('2024-01-01T00:00:00.000Z')
427
+ });
428
+ await writer.flush();
429
+ await writer.keepalive('1/1');
430
+
431
+ await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
432
+ await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toEqual(6n);
433
+
434
+ await compactActive(factory, {
435
+ compactBuckets: [],
436
+ deleteCheckpointRequestsBefore: new Date(Date.now() + 1_000)
437
+ });
438
+
439
+ await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'persistent' })).resolves.toEqual(5n);
440
+ await expect(bucketStorage.lastWriteCheckpoint({ user_id: 'temporary' })).resolves.toBeNull();
441
+ }
442
+ );
414
443
  }
415
444
 
416
445
  async function createManagedWriteCheckpoint(