@powersync/service-core-tests 0.0.0-dev-20250829094737 → 0.0.0-dev-20250903064005

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 (34) hide show
  1. package/CHANGELOG.md +21 -4
  2. package/dist/tests/register-compacting-tests.js +68 -0
  3. package/dist/tests/register-compacting-tests.js.map +1 -1
  4. package/dist/tests/register-data-storage-checkpoint-tests.d.ts +12 -0
  5. package/dist/tests/register-data-storage-checkpoint-tests.js +357 -0
  6. package/dist/tests/register-data-storage-checkpoint-tests.js.map +1 -0
  7. package/dist/tests/register-data-storage-data-tests.d.ts +12 -0
  8. package/dist/tests/{register-data-storage-tests.js → register-data-storage-data-tests.js} +151 -1035
  9. package/dist/tests/register-data-storage-data-tests.js.map +1 -0
  10. package/dist/tests/{register-data-storage-tests.d.ts → register-data-storage-parameter-tests.d.ts} +1 -2
  11. package/dist/tests/register-data-storage-parameter-tests.js +707 -0
  12. package/dist/tests/register-data-storage-parameter-tests.js.map +1 -0
  13. package/dist/tests/register-report-tests.d.ts +78 -0
  14. package/dist/tests/register-report-tests.js +119 -0
  15. package/dist/tests/register-report-tests.js.map +1 -0
  16. package/dist/tests/register-sync-tests.js +2 -1
  17. package/dist/tests/register-sync-tests.js.map +1 -1
  18. package/dist/tests/tests-index.d.ts +5 -1
  19. package/dist/tests/tests-index.js +5 -1
  20. package/dist/tests/tests-index.js.map +1 -1
  21. package/dist/tests/util.d.ts +1 -0
  22. package/dist/tests/util.js +3 -0
  23. package/dist/tests/util.js.map +1 -0
  24. package/package.json +2 -2
  25. package/src/tests/register-compacting-tests.ts +63 -0
  26. package/src/tests/register-data-storage-checkpoint-tests.ts +277 -0
  27. package/src/tests/{register-data-storage-tests.ts → register-data-storage-data-tests.ts} +38 -865
  28. package/src/tests/register-data-storage-parameter-tests.ts +613 -0
  29. package/src/tests/register-report-tests.ts +136 -0
  30. package/src/tests/register-sync-tests.ts +2 -1
  31. package/src/tests/tests-index.ts +5 -1
  32. package/src/tests/util.ts +3 -0
  33. package/tsconfig.tsbuildinfo +1 -1
  34. package/dist/tests/register-data-storage-tests.js.map +0 -1
@@ -0,0 +1,277 @@
1
+ import { storage } from '@powersync/service-core';
2
+ import { expect, test } from 'vitest';
3
+ import * as test_utils from '../test-utils/test-utils-index.js';
4
+
5
+ /**
6
+ * @example
7
+ * ```TypeScript
8
+ *
9
+ * describe('store - mongodb', function () {
10
+ * registerDataStorageCheckpointTests(MONGO_STORAGE_FACTORY);
11
+ * });
12
+ *
13
+ * ```
14
+ */
15
+ export function registerDataStorageCheckpointTests(generateStorageFactory: storage.TestStorageFactory) {
16
+ test('managed write checkpoints - checkpoint after write', async (context) => {
17
+ await using factory = await generateStorageFactory();
18
+ const r = await factory.configureSyncRules({
19
+ content: `
20
+ bucket_definitions:
21
+ mybucket:
22
+ data: []
23
+ `,
24
+ validate: false
25
+ });
26
+ const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
27
+
28
+ const abortController = new AbortController();
29
+ context.onTestFinished(() => abortController.abort());
30
+ const iter = bucketStorage
31
+ .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
32
+ [Symbol.asyncIterator]();
33
+
34
+ const writeCheckpoint = await bucketStorage.createManagedWriteCheckpoint({
35
+ heads: { '1': '5/0' },
36
+ user_id: 'user1'
37
+ });
38
+
39
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
40
+ await batch.keepalive('5/0');
41
+ });
42
+
43
+ const result = await iter.next();
44
+ expect(result).toMatchObject({
45
+ done: false,
46
+ value: {
47
+ base: {
48
+ checkpoint: 0n,
49
+ lsn: '5/0'
50
+ },
51
+ writeCheckpoint: writeCheckpoint
52
+ }
53
+ });
54
+ });
55
+
56
+ test('managed write checkpoints - write after checkpoint', async (context) => {
57
+ await using factory = await generateStorageFactory();
58
+ const r = await factory.configureSyncRules({
59
+ content: `
60
+ bucket_definitions:
61
+ mybucket:
62
+ data: []
63
+ `,
64
+ validate: false
65
+ });
66
+ const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
67
+
68
+ const abortController = new AbortController();
69
+ context.onTestFinished(() => abortController.abort());
70
+ const iter = bucketStorage
71
+ .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
72
+ [Symbol.asyncIterator]();
73
+
74
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
75
+ await batch.keepalive('5/0');
76
+ });
77
+
78
+ const result = await iter.next();
79
+ expect(result).toMatchObject({
80
+ done: false,
81
+ value: {
82
+ base: {
83
+ checkpoint: 0n,
84
+ lsn: '5/0'
85
+ },
86
+ writeCheckpoint: null
87
+ }
88
+ });
89
+
90
+ const writeCheckpoint = await bucketStorage.createManagedWriteCheckpoint({
91
+ heads: { '1': '6/0' },
92
+ user_id: 'user1'
93
+ });
94
+ // We have to trigger a new keepalive after the checkpoint, at least to cover postgres storage.
95
+ // This is what is effetively triggered with RouteAPI.createReplicationHead().
96
+ // MongoDB storage doesn't explicitly need this anymore.
97
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
98
+ await batch.keepalive('6/0');
99
+ });
100
+
101
+ let result2 = await iter.next();
102
+ if (result2.value?.base?.lsn == '5/0') {
103
+ // Events could arrive in a different order in some cases - this caters for it
104
+ result2 = await iter.next();
105
+ }
106
+ expect(result2).toMatchObject({
107
+ done: false,
108
+ value: {
109
+ base: {
110
+ checkpoint: 0n,
111
+ lsn: '6/0'
112
+ },
113
+ writeCheckpoint: writeCheckpoint
114
+ }
115
+ });
116
+ });
117
+
118
+ test('custom write checkpoints - checkpoint after write', async (context) => {
119
+ await using factory = await generateStorageFactory();
120
+ const r = await factory.configureSyncRules({
121
+ content: `
122
+ bucket_definitions:
123
+ mybucket:
124
+ data: []
125
+ `,
126
+ validate: false
127
+ });
128
+ const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
129
+ bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
130
+
131
+ const abortController = new AbortController();
132
+ context.onTestFinished(() => abortController.abort());
133
+ const iter = bucketStorage
134
+ .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
135
+ [Symbol.asyncIterator]();
136
+
137
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
138
+ await batch.addCustomWriteCheckpoint({
139
+ checkpoint: 5n,
140
+ user_id: 'user1'
141
+ });
142
+ await batch.flush();
143
+ await batch.keepalive('5/0');
144
+ });
145
+
146
+ const result = await iter.next();
147
+ expect(result).toMatchObject({
148
+ done: false,
149
+ value: {
150
+ base: {
151
+ lsn: '5/0'
152
+ },
153
+ writeCheckpoint: 5n
154
+ }
155
+ });
156
+ });
157
+
158
+ test('custom write checkpoints - standalone checkpoint', async (context) => {
159
+ await using factory = await generateStorageFactory();
160
+ const r = await factory.configureSyncRules({
161
+ content: `
162
+ bucket_definitions:
163
+ mybucket:
164
+ data: []
165
+ `,
166
+ validate: false
167
+ });
168
+ const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
169
+ bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
170
+
171
+ const abortController = new AbortController();
172
+ context.onTestFinished(() => abortController.abort());
173
+ const iter = bucketStorage
174
+ .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
175
+ [Symbol.asyncIterator]();
176
+
177
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
178
+ // Flush to clear state
179
+ await batch.flush();
180
+
181
+ await batch.addCustomWriteCheckpoint({
182
+ checkpoint: 5n,
183
+ user_id: 'user1'
184
+ });
185
+ await batch.flush();
186
+ await batch.keepalive('5/0');
187
+ });
188
+
189
+ const result = await iter.next();
190
+ expect(result).toMatchObject({
191
+ done: false,
192
+ value: {
193
+ base: {
194
+ lsn: '5/0'
195
+ },
196
+ writeCheckpoint: 5n
197
+ }
198
+ });
199
+ });
200
+
201
+ test('custom write checkpoints - write after checkpoint', async (context) => {
202
+ await using factory = await generateStorageFactory();
203
+ const r = await factory.configureSyncRules({
204
+ content: `
205
+ bucket_definitions:
206
+ mybucket:
207
+ data: []
208
+ `,
209
+ validate: false
210
+ });
211
+ const bucketStorage = factory.getInstance(r.persisted_sync_rules!);
212
+ bucketStorage.setWriteCheckpointMode(storage.WriteCheckpointMode.CUSTOM);
213
+
214
+ const abortController = new AbortController();
215
+ context.onTestFinished(() => abortController.abort());
216
+ const iter = bucketStorage
217
+ .watchCheckpointChanges({ user_id: 'user1', signal: abortController.signal })
218
+ [Symbol.asyncIterator]();
219
+
220
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
221
+ await batch.keepalive('5/0');
222
+ });
223
+
224
+ const result = await iter.next();
225
+ expect(result).toMatchObject({
226
+ done: false,
227
+ value: {
228
+ base: {
229
+ lsn: '5/0'
230
+ },
231
+ writeCheckpoint: null
232
+ }
233
+ });
234
+
235
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
236
+ batch.addCustomWriteCheckpoint({
237
+ checkpoint: 6n,
238
+ user_id: 'user1'
239
+ });
240
+ await batch.flush();
241
+ await batch.keepalive('6/0');
242
+ });
243
+
244
+ let result2 = await iter.next();
245
+ expect(result2).toMatchObject({
246
+ done: false,
247
+ value: {
248
+ base: {
249
+ // can be 5/0 or 6/0 - actual value not relevant for custom write checkpoints
250
+ // lsn: '6/0'
251
+ },
252
+ writeCheckpoint: 6n
253
+ }
254
+ });
255
+
256
+ await bucketStorage.startBatch(test_utils.BATCH_OPTIONS, async (batch) => {
257
+ batch.addCustomWriteCheckpoint({
258
+ checkpoint: 7n,
259
+ user_id: 'user1'
260
+ });
261
+ await batch.flush();
262
+ await batch.keepalive('7/0');
263
+ });
264
+
265
+ let result3 = await iter.next();
266
+ expect(result3).toMatchObject({
267
+ done: false,
268
+ value: {
269
+ base: {
270
+ // can be 5/0, 6/0 or 7/0 - actual value not relevant for custom write checkpoints
271
+ // lsn: '7/0'
272
+ },
273
+ writeCheckpoint: 7n
274
+ }
275
+ });
276
+ });
277
+ }