Skip to content

Commit 5aa9919

Browse files
committed
Test persisting/removing data based on write checkpoints.
1 parent 4ea8aca commit 5aa9919

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

packages/powersync_core/test/connected_test.dart

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ void main() {
4444
await testUtils.testFactory(path: path),
4545
schema: defaultSchema,
4646
maxReaders: 3);
47+
addTearDown(() => {db.close()});
4748
await db.initialize();
4849

4950
final connectedCompleter = Completer();
@@ -83,6 +84,9 @@ void main() {
8384
await testUtils.testFactory(path: path),
8485
schema: defaultSchema,
8586
maxReaders: 3);
87+
// Shorter retry delay, to speed up tests
88+
db.retryDelay = Duration(milliseconds: 10);
89+
addTearDown(() => {db.close()});
8690
await db.initialize();
8791

8892
// Create an item which should trigger an upload.
@@ -132,5 +136,111 @@ void main() {
132136

133137
await db.disconnect();
134138
});
139+
140+
test('should persist local changes when there is no write checkpoint',
141+
() async {
142+
final testServer = await createTestServer();
143+
final connector = TestConnector(() async {
144+
return PowerSyncCredentials(
145+
endpoint: testServer.uri.toString(),
146+
token: 'token not used here',
147+
expiresAt: DateTime.now());
148+
}, uploadData: (database) async {
149+
final tx = await database.getNextCrudTransaction();
150+
if (tx != null) {
151+
await tx.complete();
152+
}
153+
});
154+
155+
final db = PowerSyncDatabase.withFactory(
156+
await testUtils.testFactory(path: path),
157+
schema: defaultSchema,
158+
maxReaders: 3);
159+
addTearDown(() => {db.close()});
160+
await db.initialize();
161+
162+
// Create an item which should trigger an upload.
163+
await db.execute(
164+
'INSERT INTO customers (id, name) VALUES (uuid(), ?)', ['steven']);
165+
166+
// Manually simulate upload before connecting.
167+
// This is simpler than doing this via connect() and waiting for it to complete.
168+
await connector.uploadData(db);
169+
170+
// Check that the data is present locally
171+
expect(
172+
await db.getAll('select name from customers'),
173+
equals([
174+
{'name': 'steven'}
175+
]));
176+
177+
// Connect and send a checkpoint back, but no write checkpoint.
178+
testServer
179+
.addEvent('{"checkpoint": {"last_op_id": "10", "buckets": []}}\n');
180+
testServer.addEvent('{"checkpoint_complete": {"last_op_id": "10"}}\n');
181+
182+
// Now connect and wait for sync to complete
183+
await db.connect(connector: connector);
184+
await db.statusStream
185+
.firstWhere((status) => status.connected && status.downloading);
186+
await Future.delayed(Duration(milliseconds: 20));
187+
expect(
188+
await db.getAll('select name from customers'),
189+
equals([
190+
{'name': 'steven'}
191+
]));
192+
});
193+
194+
test('should remove local changes when there a write checkpoint', () async {
195+
// The only difference between this and the one above, is that the synced
196+
// checkpoint here contains a write checkpoint, matching the write-checkpoint2.json
197+
// API. This will trigger the local changes to be removed.
198+
final testServer = await createTestServer();
199+
final connector = TestConnector(() async {
200+
return PowerSyncCredentials(
201+
endpoint: testServer.uri.toString(),
202+
token: 'token not used here',
203+
expiresAt: DateTime.now());
204+
}, uploadData: (database) async {
205+
final tx = await database.getNextCrudTransaction();
206+
if (tx != null) {
207+
await tx.complete();
208+
}
209+
});
210+
211+
final db = PowerSyncDatabase.withFactory(
212+
await testUtils.testFactory(path: path),
213+
schema: defaultSchema,
214+
maxReaders: 3);
215+
addTearDown(() => {db.close()});
216+
await db.initialize();
217+
218+
// Create an item which should trigger an upload.
219+
await db.execute(
220+
'INSERT INTO customers (id, name) VALUES (uuid(), ?)', ['steven']);
221+
222+
// Manually simulate upload before connecting.
223+
// This is simpler than doing this via connect() and waiting for it to complete.
224+
await connector.uploadData(db);
225+
226+
// Check that the data is present locally
227+
expect(
228+
await db.getAll('select name from customers'),
229+
equals([
230+
{'name': 'steven'}
231+
]));
232+
233+
// Connect and send a checkpoint back, but no write checkpoint.
234+
testServer.addEvent(
235+
'{"checkpoint": {"last_op_id": "10", "buckets": [], "write_checkpoint": "10"}}\n');
236+
testServer.addEvent('{"checkpoint_complete": {"last_op_id": "10"}}\n');
237+
238+
// Now connect and wait for sync to complete
239+
await db.connect(connector: connector);
240+
await db.statusStream
241+
.firstWhere((status) => status.connected && status.downloading);
242+
await Future.delayed(Duration(milliseconds: 20));
243+
expect(await db.getAll('select name from customers'), equals([]));
244+
});
135245
});
136246
}

packages/powersync_core/test/server/sync_server/mock_sync_server.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class TestHttpServerHelper {
2828
context: {
2929
"shelf.io.buffer_output": false
3030
});
31+
})
32+
..get('/write-checkpoint2.json', (request) {
33+
return Response.ok('{"data": {"write_checkpoint": "10"}}', headers: {
34+
'Content-Type': 'application/json',
35+
});
3136
});
3237

3338
_server = await io.serve(router.call, 'localhost', 0);

0 commit comments

Comments
 (0)