@powersync/service-core-tests 0.14.0 → 0.15.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 +40 -0
- package/dist/test-utils/general-utils.d.ts +22 -3
- package/dist/test-utils/general-utils.js +56 -3
- package/dist/test-utils/general-utils.js.map +1 -1
- package/dist/test-utils/stream_utils.js +2 -2
- package/dist/test-utils/stream_utils.js.map +1 -1
- package/dist/tests/register-compacting-tests.d.ts +1 -1
- package/dist/tests/register-compacting-tests.js +360 -297
- 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 +59 -48
- 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 +1112 -612
- 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 +273 -254
- 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 +83 -87
- 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 +479 -451
- 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 +81 -4
- package/src/test-utils/stream_utils.ts +2 -2
- package/src/tests/register-compacting-tests.ts +376 -322
- package/src/tests/register-data-storage-checkpoint-tests.ts +85 -53
- package/src/tests/register-data-storage-data-tests.ts +1050 -559
- package/src/tests/register-data-storage-parameter-tests.ts +330 -288
- package/src/tests/register-parameter-compacting-tests.ts +87 -90
- package/src/tests/register-sync-tests.ts +390 -380
- package/src/tests/util.ts +46 -17
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -57,11 +57,9 @@ import * as timers from 'timers/promises';
|
|
|
57
57
|
import { fileURLToPath } from 'url';
|
|
58
58
|
import { expect, test } from 'vitest';
|
|
59
59
|
import * as test_utils from '../test-utils/test-utils-index.js';
|
|
60
|
-
import { METRICS_HELPER } from '../test-utils/test-utils-index.js';
|
|
61
|
-
import { bucketRequest } from './util.js';
|
|
60
|
+
import { bucketRequest, METRICS_HELPER } from '../test-utils/test-utils-index.js';
|
|
62
61
|
const __filename = fileURLToPath(import.meta.url);
|
|
63
62
|
const __dirname = path.dirname(__filename);
|
|
64
|
-
const TEST_TABLE = test_utils.makeTestTable('test', ['id']);
|
|
65
63
|
const BASIC_SYNC_RULES = `
|
|
66
64
|
bucket_definitions:
|
|
67
65
|
mybucket:
|
|
@@ -77,7 +75,11 @@ export const SYNC_SNAPSHOT_PATH = path.resolve(__dirname, '../__snapshots/sync.t
|
|
|
77
75
|
* });
|
|
78
76
|
* ```
|
|
79
77
|
*/
|
|
80
|
-
export function registerSyncTests(
|
|
78
|
+
export function registerSyncTests(configOrFactory, options = {}) {
|
|
79
|
+
const config = typeof configOrFactory == 'function'
|
|
80
|
+
? { factory: configOrFactory, tableIdStrings: options.tableIdStrings ?? true }
|
|
81
|
+
: configOrFactory;
|
|
82
|
+
const factory = config.factory;
|
|
81
83
|
createCoreAPIMetrics(METRICS_HELPER.metricsEngine);
|
|
82
84
|
const tracker = new sync.RequestTracker(METRICS_HELPER.metricsEngine);
|
|
83
85
|
const syncContext = new sync.SyncContext({
|
|
@@ -99,27 +101,28 @@ export function registerSyncTests(factory, options = {}) {
|
|
|
99
101
|
content: BASIC_SYNC_RULES
|
|
100
102
|
});
|
|
101
103
|
const bucketStorage = f.getInstance(syncRules);
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
104
|
+
const writer = __addDisposableResource(env_1, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
105
|
+
const sourceTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
106
|
+
await writer.markAllSnapshotDone('0/1');
|
|
107
|
+
await writer.save({
|
|
108
|
+
sourceTable,
|
|
109
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
110
|
+
after: {
|
|
111
|
+
id: 't1',
|
|
112
|
+
description: 'Test 1'
|
|
113
|
+
},
|
|
114
|
+
afterReplicaId: 't1'
|
|
115
|
+
});
|
|
116
|
+
await writer.save({
|
|
117
|
+
sourceTable,
|
|
118
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
119
|
+
after: {
|
|
120
|
+
id: 't2',
|
|
121
|
+
description: 'Test 2'
|
|
122
|
+
},
|
|
123
|
+
afterReplicaId: 't2'
|
|
122
124
|
});
|
|
125
|
+
await writer.commit('0/1');
|
|
123
126
|
const stream = sync.streamResponse({
|
|
124
127
|
syncContext,
|
|
125
128
|
bucketStorage: bucketStorage,
|
|
@@ -164,27 +167,28 @@ bucket_definitions:
|
|
|
164
167
|
`
|
|
165
168
|
});
|
|
166
169
|
const bucketStorage = f.getInstance(syncRules);
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
170
|
+
const writer = __addDisposableResource(env_2, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
171
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
172
|
+
await writer.markAllSnapshotDone('0/1');
|
|
173
|
+
await writer.save({
|
|
174
|
+
sourceTable: testTable,
|
|
175
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
176
|
+
after: {
|
|
177
|
+
id: 't1',
|
|
178
|
+
description: 'Test 1'
|
|
179
|
+
},
|
|
180
|
+
afterReplicaId: 't1'
|
|
181
|
+
});
|
|
182
|
+
await writer.save({
|
|
183
|
+
sourceTable: testTable,
|
|
184
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
185
|
+
after: {
|
|
186
|
+
id: 'earlier',
|
|
187
|
+
description: 'Test 2'
|
|
188
|
+
},
|
|
189
|
+
afterReplicaId: 'earlier'
|
|
187
190
|
});
|
|
191
|
+
await writer.commit('0/1');
|
|
188
192
|
const stream = sync.streamResponse({
|
|
189
193
|
syncContext,
|
|
190
194
|
bucketStorage,
|
|
@@ -229,30 +233,31 @@ bucket_definitions:
|
|
|
229
233
|
`
|
|
230
234
|
});
|
|
231
235
|
const bucketStorage = f.getInstance(syncRules);
|
|
232
|
-
await bucketStorage.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
+
const writer = __addDisposableResource(env_3, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
237
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
238
|
+
await writer.markAllSnapshotDone('0/1');
|
|
239
|
+
// Initial data: Add one priority row and 10k low-priority rows.
|
|
240
|
+
await writer.save({
|
|
241
|
+
sourceTable: testTable,
|
|
242
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
243
|
+
after: {
|
|
244
|
+
id: 'highprio',
|
|
245
|
+
description: 'High priority row'
|
|
246
|
+
},
|
|
247
|
+
afterReplicaId: 'highprio'
|
|
248
|
+
});
|
|
249
|
+
for (let i = 0; i < 10_000; i++) {
|
|
250
|
+
await writer.save({
|
|
251
|
+
sourceTable: testTable,
|
|
236
252
|
tag: storage.SaveOperationTag.INSERT,
|
|
237
253
|
after: {
|
|
238
|
-
id:
|
|
239
|
-
description: '
|
|
254
|
+
id: `${i}`,
|
|
255
|
+
description: 'low prio'
|
|
240
256
|
},
|
|
241
|
-
afterReplicaId:
|
|
257
|
+
afterReplicaId: `${i}`
|
|
242
258
|
});
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
sourceTable: TEST_TABLE,
|
|
246
|
-
tag: storage.SaveOperationTag.INSERT,
|
|
247
|
-
after: {
|
|
248
|
-
id: `${i}`,
|
|
249
|
-
description: 'low prio'
|
|
250
|
-
},
|
|
251
|
-
afterReplicaId: `${i}`
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
await batch.commit('0/1');
|
|
255
|
-
});
|
|
259
|
+
}
|
|
260
|
+
await writer.commit('0/1');
|
|
256
261
|
const stream = sync.streamResponse({
|
|
257
262
|
syncContext,
|
|
258
263
|
bucketStorage,
|
|
@@ -276,19 +281,17 @@ bucket_definitions:
|
|
|
276
281
|
if ('partial_checkpoint_complete' in next) {
|
|
277
282
|
if (sentCheckpoints == 1) {
|
|
278
283
|
// Save new data to interrupt the low-priority sync.
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
afterReplicaId: 'highprio2'
|
|
289
|
-
});
|
|
290
|
-
await batch.commit('0/2');
|
|
284
|
+
// Add another high-priority row. This should interrupt the long-running low-priority sync.
|
|
285
|
+
await writer.save({
|
|
286
|
+
sourceTable: testTable,
|
|
287
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
288
|
+
after: {
|
|
289
|
+
id: 'highprio2',
|
|
290
|
+
description: 'Another high-priority row'
|
|
291
|
+
},
|
|
292
|
+
afterReplicaId: 'highprio2'
|
|
291
293
|
});
|
|
294
|
+
await writer.commit('0/2');
|
|
292
295
|
}
|
|
293
296
|
else {
|
|
294
297
|
// Low-priority sync from the first checkpoint was interrupted. This should not happen before
|
|
@@ -340,30 +343,31 @@ bucket_definitions:
|
|
|
340
343
|
`
|
|
341
344
|
});
|
|
342
345
|
const bucketStorage = f.getInstance(syncRules);
|
|
343
|
-
await bucketStorage.
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
346
|
+
const writer = __addDisposableResource(env_4, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
347
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
348
|
+
await writer.markAllSnapshotDone('0/1');
|
|
349
|
+
// Initial data: Add one priority row and 10k low-priority rows.
|
|
350
|
+
await writer.save({
|
|
351
|
+
sourceTable: testTable,
|
|
352
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
353
|
+
after: {
|
|
354
|
+
id: 'highprio',
|
|
355
|
+
description: 'user_one'
|
|
356
|
+
},
|
|
357
|
+
afterReplicaId: 'highprio'
|
|
358
|
+
});
|
|
359
|
+
for (let i = 0; i < 10_000; i++) {
|
|
360
|
+
await writer.save({
|
|
361
|
+
sourceTable: testTable,
|
|
347
362
|
tag: storage.SaveOperationTag.INSERT,
|
|
348
363
|
after: {
|
|
349
|
-
id:
|
|
350
|
-
description: '
|
|
364
|
+
id: `${i}`,
|
|
365
|
+
description: 'low prio'
|
|
351
366
|
},
|
|
352
|
-
afterReplicaId:
|
|
367
|
+
afterReplicaId: `${i}`
|
|
353
368
|
});
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
sourceTable: TEST_TABLE,
|
|
357
|
-
tag: storage.SaveOperationTag.INSERT,
|
|
358
|
-
after: {
|
|
359
|
-
id: `${i}`,
|
|
360
|
-
description: 'low prio'
|
|
361
|
-
},
|
|
362
|
-
afterReplicaId: `${i}`
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
await batch.commit('0/1');
|
|
366
|
-
});
|
|
369
|
+
}
|
|
370
|
+
await writer.commit('0/1');
|
|
367
371
|
const stream = sync.streamResponse({
|
|
368
372
|
syncContext,
|
|
369
373
|
bucketStorage,
|
|
@@ -392,19 +396,17 @@ bucket_definitions:
|
|
|
392
396
|
if (typeof next === 'object' && next !== null) {
|
|
393
397
|
if ('partial_checkpoint_complete' in next) {
|
|
394
398
|
if (sentCheckpoints == 1) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
afterReplicaId: 'highprio2'
|
|
405
|
-
});
|
|
406
|
-
await batch.commit('0/2');
|
|
399
|
+
// Add a high-priority row that doesn't affect this sync stream.
|
|
400
|
+
await writer.save({
|
|
401
|
+
sourceTable: testTable,
|
|
402
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
403
|
+
after: {
|
|
404
|
+
id: 'highprio2',
|
|
405
|
+
description: 'user_two'
|
|
406
|
+
},
|
|
407
|
+
afterReplicaId: 'highprio2'
|
|
407
408
|
});
|
|
409
|
+
await writer.commit('0/2');
|
|
408
410
|
}
|
|
409
411
|
else {
|
|
410
412
|
expect(sentCheckpoints).toBe(2);
|
|
@@ -424,19 +426,17 @@ bucket_definitions:
|
|
|
424
426
|
}
|
|
425
427
|
if (completedCheckpoints == 1) {
|
|
426
428
|
expect(sentRows).toBe(10001);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
afterReplicaId: 'highprio3'
|
|
437
|
-
});
|
|
438
|
-
await batch.commit('0/3');
|
|
429
|
+
// Add a high-priority row that affects this sync stream.
|
|
430
|
+
await writer.save({
|
|
431
|
+
sourceTable: testTable,
|
|
432
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
433
|
+
after: {
|
|
434
|
+
id: 'highprio3',
|
|
435
|
+
description: 'user_one'
|
|
436
|
+
},
|
|
437
|
+
afterReplicaId: 'highprio3'
|
|
439
438
|
});
|
|
439
|
+
await writer.commit('0/3');
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
}
|
|
@@ -479,30 +479,31 @@ bucket_definitions:
|
|
|
479
479
|
`
|
|
480
480
|
});
|
|
481
481
|
const bucketStorage = f.getInstance(syncRules);
|
|
482
|
-
await bucketStorage.
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
482
|
+
const writer = __addDisposableResource(env_5, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
483
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
484
|
+
await writer.markAllSnapshotDone('0/1');
|
|
485
|
+
// Initial data: Add one priority row and 10k low-priority rows.
|
|
486
|
+
await writer.save({
|
|
487
|
+
sourceTable: testTable,
|
|
488
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
489
|
+
after: {
|
|
490
|
+
id: 'highprio',
|
|
491
|
+
description: 'High priority row'
|
|
492
|
+
},
|
|
493
|
+
afterReplicaId: 'highprio'
|
|
494
|
+
});
|
|
495
|
+
for (let i = 0; i < 2_000; i++) {
|
|
496
|
+
await writer.save({
|
|
497
|
+
sourceTable: testTable,
|
|
486
498
|
tag: storage.SaveOperationTag.INSERT,
|
|
487
499
|
after: {
|
|
488
|
-
id:
|
|
489
|
-
description: '
|
|
500
|
+
id: `${i}`,
|
|
501
|
+
description: 'low prio'
|
|
490
502
|
},
|
|
491
|
-
afterReplicaId:
|
|
503
|
+
afterReplicaId: `${i}`
|
|
492
504
|
});
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
sourceTable: TEST_TABLE,
|
|
496
|
-
tag: storage.SaveOperationTag.INSERT,
|
|
497
|
-
after: {
|
|
498
|
-
id: `${i}`,
|
|
499
|
-
description: 'low prio'
|
|
500
|
-
},
|
|
501
|
-
afterReplicaId: `${i}`
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
await batch.commit('0/1');
|
|
505
|
-
});
|
|
505
|
+
}
|
|
506
|
+
await writer.commit('0/1');
|
|
506
507
|
const stream = sync.streamResponse({
|
|
507
508
|
syncContext,
|
|
508
509
|
bucketStorage,
|
|
@@ -534,29 +535,27 @@ bucket_definitions:
|
|
|
534
535
|
sentRows += next.data.data.length;
|
|
535
536
|
if (sentRows == 1001) {
|
|
536
537
|
// Save new data to interrupt the low-priority sync.
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
afterReplicaId: '2001'
|
|
557
|
-
});
|
|
558
|
-
await batch.commit('0/2');
|
|
538
|
+
// Add another high-priority row. This should interrupt the long-running low-priority sync.
|
|
539
|
+
await writer.save({
|
|
540
|
+
sourceTable: testTable,
|
|
541
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
542
|
+
after: {
|
|
543
|
+
id: 'highprio2',
|
|
544
|
+
description: 'Another high-priority row'
|
|
545
|
+
},
|
|
546
|
+
afterReplicaId: 'highprio2'
|
|
547
|
+
});
|
|
548
|
+
// Also add a low-priority row
|
|
549
|
+
await writer.save({
|
|
550
|
+
sourceTable: testTable,
|
|
551
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
552
|
+
after: {
|
|
553
|
+
id: '2001',
|
|
554
|
+
description: 'Another low-priority row'
|
|
555
|
+
},
|
|
556
|
+
afterReplicaId: '2001'
|
|
559
557
|
});
|
|
558
|
+
await writer.commit('0/2');
|
|
560
559
|
}
|
|
561
560
|
if (sentRows >= 1000 && sentRows <= 2001) {
|
|
562
561
|
// pause for a bit to give the stream time to process interruptions.
|
|
@@ -607,18 +606,19 @@ bucket_definitions:
|
|
|
607
606
|
content: BASIC_SYNC_RULES
|
|
608
607
|
});
|
|
609
608
|
const bucketStorage = f.getInstance(syncRules);
|
|
610
|
-
await bucketStorage.
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
620
|
-
|
|
609
|
+
const writer = __addDisposableResource(env_6, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
610
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
611
|
+
await writer.markAllSnapshotDone('0/1');
|
|
612
|
+
await writer.save({
|
|
613
|
+
sourceTable: testTable,
|
|
614
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
615
|
+
after: {
|
|
616
|
+
id: 't1',
|
|
617
|
+
description: 'sync'
|
|
618
|
+
},
|
|
619
|
+
afterReplicaId: 't1'
|
|
621
620
|
});
|
|
621
|
+
await writer.commit('0/1');
|
|
622
622
|
const stream = sync.streamResponse({
|
|
623
623
|
syncContext,
|
|
624
624
|
bucketStorage,
|
|
@@ -645,9 +645,7 @@ bucket_definitions:
|
|
|
645
645
|
if (receivedCompletions == 1) {
|
|
646
646
|
// Trigger an empty bucket update.
|
|
647
647
|
await bucketStorage.createManagedWriteCheckpoint({ user_id: '', heads: { '1': '1/0' } });
|
|
648
|
-
await
|
|
649
|
-
await batch.commit('1/0');
|
|
650
|
-
});
|
|
648
|
+
await writer.commit('1/0');
|
|
651
649
|
}
|
|
652
650
|
else {
|
|
653
651
|
break;
|
|
@@ -668,14 +666,18 @@ bucket_definitions:
|
|
|
668
666
|
}
|
|
669
667
|
});
|
|
670
668
|
test('sync legacy non-raw data', async () => {
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
await
|
|
678
|
-
|
|
669
|
+
const env_7 = { stack: [], error: void 0, hasError: false };
|
|
670
|
+
try {
|
|
671
|
+
const f = __addDisposableResource(env_7, await factory(), true);
|
|
672
|
+
const syncRules = await updateSyncRules(f, {
|
|
673
|
+
content: BASIC_SYNC_RULES
|
|
674
|
+
});
|
|
675
|
+
const bucketStorage = await f.getInstance(syncRules);
|
|
676
|
+
const writer = __addDisposableResource(env_7, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
677
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
678
|
+
await writer.markAllSnapshotDone('0/1');
|
|
679
|
+
await writer.save({
|
|
680
|
+
sourceTable: testTable,
|
|
679
681
|
tag: storage.SaveOperationTag.INSERT,
|
|
680
682
|
after: {
|
|
681
683
|
id: 't1',
|
|
@@ -684,30 +686,39 @@ bucket_definitions:
|
|
|
684
686
|
},
|
|
685
687
|
afterReplicaId: 't1'
|
|
686
688
|
});
|
|
687
|
-
await
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
689
|
+
await writer.commit('0/1');
|
|
690
|
+
const stream = sync.streamResponse({
|
|
691
|
+
syncContext,
|
|
692
|
+
bucketStorage,
|
|
693
|
+
syncRules: bucketStorage.getParsedSyncRules(test_utils.PARSE_OPTIONS),
|
|
694
|
+
params: {
|
|
695
|
+
buckets: [],
|
|
696
|
+
include_checksum: true,
|
|
697
|
+
raw_data: false
|
|
698
|
+
},
|
|
699
|
+
tracker,
|
|
700
|
+
token: new JwtPayload({ sub: '', exp: Date.now() / 1000 + 10 }),
|
|
701
|
+
isEncodingAsBson: false
|
|
702
|
+
});
|
|
703
|
+
const lines = await consumeCheckpointLines(stream);
|
|
704
|
+
expect(lines).toMatchSnapshot();
|
|
705
|
+
// Specifically check the number - this is the important part of the test
|
|
706
|
+
expect(lines[1].data.data[0].data.large_num).toEqual(12345678901234567890n);
|
|
707
|
+
}
|
|
708
|
+
catch (e_7) {
|
|
709
|
+
env_7.error = e_7;
|
|
710
|
+
env_7.hasError = true;
|
|
711
|
+
}
|
|
712
|
+
finally {
|
|
713
|
+
const result_7 = __disposeResources(env_7);
|
|
714
|
+
if (result_7)
|
|
715
|
+
await result_7;
|
|
716
|
+
}
|
|
706
717
|
});
|
|
707
718
|
test('expired token', async () => {
|
|
708
|
-
const
|
|
719
|
+
const env_8 = { stack: [], error: void 0, hasError: false };
|
|
709
720
|
try {
|
|
710
|
-
const f = __addDisposableResource(
|
|
721
|
+
const f = __addDisposableResource(env_8, await factory(), true);
|
|
711
722
|
const syncRules = await updateSyncRules(f, {
|
|
712
723
|
content: BASIC_SYNC_RULES
|
|
713
724
|
});
|
|
@@ -728,28 +739,29 @@ bucket_definitions:
|
|
|
728
739
|
const lines = await consumeCheckpointLines(stream);
|
|
729
740
|
expect(lines).toMatchSnapshot();
|
|
730
741
|
}
|
|
731
|
-
catch (
|
|
732
|
-
|
|
733
|
-
|
|
742
|
+
catch (e_8) {
|
|
743
|
+
env_8.error = e_8;
|
|
744
|
+
env_8.hasError = true;
|
|
734
745
|
}
|
|
735
746
|
finally {
|
|
736
|
-
const
|
|
737
|
-
if (
|
|
738
|
-
await
|
|
747
|
+
const result_8 = __disposeResources(env_8);
|
|
748
|
+
if (result_8)
|
|
749
|
+
await result_8;
|
|
739
750
|
}
|
|
740
751
|
});
|
|
741
752
|
test('sync updates to global data', async (context) => {
|
|
742
|
-
const
|
|
753
|
+
const env_9 = { stack: [], error: void 0, hasError: false };
|
|
743
754
|
try {
|
|
744
|
-
const f = __addDisposableResource(
|
|
755
|
+
const f = __addDisposableResource(env_9, await factory(), true);
|
|
745
756
|
const syncRules = await updateSyncRules(f, {
|
|
746
757
|
content: BASIC_SYNC_RULES
|
|
747
758
|
});
|
|
748
759
|
const bucketStorage = await f.getInstance(syncRules);
|
|
760
|
+
const writer = __addDisposableResource(env_9, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
761
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
749
762
|
// Activate
|
|
750
|
-
await
|
|
751
|
-
|
|
752
|
-
});
|
|
763
|
+
await writer.markAllSnapshotDone('0/0');
|
|
764
|
+
await writer.keepalive('0/0');
|
|
753
765
|
const stream = sync.streamResponse({
|
|
754
766
|
syncContext,
|
|
755
767
|
bucketStorage,
|
|
@@ -768,47 +780,43 @@ bucket_definitions:
|
|
|
768
780
|
iter.return?.();
|
|
769
781
|
});
|
|
770
782
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
771
|
-
await
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
afterReplicaId: 't1'
|
|
780
|
-
});
|
|
781
|
-
await batch.commit('0/1');
|
|
783
|
+
await writer.save({
|
|
784
|
+
sourceTable: testTable,
|
|
785
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
786
|
+
after: {
|
|
787
|
+
id: 't1',
|
|
788
|
+
description: 'Test 1'
|
|
789
|
+
},
|
|
790
|
+
afterReplicaId: 't1'
|
|
782
791
|
});
|
|
792
|
+
await writer.commit('0/1');
|
|
783
793
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
784
|
-
await
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
afterReplicaId: 't2'
|
|
793
|
-
});
|
|
794
|
-
await batch.commit('0/2');
|
|
794
|
+
await writer.save({
|
|
795
|
+
sourceTable: testTable,
|
|
796
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
797
|
+
after: {
|
|
798
|
+
id: 't2',
|
|
799
|
+
description: 'Test 2'
|
|
800
|
+
},
|
|
801
|
+
afterReplicaId: 't2'
|
|
795
802
|
});
|
|
803
|
+
await writer.commit('0/2');
|
|
796
804
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
797
805
|
}
|
|
798
|
-
catch (
|
|
799
|
-
|
|
800
|
-
|
|
806
|
+
catch (e_9) {
|
|
807
|
+
env_9.error = e_9;
|
|
808
|
+
env_9.hasError = true;
|
|
801
809
|
}
|
|
802
810
|
finally {
|
|
803
|
-
const
|
|
804
|
-
if (
|
|
805
|
-
await
|
|
811
|
+
const result_9 = __disposeResources(env_9);
|
|
812
|
+
if (result_9)
|
|
813
|
+
await result_9;
|
|
806
814
|
}
|
|
807
815
|
});
|
|
808
816
|
test('sync updates to parameter query only', async (context) => {
|
|
809
|
-
const
|
|
817
|
+
const env_10 = { stack: [], error: void 0, hasError: false };
|
|
810
818
|
try {
|
|
811
|
-
const f = __addDisposableResource(
|
|
819
|
+
const f = __addDisposableResource(env_10, await factory(), true);
|
|
812
820
|
const syncRules = await updateSyncRules(f, {
|
|
813
821
|
content: `bucket_definitions:
|
|
814
822
|
by_user:
|
|
@@ -817,13 +825,12 @@ bucket_definitions:
|
|
|
817
825
|
- select * from lists where user_id = bucket.user_id
|
|
818
826
|
`
|
|
819
827
|
});
|
|
820
|
-
const usersTable = test_utils.makeTestTable('users', ['id']);
|
|
821
|
-
const listsTable = test_utils.makeTestTable('lists', ['id']);
|
|
822
828
|
const bucketStorage = await f.getInstance(syncRules);
|
|
829
|
+
const writer = __addDisposableResource(env_10, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
830
|
+
const usersTable = await test_utils.resolveTestTable(writer, 'users', ['id'], config, 1);
|
|
823
831
|
// Activate
|
|
824
|
-
await
|
|
825
|
-
|
|
826
|
-
});
|
|
832
|
+
await writer.markAllSnapshotDone('0/0');
|
|
833
|
+
await writer.keepalive('0/0');
|
|
827
834
|
const stream = sync.streamResponse({
|
|
828
835
|
syncContext,
|
|
829
836
|
bucketStorage,
|
|
@@ -846,36 +853,35 @@ bucket_definitions:
|
|
|
846
853
|
expect(checkpoint1[0].checkpoint?.buckets?.map((b) => b.bucket)).toEqual([]);
|
|
847
854
|
expect(checkpoint1).toMatchSnapshot();
|
|
848
855
|
// Add user
|
|
849
|
-
await
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
afterReplicaId: 'user1'
|
|
858
|
-
});
|
|
859
|
-
await batch.commit('0/1');
|
|
856
|
+
await writer.save({
|
|
857
|
+
sourceTable: usersTable,
|
|
858
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
859
|
+
after: {
|
|
860
|
+
id: 'user1',
|
|
861
|
+
name: 'User 1'
|
|
862
|
+
},
|
|
863
|
+
afterReplicaId: 'user1'
|
|
860
864
|
});
|
|
865
|
+
await writer.commit('0/1');
|
|
861
866
|
const checkpoint2 = await getCheckpointLines(iter);
|
|
862
|
-
|
|
867
|
+
const { bucket } = test_utils.bucketRequest(syncRules, 'by_user["user1"]');
|
|
868
|
+
expect(checkpoint2[0].checkpoint_diff?.updated_buckets?.map((b) => b.bucket)).toEqual([bucket]);
|
|
863
869
|
expect(checkpoint2).toMatchSnapshot();
|
|
864
870
|
}
|
|
865
|
-
catch (
|
|
866
|
-
|
|
867
|
-
|
|
871
|
+
catch (e_10) {
|
|
872
|
+
env_10.error = e_10;
|
|
873
|
+
env_10.hasError = true;
|
|
868
874
|
}
|
|
869
875
|
finally {
|
|
870
|
-
const
|
|
871
|
-
if (
|
|
872
|
-
await
|
|
876
|
+
const result_10 = __disposeResources(env_10);
|
|
877
|
+
if (result_10)
|
|
878
|
+
await result_10;
|
|
873
879
|
}
|
|
874
880
|
});
|
|
875
881
|
test('sync updates to data query only', async (context) => {
|
|
876
|
-
const
|
|
882
|
+
const env_11 = { stack: [], error: void 0, hasError: false };
|
|
877
883
|
try {
|
|
878
|
-
const f = __addDisposableResource(
|
|
884
|
+
const f = __addDisposableResource(env_11, await factory(), true);
|
|
879
885
|
const syncRules = await updateSyncRules(f, {
|
|
880
886
|
content: `bucket_definitions:
|
|
881
887
|
by_user:
|
|
@@ -884,21 +890,21 @@ bucket_definitions:
|
|
|
884
890
|
- select * from lists where user_id = bucket.user_id
|
|
885
891
|
`
|
|
886
892
|
});
|
|
887
|
-
const usersTable = test_utils.makeTestTable('users', ['id']);
|
|
888
|
-
const listsTable = test_utils.makeTestTable('lists', ['id']);
|
|
889
893
|
const bucketStorage = await f.getInstance(syncRules);
|
|
890
|
-
await bucketStorage.
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
894
|
+
const writer = __addDisposableResource(env_11, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
895
|
+
const usersTable = await test_utils.resolveTestTable(writer, 'users', ['id'], config, 1);
|
|
896
|
+
const listsTable = await test_utils.resolveTestTable(writer, 'lists', ['id'], config, 2);
|
|
897
|
+
await writer.markAllSnapshotDone('0/1');
|
|
898
|
+
await writer.save({
|
|
899
|
+
sourceTable: usersTable,
|
|
900
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
901
|
+
after: {
|
|
902
|
+
id: 'user1',
|
|
903
|
+
name: 'User 1'
|
|
904
|
+
},
|
|
905
|
+
afterReplicaId: 'user1'
|
|
901
906
|
});
|
|
907
|
+
await writer.commit('0/1');
|
|
902
908
|
const stream = sync.streamResponse({
|
|
903
909
|
syncContext,
|
|
904
910
|
bucketStorage,
|
|
@@ -916,42 +922,39 @@ bucket_definitions:
|
|
|
916
922
|
context.onTestFinished(() => {
|
|
917
923
|
iter.return?.();
|
|
918
924
|
});
|
|
925
|
+
const { bucket } = bucketRequest(syncRules, 'by_user["user1"]');
|
|
919
926
|
const checkpoint1 = await getCheckpointLines(iter);
|
|
920
|
-
expect(checkpoint1[0].checkpoint?.buckets?.map((b) => b.bucket)).toEqual([
|
|
921
|
-
bucketRequest(syncRules, 'by_user["user1"]')
|
|
922
|
-
]);
|
|
927
|
+
expect(checkpoint1[0].checkpoint?.buckets?.map((b) => b.bucket)).toEqual([bucket]);
|
|
923
928
|
expect(checkpoint1).toMatchSnapshot();
|
|
924
|
-
await
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
afterReplicaId: 'list1'
|
|
934
|
-
});
|
|
935
|
-
await batch.commit('0/1');
|
|
929
|
+
await writer.save({
|
|
930
|
+
sourceTable: listsTable,
|
|
931
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
932
|
+
after: {
|
|
933
|
+
id: 'list1',
|
|
934
|
+
user_id: 'user1',
|
|
935
|
+
name: 'User 1'
|
|
936
|
+
},
|
|
937
|
+
afterReplicaId: 'list1'
|
|
936
938
|
});
|
|
939
|
+
await writer.commit('0/1');
|
|
937
940
|
const checkpoint2 = await getCheckpointLines(iter);
|
|
938
|
-
expect(checkpoint2[0].checkpoint_diff?.updated_buckets?.map((b) => b.bucket)).toEqual([
|
|
941
|
+
expect(checkpoint2[0].checkpoint_diff?.updated_buckets?.map((b) => b.bucket)).toEqual([bucket]);
|
|
939
942
|
expect(checkpoint2).toMatchSnapshot();
|
|
940
943
|
}
|
|
941
|
-
catch (
|
|
942
|
-
|
|
943
|
-
|
|
944
|
+
catch (e_11) {
|
|
945
|
+
env_11.error = e_11;
|
|
946
|
+
env_11.hasError = true;
|
|
944
947
|
}
|
|
945
948
|
finally {
|
|
946
|
-
const
|
|
947
|
-
if (
|
|
948
|
-
await
|
|
949
|
+
const result_11 = __disposeResources(env_11);
|
|
950
|
+
if (result_11)
|
|
951
|
+
await result_11;
|
|
949
952
|
}
|
|
950
953
|
});
|
|
951
954
|
test('sync updates to parameter query + data', async (context) => {
|
|
952
|
-
const
|
|
955
|
+
const env_12 = { stack: [], error: void 0, hasError: false };
|
|
953
956
|
try {
|
|
954
|
-
const f = __addDisposableResource(
|
|
957
|
+
const f = __addDisposableResource(env_12, await factory(), true);
|
|
955
958
|
const syncRules = await updateSyncRules(f, {
|
|
956
959
|
content: `bucket_definitions:
|
|
957
960
|
by_user:
|
|
@@ -960,13 +963,13 @@ bucket_definitions:
|
|
|
960
963
|
- select * from lists where user_id = bucket.user_id
|
|
961
964
|
`
|
|
962
965
|
});
|
|
963
|
-
const usersTable = test_utils.makeTestTable('users', ['id']);
|
|
964
|
-
const listsTable = test_utils.makeTestTable('lists', ['id']);
|
|
965
966
|
const bucketStorage = await f.getInstance(syncRules);
|
|
967
|
+
const writer = __addDisposableResource(env_12, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
968
|
+
const usersTable = await test_utils.resolveTestTable(writer, 'users', ['id'], config, 1);
|
|
969
|
+
const listsTable = await test_utils.resolveTestTable(writer, 'lists', ['id'], config, 2);
|
|
966
970
|
// Activate
|
|
967
|
-
await
|
|
968
|
-
|
|
969
|
-
});
|
|
971
|
+
await writer.markAllSnapshotDone('0/0');
|
|
972
|
+
await writer.keepalive('0/0');
|
|
970
973
|
const stream = sync.streamResponse({
|
|
971
974
|
syncContext,
|
|
972
975
|
bucketStorage,
|
|
@@ -986,54 +989,54 @@ bucket_definitions:
|
|
|
986
989
|
});
|
|
987
990
|
// Initial empty checkpoint
|
|
988
991
|
expect(await getCheckpointLines(iter)).toMatchSnapshot();
|
|
989
|
-
await
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
});
|
|
1009
|
-
await batch.commit('0/1');
|
|
992
|
+
await writer.markAllSnapshotDone('0/1');
|
|
993
|
+
await writer.save({
|
|
994
|
+
sourceTable: listsTable,
|
|
995
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
996
|
+
after: {
|
|
997
|
+
id: 'list1',
|
|
998
|
+
user_id: 'user1',
|
|
999
|
+
name: 'User 1'
|
|
1000
|
+
},
|
|
1001
|
+
afterReplicaId: 'list1'
|
|
1002
|
+
});
|
|
1003
|
+
await writer.save({
|
|
1004
|
+
sourceTable: usersTable,
|
|
1005
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
1006
|
+
after: {
|
|
1007
|
+
id: 'user1',
|
|
1008
|
+
name: 'User 1'
|
|
1009
|
+
},
|
|
1010
|
+
afterReplicaId: 'user1'
|
|
1010
1011
|
});
|
|
1012
|
+
await writer.commit('0/1');
|
|
1013
|
+
const { bucket } = test_utils.bucketRequest(syncRules, 'by_user["user1"]');
|
|
1011
1014
|
const checkpoint2 = await getCheckpointLines(iter);
|
|
1012
|
-
expect(checkpoint2[0].checkpoint_diff?.updated_buckets?.map((b) => b.bucket)).toEqual([
|
|
1015
|
+
expect(checkpoint2[0].checkpoint_diff?.updated_buckets?.map((b) => b.bucket)).toEqual([bucket]);
|
|
1013
1016
|
expect(checkpoint2).toMatchSnapshot();
|
|
1014
1017
|
}
|
|
1015
|
-
catch (
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
+
catch (e_12) {
|
|
1019
|
+
env_12.error = e_12;
|
|
1020
|
+
env_12.hasError = true;
|
|
1018
1021
|
}
|
|
1019
1022
|
finally {
|
|
1020
|
-
const
|
|
1021
|
-
if (
|
|
1022
|
-
await
|
|
1023
|
+
const result_12 = __disposeResources(env_12);
|
|
1024
|
+
if (result_12)
|
|
1025
|
+
await result_12;
|
|
1023
1026
|
}
|
|
1024
1027
|
});
|
|
1025
1028
|
test('expiring token', async (context) => {
|
|
1026
|
-
const
|
|
1029
|
+
const env_13 = { stack: [], error: void 0, hasError: false };
|
|
1027
1030
|
try {
|
|
1028
|
-
const f = __addDisposableResource(
|
|
1031
|
+
const f = __addDisposableResource(env_13, await factory(), true);
|
|
1029
1032
|
const syncRules = await updateSyncRules(f, {
|
|
1030
1033
|
content: BASIC_SYNC_RULES
|
|
1031
1034
|
});
|
|
1032
1035
|
const bucketStorage = await f.getInstance(syncRules);
|
|
1036
|
+
const writer = __addDisposableResource(env_13, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
1033
1037
|
// Activate
|
|
1034
|
-
await
|
|
1035
|
-
|
|
1036
|
-
});
|
|
1038
|
+
await writer.markAllSnapshotDone('0/0');
|
|
1039
|
+
await writer.keepalive('0/0');
|
|
1037
1040
|
const exp = Date.now() / 1000 + 0.1;
|
|
1038
1041
|
const stream = sync.streamResponse({
|
|
1039
1042
|
syncContext,
|
|
@@ -1057,49 +1060,50 @@ bucket_definitions:
|
|
|
1057
1060
|
const expLines = await getCheckpointLines(iter);
|
|
1058
1061
|
expect(expLines).toMatchSnapshot();
|
|
1059
1062
|
}
|
|
1060
|
-
catch (
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
+
catch (e_13) {
|
|
1064
|
+
env_13.error = e_13;
|
|
1065
|
+
env_13.hasError = true;
|
|
1063
1066
|
}
|
|
1064
1067
|
finally {
|
|
1065
|
-
const
|
|
1066
|
-
if (
|
|
1067
|
-
await
|
|
1068
|
+
const result_13 = __disposeResources(env_13);
|
|
1069
|
+
if (result_13)
|
|
1070
|
+
await result_13;
|
|
1068
1071
|
}
|
|
1069
1072
|
});
|
|
1070
1073
|
test('compacting data - invalidate checkpoint', async (context) => {
|
|
1071
|
-
const
|
|
1074
|
+
const env_14 = { stack: [], error: void 0, hasError: false };
|
|
1072
1075
|
try {
|
|
1073
1076
|
// This tests a case of a compact operation invalidating a checkpoint in the
|
|
1074
1077
|
// middle of syncing data.
|
|
1075
1078
|
// This is expected to be rare in practice, but it is important to handle
|
|
1076
1079
|
// this case correctly to maintain consistency on the client.
|
|
1077
|
-
const f = __addDisposableResource(
|
|
1080
|
+
const f = __addDisposableResource(env_14, await factory(), true);
|
|
1078
1081
|
const syncRules = await updateSyncRules(f, {
|
|
1079
1082
|
content: BASIC_SYNC_RULES
|
|
1080
1083
|
});
|
|
1081
1084
|
const bucketStorage = await f.getInstance(syncRules);
|
|
1082
|
-
await bucketStorage.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
sourceTable: TEST_TABLE,
|
|
1094
|
-
tag: storage.SaveOperationTag.INSERT,
|
|
1095
|
-
after: {
|
|
1096
|
-
id: 't2',
|
|
1097
|
-
description: 'Test 2'
|
|
1098
|
-
},
|
|
1099
|
-
afterReplicaId: 't2'
|
|
1100
|
-
});
|
|
1101
|
-
await batch.commit('0/1');
|
|
1085
|
+
const writer = __addDisposableResource(env_14, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
1086
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config);
|
|
1087
|
+
await writer.markAllSnapshotDone('0/1');
|
|
1088
|
+
await writer.save({
|
|
1089
|
+
sourceTable: testTable,
|
|
1090
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
1091
|
+
after: {
|
|
1092
|
+
id: 't1',
|
|
1093
|
+
description: 'Test 1'
|
|
1094
|
+
},
|
|
1095
|
+
afterReplicaId: 't1'
|
|
1102
1096
|
});
|
|
1097
|
+
await writer.save({
|
|
1098
|
+
sourceTable: testTable,
|
|
1099
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
1100
|
+
after: {
|
|
1101
|
+
id: 't2',
|
|
1102
|
+
description: 'Test 2'
|
|
1103
|
+
},
|
|
1104
|
+
afterReplicaId: 't2'
|
|
1105
|
+
});
|
|
1106
|
+
await writer.commit('0/1');
|
|
1103
1107
|
const stream = sync.streamResponse({
|
|
1104
1108
|
syncContext,
|
|
1105
1109
|
bucketStorage,
|
|
@@ -1127,27 +1131,26 @@ bucket_definitions:
|
|
|
1127
1131
|
});
|
|
1128
1132
|
// Now we save additional data AND compact before continuing.
|
|
1129
1133
|
// This invalidates the checkpoint we've received above.
|
|
1130
|
-
await
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
});
|
|
1140
|
-
await batch.save({
|
|
1141
|
-
sourceTable: TEST_TABLE,
|
|
1142
|
-
tag: storage.SaveOperationTag.UPDATE,
|
|
1143
|
-
after: {
|
|
1144
|
-
id: 't2',
|
|
1145
|
-
description: 'Test 2b'
|
|
1146
|
-
},
|
|
1147
|
-
afterReplicaId: 't2'
|
|
1148
|
-
});
|
|
1149
|
-
await batch.commit('0/2');
|
|
1134
|
+
await writer.markAllSnapshotDone('0/1');
|
|
1135
|
+
await writer.save({
|
|
1136
|
+
sourceTable: testTable,
|
|
1137
|
+
tag: storage.SaveOperationTag.UPDATE,
|
|
1138
|
+
after: {
|
|
1139
|
+
id: 't1',
|
|
1140
|
+
description: 'Test 1b'
|
|
1141
|
+
},
|
|
1142
|
+
afterReplicaId: 't1'
|
|
1150
1143
|
});
|
|
1144
|
+
await writer.save({
|
|
1145
|
+
sourceTable: testTable,
|
|
1146
|
+
tag: storage.SaveOperationTag.UPDATE,
|
|
1147
|
+
after: {
|
|
1148
|
+
id: 't2',
|
|
1149
|
+
description: 'Test 2b'
|
|
1150
|
+
},
|
|
1151
|
+
afterReplicaId: 't2'
|
|
1152
|
+
});
|
|
1153
|
+
await writer.commit('0/2');
|
|
1151
1154
|
await bucketStorage.compact({
|
|
1152
1155
|
minBucketChanges: 1,
|
|
1153
1156
|
minChangeRatio: 0
|
|
@@ -1195,28 +1198,28 @@ bucket_definitions:
|
|
|
1195
1198
|
})
|
|
1196
1199
|
});
|
|
1197
1200
|
}
|
|
1198
|
-
catch (
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
+
catch (e_14) {
|
|
1202
|
+
env_14.error = e_14;
|
|
1203
|
+
env_14.hasError = true;
|
|
1201
1204
|
}
|
|
1202
1205
|
finally {
|
|
1203
|
-
const
|
|
1204
|
-
if (
|
|
1205
|
-
await
|
|
1206
|
+
const result_14 = __disposeResources(env_14);
|
|
1207
|
+
if (result_14)
|
|
1208
|
+
await result_14;
|
|
1206
1209
|
}
|
|
1207
1210
|
});
|
|
1208
1211
|
test('write checkpoint', async () => {
|
|
1209
|
-
const
|
|
1212
|
+
const env_15 = { stack: [], error: void 0, hasError: false };
|
|
1210
1213
|
try {
|
|
1211
|
-
const f = __addDisposableResource(
|
|
1214
|
+
const f = __addDisposableResource(env_15, await factory(), true);
|
|
1212
1215
|
const syncRules = await updateSyncRules(f, {
|
|
1213
1216
|
content: BASIC_SYNC_RULES
|
|
1214
1217
|
});
|
|
1215
1218
|
const bucketStorage = f.getInstance(syncRules);
|
|
1216
|
-
await bucketStorage.
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1219
|
+
const writer = __addDisposableResource(env_15, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
1220
|
+
await writer.markAllSnapshotDone('0/1');
|
|
1221
|
+
// <= the managed write checkpoint LSN below
|
|
1222
|
+
await writer.commit('0/1');
|
|
1220
1223
|
const checkpoint = await bucketStorage.createManagedWriteCheckpoint({
|
|
1221
1224
|
user_id: 'test',
|
|
1222
1225
|
heads: { '1': '1/0' }
|
|
@@ -1244,10 +1247,9 @@ bucket_definitions:
|
|
|
1244
1247
|
write_checkpoint: undefined
|
|
1245
1248
|
})
|
|
1246
1249
|
});
|
|
1247
|
-
await
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
});
|
|
1250
|
+
await writer.markAllSnapshotDone('0/1');
|
|
1251
|
+
// must be >= the managed write checkpoint LSN
|
|
1252
|
+
await writer.commit('1/0');
|
|
1251
1253
|
// At this point the LSN has advanced, so the write checkpoint should be
|
|
1252
1254
|
// included in the next checkpoint message.
|
|
1253
1255
|
const stream2 = sync.streamResponse(params);
|
|
@@ -1259,21 +1261,24 @@ bucket_definitions:
|
|
|
1259
1261
|
})
|
|
1260
1262
|
});
|
|
1261
1263
|
}
|
|
1262
|
-
catch (
|
|
1263
|
-
|
|
1264
|
-
|
|
1264
|
+
catch (e_15) {
|
|
1265
|
+
env_15.error = e_15;
|
|
1266
|
+
env_15.hasError = true;
|
|
1265
1267
|
}
|
|
1266
1268
|
finally {
|
|
1267
|
-
const
|
|
1268
|
-
if (
|
|
1269
|
-
await
|
|
1269
|
+
const result_15 = __disposeResources(env_15);
|
|
1270
|
+
if (result_15)
|
|
1271
|
+
await result_15;
|
|
1270
1272
|
}
|
|
1271
1273
|
});
|
|
1272
|
-
test('encodes sync rules id in
|
|
1273
|
-
const
|
|
1274
|
+
test('encodes sync rules id in buckets for streams', async () => {
|
|
1275
|
+
const env_16 = { stack: [], error: void 0, hasError: false };
|
|
1274
1276
|
try {
|
|
1275
|
-
const f = __addDisposableResource(
|
|
1276
|
-
|
|
1277
|
+
const f = __addDisposableResource(env_16, await factory(), true);
|
|
1278
|
+
// This test relies making an actual update to sync rules to test the different bucket names.
|
|
1279
|
+
// The actual naming scheme may change, as long as the two buckets have different names.
|
|
1280
|
+
const rules = [
|
|
1281
|
+
`
|
|
1277
1282
|
streams:
|
|
1278
1283
|
test:
|
|
1279
1284
|
auto_subscribe: true
|
|
@@ -1281,15 +1286,29 @@ streams:
|
|
|
1281
1286
|
|
|
1282
1287
|
config:
|
|
1283
1288
|
edition: 2
|
|
1284
|
-
|
|
1289
|
+
`,
|
|
1290
|
+
`
|
|
1291
|
+
streams:
|
|
1292
|
+
test2:
|
|
1293
|
+
auto_subscribe: true
|
|
1294
|
+
query: SELECT * FROM test WHERE 1;
|
|
1295
|
+
|
|
1296
|
+
config:
|
|
1297
|
+
edition: 2
|
|
1298
|
+
`
|
|
1299
|
+
];
|
|
1285
1300
|
for (let i = 0; i < 2; i++) {
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1301
|
+
const env_17 = { stack: [], error: void 0, hasError: false };
|
|
1302
|
+
try {
|
|
1303
|
+
const syncRules = await updateSyncRules(f, {
|
|
1304
|
+
content: rules[i]
|
|
1305
|
+
});
|
|
1306
|
+
const bucketStorage = f.getInstance(syncRules);
|
|
1307
|
+
const writer = __addDisposableResource(env_17, await bucketStorage.createWriter(test_utils.BATCH_OPTIONS), true);
|
|
1308
|
+
const testTable = await test_utils.resolveTestTable(writer, 'test', ['id'], config, i + 1);
|
|
1309
|
+
await writer.markAllSnapshotDone('0/1');
|
|
1310
|
+
await writer.save({
|
|
1311
|
+
sourceTable: testTable,
|
|
1293
1312
|
tag: storage.SaveOperationTag.INSERT,
|
|
1294
1313
|
after: {
|
|
1295
1314
|
id: 't1',
|
|
@@ -1297,33 +1316,42 @@ config:
|
|
|
1297
1316
|
},
|
|
1298
1317
|
afterReplicaId: 't1'
|
|
1299
1318
|
});
|
|
1300
|
-
await
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1319
|
+
await writer.commit('0/1');
|
|
1320
|
+
const stream = sync.streamResponse({
|
|
1321
|
+
syncContext,
|
|
1322
|
+
bucketStorage: bucketStorage,
|
|
1323
|
+
syncRules: bucketStorage.getParsedSyncRules(test_utils.PARSE_OPTIONS),
|
|
1324
|
+
params: {
|
|
1325
|
+
buckets: [],
|
|
1326
|
+
include_checksum: true,
|
|
1327
|
+
raw_data: true
|
|
1328
|
+
},
|
|
1329
|
+
tracker,
|
|
1330
|
+
token: new JwtPayload({ sub: '', exp: Date.now() / 1000 + 10 }),
|
|
1331
|
+
isEncodingAsBson: false
|
|
1332
|
+
});
|
|
1333
|
+
const lines = await consumeCheckpointLines(stream);
|
|
1334
|
+
expect(lines).toMatchSnapshot();
|
|
1335
|
+
}
|
|
1336
|
+
catch (e_16) {
|
|
1337
|
+
env_17.error = e_16;
|
|
1338
|
+
env_17.hasError = true;
|
|
1339
|
+
}
|
|
1340
|
+
finally {
|
|
1341
|
+
const result_16 = __disposeResources(env_17);
|
|
1342
|
+
if (result_16)
|
|
1343
|
+
await result_16;
|
|
1344
|
+
}
|
|
1317
1345
|
}
|
|
1318
1346
|
}
|
|
1319
|
-
catch (
|
|
1320
|
-
|
|
1321
|
-
|
|
1347
|
+
catch (e_17) {
|
|
1348
|
+
env_16.error = e_17;
|
|
1349
|
+
env_16.hasError = true;
|
|
1322
1350
|
}
|
|
1323
1351
|
finally {
|
|
1324
|
-
const
|
|
1325
|
-
if (
|
|
1326
|
-
await
|
|
1352
|
+
const result_17 = __disposeResources(env_16);
|
|
1353
|
+
if (result_17)
|
|
1354
|
+
await result_17;
|
|
1327
1355
|
}
|
|
1328
1356
|
});
|
|
1329
1357
|
}
|