@powersync/service-core-tests 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/test-utils/AbstractStreamTestContext.d.ts +6 -5
  3. package/dist/test-utils/AbstractStreamTestContext.js +26 -22
  4. package/dist/test-utils/AbstractStreamTestContext.js.map +1 -1
  5. package/dist/test-utils/StorageDataHelpers.d.ts +5 -5
  6. package/dist/test-utils/StorageDataHelpers.js.map +1 -1
  7. package/dist/test-utils/bucket-validation.d.ts +3 -3
  8. package/dist/test-utils/bucket-validation.js +3 -3
  9. package/dist/test-utils/general-utils.d.ts +13 -2
  10. package/dist/test-utils/general-utils.js +24 -3
  11. package/dist/test-utils/general-utils.js.map +1 -1
  12. package/dist/tests/register-compacting-tests.js +28 -21
  13. package/dist/tests/register-compacting-tests.js.map +1 -1
  14. package/dist/tests/register-data-storage-checkpoint-tests.js +8 -2
  15. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -1
  16. package/dist/tests/register-data-storage-data-tests.js +148 -101
  17. package/dist/tests/register-data-storage-data-tests.js.map +1 -1
  18. package/dist/tests/register-data-storage-parameter-tests.js +44 -42
  19. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -1
  20. package/dist/tests/register-sync-tests.js +141 -8
  21. package/dist/tests/register-sync-tests.js.map +1 -1
  22. package/dist/tests/util.d.ts +2 -2
  23. package/dist/tests/util.js.map +1 -1
  24. package/package.json +6 -7
  25. package/src/test-utils/AbstractStreamTestContext.ts +29 -24
  26. package/src/test-utils/StorageDataHelpers.ts +7 -6
  27. package/src/test-utils/bucket-validation.ts +3 -3
  28. package/src/test-utils/general-utils.ts +35 -7
  29. package/src/tests/register-compacting-tests.ts +45 -22
  30. package/src/tests/register-data-storage-checkpoint-tests.ts +12 -2
  31. package/src/tests/register-data-storage-data-tests.ts +210 -107
  32. package/src/tests/register-data-storage-parameter-tests.ts +58 -42
  33. package/src/tests/register-sync-tests.ts +159 -8
  34. package/src/tests/util.ts +2 -2
  35. package/tsconfig.json +1 -4
  36. package/tsconfig.tsbuildinfo +1 -1
@@ -2,6 +2,7 @@ import { ReplicationAbortedError } from '@powersync/lib-services-framework';
2
2
  import {
3
3
  BucketStorageFactory,
4
4
  InternalOpId,
5
+ ReplicationCheckpoint,
5
6
  settledPromise,
6
7
  storage,
7
8
  SyncRulesBucketStorage,
@@ -14,7 +15,8 @@ import { fromAsync } from './stream_utils.js';
14
15
 
15
16
  export abstract class AbstractStreamTestContext implements AsyncDisposable {
16
17
  protected abortController = new AbortController();
17
- protected syncRulesContent?: storage.PersistedSyncRulesContent;
18
+ protected syncRulesContent?: storage.PersistedSyncConfigContent;
19
+ protected replicationStream?: storage.PersistedReplicationStream;
18
20
  public storage?: SyncRulesBucketStorage;
19
21
  protected settledReplicationPromise?: Promise<PromiseSettledResult<void>>;
20
22
 
@@ -44,39 +46,42 @@ export abstract class AbstractStreamTestContext implements AsyncDisposable {
44
46
  }
45
47
 
46
48
  async updateSyncRules(content: string) {
47
- const syncRules = await this.factory.updateSyncRules(
49
+ const stream = await this.factory.updateSyncRules(
48
50
  updateSyncRulesFromYaml(content, { validate: true, storageVersion: this.storageVersion })
49
51
  );
50
- this.syncRulesContent = syncRules;
51
- this.storage = this.factory.getInstance(syncRules);
52
+ this.replicationStream = stream;
53
+ this.syncRulesContent = stream.syncConfigContent[0];
54
+ this.storage = this.factory.getInstance(stream);
52
55
  return this.storage!;
53
56
  }
54
57
 
55
58
  async loadNextSyncRules() {
56
- const syncRules = await this.factory.getNextSyncRulesContent();
57
- if (syncRules == null) {
58
- throw new Error(`Next sync rules not available`);
59
+ const syncConfig = await this.factory.getDeployingSyncConfig();
60
+ if (syncConfig == null) {
61
+ throw new Error(`Next sync config not available`);
59
62
  }
60
63
 
61
- this.syncRulesContent = syncRules;
62
- this.storage = this.factory.getInstance(syncRules);
64
+ this.syncRulesContent = syncConfig.content;
65
+ this.replicationStream = syncConfig.replicationStream;
66
+ this.storage = syncConfig.storage;
63
67
  return this.storage!;
64
68
  }
65
69
 
66
70
  async loadActiveSyncRules() {
67
- const syncRules = await this.factory.getActiveSyncRulesContent();
68
- if (syncRules == null) {
69
- throw new Error(`Active sync rules not available`);
71
+ const syncConfig = await this.factory.getActiveSyncConfig();
72
+ if (syncConfig == null) {
73
+ throw new Error(`Active sync config not available`);
70
74
  }
71
75
 
72
- this.syncRulesContent = syncRules;
73
- this.storage = this.factory.getInstance(syncRules);
76
+ this.syncRulesContent = syncConfig.content;
77
+ this.replicationStream = syncConfig.replicationStream;
78
+ this.storage = syncConfig.storage;
74
79
  return this.storage!;
75
80
  }
76
81
 
77
- private getSyncRulesContent(): storage.PersistedSyncRulesContent {
82
+ private getSyncConfigContent(): storage.PersistedSyncConfigContent {
78
83
  if (this.syncRulesContent == null) {
79
- throw new Error('Sync rules not configured - call updateSyncRules() first');
84
+ throw new Error('Sync config not configured - call updateSyncRules() first');
80
85
  }
81
86
  return this.syncRulesContent;
82
87
  }
@@ -112,7 +117,7 @@ export abstract class AbstractStreamTestContext implements AsyncDisposable {
112
117
  }
113
118
  }
114
119
 
115
- abstract getClientCheckpoint(options?: { timeout?: number }): Promise<bigint>;
120
+ abstract getClientCheckpoint(options?: { timeout?: number }): Promise<ReplicationCheckpoint>;
116
121
 
117
122
  async getCheckpoint(options?: { timeout?: number }) {
118
123
  let checkpoint = await Promise.race([
@@ -128,7 +133,7 @@ export abstract class AbstractStreamTestContext implements AsyncDisposable {
128
133
  }
129
134
 
130
135
  async getBucketsDataBatch(buckets: Record<string, InternalOpId>, options?: { timeout?: number }) {
131
- const helpers = new StorageDataHelpers(this.storage!, this.getSyncRulesContent());
136
+ const helpers = new StorageDataHelpers(this.storage!, this.getSyncConfigContent());
132
137
  const checkpoint = await this.getCheckpoint(options);
133
138
  return helpers.getBucketsDataBatch(buckets, checkpoint);
134
139
  }
@@ -137,15 +142,15 @@ export abstract class AbstractStreamTestContext implements AsyncDisposable {
137
142
  * This waits for a client checkpoint.
138
143
  */
139
144
  async getBucketData(bucket: string, start?: InternalOpId | string | undefined, options?: { timeout?: number }) {
140
- const helpers = new StorageDataHelpers(this.storage!, this.getSyncRulesContent());
145
+ const helpers = new StorageDataHelpers(this.storage!, this.getSyncConfigContent());
141
146
  const checkpoint = await this.getCheckpoint(options);
142
147
  return helpers.getBucketData(bucket, checkpoint, start);
143
148
  }
144
149
 
145
150
  async getChecksums(buckets: string[], options?: { timeout?: number }) {
146
151
  const checkpoint = await this.getCheckpoint(options);
147
- const syncRules = this.getSyncRulesContent();
148
- const versionedBuckets = buckets.map((bucket) => bucketRequest(syncRules, bucket, 0n));
152
+ const syncConfigContent = this.getSyncConfigContent();
153
+ const versionedBuckets = buckets.map((bucket) => bucketRequest(syncConfigContent, bucket, 0n));
149
154
  const checksums = await this.storage!.getChecksums(checkpoint, versionedBuckets);
150
155
 
151
156
  const unversioned = new Map();
@@ -169,9 +174,9 @@ export abstract class AbstractStreamTestContext implements AsyncDisposable {
169
174
  if (typeof start == 'string') {
170
175
  start = BigInt(start);
171
176
  }
172
- const syncRules = this.getSyncRulesContent();
173
- const { checkpoint } = await this.storage!.getCheckpoint();
174
- const map = [bucketRequest(syncRules, bucket, start)];
177
+ const syncConfigContent = this.getSyncConfigContent();
178
+ const checkpoint = await this.storage!.getCheckpoint();
179
+ const map = [bucketRequest(syncConfigContent, bucket, start)];
175
180
  const batch = this.storage!.getBucketDataBatch(checkpoint, map);
176
181
  const batches = await fromAsync(batch);
177
182
  return batches[0]?.chunkData.data ?? [];
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  InternalOpId,
3
3
  OplogEntry,
4
- PersistedSyncRules,
5
- PersistedSyncRulesContent,
4
+ ParsedSyncConfigSet,
5
+ PersistedSyncConfigContent,
6
+ ReplicationCheckpoint,
6
7
  SyncRulesBucketStorage
7
8
  } from '@powersync/service-core';
8
9
  import { bucketRequest } from './general-utils.js';
@@ -10,14 +11,14 @@ import { fromAsync } from './stream_utils.js';
10
11
 
11
12
  export class StorageDataHelpers {
12
13
  storage: SyncRulesBucketStorage;
13
- syncRules: PersistedSyncRulesContent | PersistedSyncRules;
14
+ syncRules: PersistedSyncConfigContent | ParsedSyncConfigSet;
14
15
 
15
- constructor(storage: SyncRulesBucketStorage, syncRules: PersistedSyncRulesContent | PersistedSyncRules) {
16
+ constructor(storage: SyncRulesBucketStorage, syncRules: PersistedSyncConfigContent | ParsedSyncConfigSet) {
16
17
  this.storage = storage;
17
18
  this.syncRules = syncRules;
18
19
  }
19
20
 
20
- async getBucketData(bucket: string, checkpoint: InternalOpId, start?: InternalOpId | string | undefined) {
21
+ async getBucketData(bucket: string, checkpoint: ReplicationCheckpoint, start?: InternalOpId | string | undefined) {
21
22
  start ??= 0n;
22
23
  if (typeof start == 'string') {
23
24
  start = BigInt(start);
@@ -37,7 +38,7 @@ export class StorageDataHelpers {
37
38
  return data;
38
39
  }
39
40
 
40
- async getBucketsDataBatch(buckets: Record<string, InternalOpId>, checkpoint: InternalOpId) {
41
+ async getBucketsDataBatch(buckets: Record<string, InternalOpId>, checkpoint: ReplicationCheckpoint) {
41
42
  const map = Object.entries(buckets).map(([bucket, start]) => bucketRequest(this.syncRules, bucket, start));
42
43
  return fromAsync(this.storage!.getBucketDataBatch(checkpoint, map));
43
44
  }
@@ -9,7 +9,7 @@ import { expect } from 'vitest';
9
9
  * All other operations are replaced with a single CLEAR operation,
10
10
  * summing their checksums, and using a 0 as an op_id.
11
11
  *
12
- * This is the function $r(B)$, as described in /docs/bucket-properties.md.
12
+ * This is the function $r(B)$, as described in /docs/storage/bucket-properties.md.
13
13
  */
14
14
  export function reduceBucket(operations: utils.OplogEntry[]) {
15
15
  let rowState = new Map<string, utils.OplogEntry>();
@@ -63,7 +63,7 @@ import { reduceBucket } from '@/util/utils.js';
63
63
  import { expect } from 'vitest';
64
64
 
65
65
  /**
66
- * Validate this property, as described in /docs/bucket-properties.md:
66
+ * Validate this property, as described in /docs/storage/bucket-properties.md:
67
67
  *
68
68
  * $r(B_{[..id_n]}) = r(r(B_{[..id_i]}) \cup B_{[id_{i+1}..id_n]}) \;\forall\; i \in [1..n]$
69
69
  *
@@ -87,7 +87,7 @@ export function validateBucket(bucket: utils.OplogEntry[]) {
87
87
 
88
88
  /**
89
89
  * Validate these properties for a bucket $B$ and its compacted version $B'$,:
90
- * as described in /docs/bucket-properties.md:
90
+ * as described in /docs/storage/bucket-properties.md:
91
91
  *
92
92
  * 1. $r(B) = r(B')$
93
93
  * 2. $r(B_{[..c]}) = r(r(B_{[..c_i]}) \cup B'_{[c_i+1..c]}) \;\forall\; c_i \in B$
@@ -4,7 +4,7 @@ import * as bson from 'bson';
4
4
 
5
5
  export const ZERO_LSN = '0/0';
6
6
 
7
- export const PARSE_OPTIONS: storage.ParseSyncRulesOptions = {
7
+ export const PARSE_OPTIONS: storage.ParseSyncConfigOptions = {
8
8
  defaultSchema: 'public'
9
9
  };
10
10
 
@@ -14,6 +14,31 @@ export const BATCH_OPTIONS: storage.CreateWriterOptions = {
14
14
  storeCurrentData: true
15
15
  };
16
16
 
17
+ export function testCheckpoint(checkpoint: InternalOpId, lsn: string | null = null): storage.ReplicationCheckpoint {
18
+ return {
19
+ checkpoint,
20
+ lsn,
21
+ async getParameterSets() {
22
+ return [];
23
+ }
24
+ };
25
+ }
26
+
27
+ /**
28
+ * Deploy a sync config and return both the replication stream (for {@link storage.BucketStorageFactory.getInstance})
29
+ * and the deployed config content (for parsing / bucket requests).
30
+ *
31
+ * Replication streams and sync config content are separate concerns since one stream can hold multiple configs.
32
+ */
33
+ export async function deploySyncRules(
34
+ factory: storage.BucketStorageFactory,
35
+ options: storage.UpdateSyncRulesOptions
36
+ ): Promise<{ stream: storage.PersistedReplicationStream; content: storage.PersistedSyncConfigContent }> {
37
+ const stream = await factory.updateSyncRules(options);
38
+ const content = stream.syncConfigContent[0];
39
+ return { stream, content };
40
+ }
41
+
17
42
  /**
18
43
  * With newer storage versions, we need actual test tables, resolved via the writer.
19
44
  */
@@ -78,9 +103,9 @@ export function getBatchData(
78
103
  }
79
104
 
80
105
  function isParsedSyncRules(
81
- syncRules: storage.PersistedSyncRulesContent | storage.PersistedSyncRules
82
- ): syncRules is storage.PersistedSyncRules {
83
- return (syncRules as storage.PersistedSyncRules).syncConfigWithErrors !== undefined;
106
+ syncRules: storage.PersistedSyncConfigContent | storage.ParsedSyncConfigSet
107
+ ): syncRules is storage.ParsedSyncConfigSet {
108
+ return (syncRules as storage.ParsedSyncConfigSet).syncConfigs !== undefined;
84
109
  }
85
110
 
86
111
  /**
@@ -88,7 +113,7 @@ function isParsedSyncRules(
88
113
  * This converts a bucket name like "global[]" into the actual bucket name, for use in tests.
89
114
  */
90
115
  export function bucketRequest(
91
- syncRules: storage.PersistedSyncRulesContent | storage.PersistedSyncRules,
116
+ syncRules: storage.PersistedSyncConfigContent | storage.ParsedSyncConfigSet,
92
117
  bucket: string,
93
118
  start?: InternalOpId | string | number
94
119
  ): BucketDataRequest {
@@ -97,10 +122,13 @@ export function bucketRequest(
97
122
  const parameterStart = bucket.indexOf('[');
98
123
  const definitionName = bucket.substring(0, parameterStart);
99
124
  const parameters = bucket.substring(parameterStart);
100
- const source = parsed.syncConfigWithErrors.config.bucketDataSources.find((b) => b.uniqueName === definitionName);
125
+ const availableSources = parsed.syncConfigs.flatMap((config) => config.config.bucketDataSources);
126
+ const source = availableSources.find((b) => b.uniqueName === definitionName);
101
127
 
102
128
  if (source == null) {
103
- throw new Error(`Failed to find global bucket ${bucket}`);
129
+ throw new Error(
130
+ `Failed to find global bucket ${bucket}. Available: ${availableSources.map((s) => s.uniqueName).join(',')}`
131
+ );
104
132
  }
105
133
  const bucketName = hydrationState.getBucketSourceScope(source).bucketPrefix + parameters;
106
134
  return {
@@ -17,6 +17,7 @@ bucket_definitions:
17
17
  `)
18
18
  );
19
19
  const bucketStorage = factory.getInstance(syncRules);
20
+ const syncRulesContent = syncRules.syncConfigContent[0];
20
21
 
21
22
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
22
23
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -53,11 +54,13 @@ bucket_definitions:
53
54
 
54
55
  const checkpoint = writer.last_flushed_op!;
55
56
 
56
- const request = bucketRequest(syncRules, 'global[]');
57
+ const request = bucketRequest(syncRulesContent, 'global[]');
57
58
 
58
- const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
59
+ const batchBefore = await test_utils.oneFromAsync(
60
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
61
+ );
59
62
  const dataBefore = batchBefore.chunkData.data;
60
- const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
63
+ const checksumBefore = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request]);
61
64
 
62
65
  expect(dataBefore).toMatchObject([
63
66
  {
@@ -86,11 +89,13 @@ bucket_definitions:
86
89
  minChangeRatio: 0
87
90
  });
88
91
 
89
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
92
+ const batchAfter = await test_utils.oneFromAsync(
93
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
94
+ );
90
95
  const dataAfter = batchAfter.chunkData.data;
91
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
96
+ const checksumAfter = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request]);
92
97
  bucketStorage.clearChecksumCache();
93
- const checksumAfter2 = await bucketStorage.getChecksums(checkpoint, [request]);
98
+ const checksumAfter2 = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request]);
94
99
 
95
100
  expect(batchAfter.targetOp).toEqual(3n);
96
101
  expect(dataAfter).toMatchObject([
@@ -124,6 +129,7 @@ bucket_definitions:
124
129
  `)
125
130
  );
126
131
  const bucketStorage = factory.getInstance(syncRules);
132
+ const syncRulesContent = syncRules.syncConfigContent[0];
127
133
 
128
134
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
129
135
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -168,11 +174,13 @@ bucket_definitions:
168
174
  await writer.flush();
169
175
 
170
176
  const checkpoint = writer.last_flushed_op!;
171
- const request = bucketRequest(syncRules, 'global[]');
177
+ const request = bucketRequest(syncRulesContent, 'global[]');
172
178
 
173
- const batchBefore = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
179
+ const batchBefore = await test_utils.oneFromAsync(
180
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
181
+ );
174
182
  const dataBefore = batchBefore.chunkData.data;
175
- const checksumBefore = await bucketStorage.getChecksums(checkpoint, [request]);
183
+ const checksumBefore = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request]);
176
184
 
177
185
  // op_id sequence depends on the storage implementation
178
186
  expect(dataBefore).toMatchObject([
@@ -202,10 +210,12 @@ bucket_definitions:
202
210
  minChangeRatio: 0
203
211
  });
204
212
 
205
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint, [request]));
213
+ const batchAfter = await test_utils.oneFromAsync(
214
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint), [request])
215
+ );
206
216
  const dataAfter = batchAfter.chunkData.data;
207
217
  bucketStorage.clearChecksumCache();
208
- const checksumAfter = await bucketStorage.getChecksums(checkpoint, [request]);
218
+ const checksumAfter = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint), [request]);
209
219
 
210
220
  expect(batchAfter.targetOp).toBeLessThanOrEqual(checkpoint);
211
221
  expect(dataAfter).toMatchObject([
@@ -240,6 +250,7 @@ bucket_definitions:
240
250
  `)
241
251
  );
242
252
  const bucketStorage = factory.getInstance(syncRules);
253
+ const syncRulesContent = syncRules.syncConfigContent[0];
243
254
 
244
255
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
245
256
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -275,7 +286,7 @@ bucket_definitions:
275
286
  await writer.flush();
276
287
 
277
288
  const checkpoint1 = writer.last_flushed_op!;
278
- const request = bucketRequest(syncRules, 'global[]');
289
+ const request = bucketRequest(syncRulesContent, 'global[]');
279
290
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
280
291
  const testTable2 = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
281
292
  await writer2.save({
@@ -298,10 +309,12 @@ bucket_definitions:
298
309
  minChangeRatio: 0
299
310
  });
300
311
 
301
- const batchAfter = await test_utils.oneFromAsync(bucketStorage.getBucketDataBatch(checkpoint2, [request]));
312
+ const batchAfter = await test_utils.oneFromAsync(
313
+ bucketStorage.getBucketDataBatch(test_utils.testCheckpoint(checkpoint2), [request])
314
+ );
302
315
  const dataAfter = batchAfter.chunkData.data;
303
316
  await bucketStorage.clearChecksumCache();
304
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
317
+ const checksumAfter = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint2), [request]);
305
318
 
306
319
  expect(dataAfter).toMatchObject([
307
320
  {
@@ -328,6 +341,7 @@ bucket_definitions:
328
341
  - select * from test where b = bucket.b`)
329
342
  );
330
343
  const bucketStorage = factory.getInstance(syncRules);
344
+ const syncRulesContent = syncRules.syncConfigContent[0];
331
345
 
332
346
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
333
347
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -412,8 +426,8 @@ bucket_definitions:
412
426
 
413
427
  const batchAfter = await test_utils.fromAsync(
414
428
  bucketStorage.getBucketDataBatch(
415
- checkpoint,
416
- bucketRequestMap(syncRules, [
429
+ test_utils.testCheckpoint(checkpoint),
430
+ bucketRequestMap(syncRulesContent, [
417
431
  ['grouped["b1"]', 0n],
418
432
  ['grouped["b2"]', 0n]
419
433
  ])
@@ -458,6 +472,7 @@ bucket_definitions:
458
472
  `)
459
473
  );
460
474
  const bucketStorage = factory.getInstance(syncRules);
475
+ const syncRulesContent = syncRules.syncConfigContent[0];
461
476
 
462
477
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
463
478
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -513,9 +528,9 @@ bucket_definitions:
513
528
  await writer2.commit('2/1');
514
529
  await writer2.flush();
515
530
  const checkpoint2 = writer2.last_flushed_op!;
516
- const request = bucketRequest(syncRules, 'global[]');
531
+ const request = bucketRequest(syncRulesContent, 'global[]');
517
532
  await bucketStorage.clearChecksumCache();
518
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
533
+ const checksumAfter = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint2), [request]);
519
534
  const globalChecksum = checksumAfter.get(request.bucket);
520
535
  expect(globalChecksum).toMatchObject({
521
536
  bucket: request.bucket,
@@ -536,6 +551,7 @@ bucket_definitions:
536
551
  `)
537
552
  );
538
553
  const bucketStorage = factory.getInstance(syncRules);
554
+ const syncRulesContent = syncRules.syncConfigContent[0];
539
555
 
540
556
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
541
557
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -562,7 +578,10 @@ bucket_definitions:
562
578
  await writer.flush();
563
579
 
564
580
  // Get checksums here just to populate the cache
565
- await bucketStorage.getChecksums(writer.last_flushed_op!, bucketRequests(syncRules, ['global[]']));
581
+ await bucketStorage.getChecksums(
582
+ test_utils.testCheckpoint(writer.last_flushed_op!),
583
+ bucketRequests(syncRulesContent, ['global[]'])
584
+ );
566
585
  await using writer2 = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
567
586
  const testTable2 = await test_utils.resolveTestTable(writer2, 'test', ['id'], config);
568
587
  await writer2.save({
@@ -585,9 +604,9 @@ bucket_definitions:
585
604
  });
586
605
 
587
606
  const checkpoint2 = writer2.last_flushed_op!;
588
- const request = bucketRequest(syncRules, 'global[]');
607
+ const request = bucketRequest(syncRulesContent, 'global[]');
589
608
  // Check that the checksum was correctly updated with the clear operation after having a cached checksum
590
- const checksumAfter = await bucketStorage.getChecksums(checkpoint2, [request]);
609
+ const checksumAfter = await bucketStorage.getChecksums(test_utils.testCheckpoint(checkpoint2), [request]);
591
610
  const globalChecksum = checksumAfter.get(request.bucket);
592
611
  expect(globalChecksum).toMatchObject({
593
612
  bucket: request.bucket,
@@ -607,6 +626,7 @@ bucket_definitions:
607
626
  `)
608
627
  );
609
628
  const bucketStorage = factory.getInstance(syncRules);
629
+ const syncRulesContent = syncRules.syncConfigContent[0];
610
630
 
611
631
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
612
632
  const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
@@ -646,7 +666,10 @@ bucket_definitions:
646
666
  });
647
667
 
648
668
  const batchAfterDefaultCompact = await test_utils.oneFromAsync(
649
- bucketStorage.getBucketDataBatch(checkpoint2, bucketRequestMap(syncRules, [['global[]', 0n]]))
669
+ bucketStorage.getBucketDataBatch(
670
+ test_utils.testCheckpoint(checkpoint2),
671
+ bucketRequestMap(syncRulesContent, [['global[]', 0n]])
672
+ )
650
673
  );
651
674
 
652
675
  // Operation 1 should remain a PUT because op_id=2 is above the default maxOpId checkpoint.
@@ -42,7 +42,7 @@ bucket_definitions:
42
42
  await using writer = await bucketStorage.createWriter(test_utils.BATCH_OPTIONS);
43
43
  await writer.markAllSnapshotDone('1/1');
44
44
 
45
- const writeCheckpoint = await bucketStorage.createManagedWriteCheckpoint({
45
+ const writeCheckpoint = await createManagedWriteCheckpoint(bucketStorage, {
46
46
  heads: { '1': '5/0' },
47
47
  user_id: 'user1'
48
48
  });
@@ -102,7 +102,7 @@ bucket_definitions:
102
102
  }
103
103
  });
104
104
 
105
- const writeCheckpoint = await bucketStorage.createManagedWriteCheckpoint({
105
+ const writeCheckpoint = await createManagedWriteCheckpoint(bucketStorage, {
106
106
  heads: { '1': '6/0' },
107
107
  user_id: 'user1'
108
108
  });
@@ -302,3 +302,13 @@ bucket_definitions:
302
302
  });
303
303
  });
304
304
  }
305
+
306
+ async function createManagedWriteCheckpoint(
307
+ bucketStorage: storage.SyncRulesBucketStorage,
308
+ checkpoint: storage.ManagedWriteCheckpointOptions
309
+ ) {
310
+ const checkpoints = await bucketStorage.createManagedWriteCheckpoints([checkpoint]);
311
+ const writeCheckpoint = checkpoints.get(checkpoint.user_id);
312
+ expect(writeCheckpoint).not.toBeUndefined();
313
+ return writeCheckpoint!;
314
+ }