1
+ import 'dart:async' ;
1
2
import 'dart:io' ;
2
3
import 'dart:math' ;
3
4
import 'dart:typed_data' ;
@@ -32,6 +33,10 @@ void main() {
32
33
env2.closeAndDelete ();
33
34
});
34
35
36
+ waitUntilLoggedIn (SyncClient client) {
37
+ expect (waitUntil (() => client.state () == SyncState .loggedIn), isTrue);
38
+ }
39
+
35
40
// lambda to easily create clients in the test below
36
41
SyncClient createClient (Store s) =>
37
42
Sync .client (s, 'ws://127.0.0.1:$serverPort ' , SyncCredentials .none ());
@@ -40,7 +45,7 @@ void main() {
40
45
SyncClient loggedInClient (Store s) {
41
46
final client = createClient (s);
42
47
client.start ();
43
- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
48
+ waitUntilLoggedIn ( client);
44
49
return client;
45
50
}
46
51
@@ -215,7 +220,7 @@ void main() {
215
220
await server.online ();
216
221
client.start ();
217
222
218
- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
223
+ waitUntilLoggedIn ( client);
219
224
await yieldExecution ();
220
225
expect (events, equals ([SyncConnectionEvent .connected]));
221
226
expect (events2, equals ([SyncConnectionEvent .connected]));
@@ -237,7 +242,7 @@ void main() {
237
242
await server.start (keepDb: true );
238
243
await server.online ();
239
244
240
- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
245
+ waitUntilLoggedIn ( client);
241
246
await yieldExecution ();
242
247
243
248
expect (
@@ -270,7 +275,7 @@ void main() {
270
275
271
276
client.setCredentials (SyncCredentials .none ());
272
277
273
- expect ( waitUntil (() => client. state () == SyncState .loggedIn), isTrue );
278
+ waitUntilLoggedIn ( client);
274
279
await yieldExecution ();
275
280
expect (
276
281
events,
@@ -283,21 +288,51 @@ void main() {
283
288
test ('SyncClient listeners: completion' , () async {
284
289
await server.online ();
285
290
final client = loggedInClient (store);
291
+ addTearDown (() {
292
+ client.close ();
293
+ });
286
294
final box = env.store.box <TestEntitySynced >();
287
295
final box2 = env2.store.box <TestEntitySynced >();
288
296
expect (box.isEmpty (), isTrue);
289
- int id = box.put (TestEntitySynced (value: 100 ));
297
+ // Do multiple changes to verify only a single completion event is sent
298
+ // after all changes are received.
299
+ box.put (TestEntitySynced (value: 1 ));
300
+ box.put (TestEntitySynced (value: 100 ));
290
301
291
302
// Note: wait for the client to finish sending to the server.
292
303
// There's currently no other way to recognize this.
293
304
sleep (const Duration (milliseconds: 100 ));
294
- client.close ();
295
305
296
- final client2 = loggedInClient (env2.store);
297
- await client2.completionEvents.first.timeout (defaultTimeout);
298
- client2.close ();
306
+ final client2 = createClient (env2.store);
307
+ addTearDown (() {
308
+ client2.close ();
309
+ });
310
+ final Completer firstEvent = Completer ();
311
+ var receivedEvents = 0 ;
312
+ final subscription = client2.completionEvents.listen ((event) {
313
+ if (! firstEvent.isCompleted) {
314
+ firstEvent.complete ();
315
+ }
316
+ receivedEvents++ ;
317
+ });
299
318
300
- expect (box2.get (id)! .value, 100 );
319
+ client2.start ();
320
+ waitUntilLoggedIn (client2);
321
+
322
+ // Yield and wait for the first event...
323
+ await firstEvent.future.timeout (defaultTimeout);
324
+ // ...and some more on any additional events (should be none)
325
+ await Future .delayed (Duration (milliseconds: 200 ));
326
+ expect (receivedEvents, 1 );
327
+ // Note: the ID just happens to be the same as the box was unused
328
+ expect (box2.get (2 )! .value, 100 );
329
+
330
+ // Do another change
331
+ box.put (TestEntitySynced (value: 200 ));
332
+ // Yield and wait for event(s) to come in
333
+ await Future .delayed (Duration (milliseconds: 200 ));
334
+ await subscription.cancel ();
335
+ expect (receivedEvents, 2 );
301
336
});
302
337
303
338
test ('SyncClient listeners: changes' , () async {
@@ -415,9 +450,13 @@ class SyncServer {
415
450
await httpClient.get ('127.0.0.1' , _port! , '' );
416
451
break ;
417
452
} on SocketException catch (e) {
418
- // only retry if "connection refused"
419
- if (e.osError! .errorCode != 111 ) rethrow ;
420
- await Future <void >.delayed (const Duration (milliseconds: 1 ));
453
+ // Only retry if "Connection refused" (not using error codes as they
454
+ // differ by platform).
455
+ if (e.osError! .message.contains ('Connection refused' )) {
456
+ await Future <void >.delayed (const Duration (milliseconds: 1 ));
457
+ } else {
458
+ rethrow ;
459
+ }
421
460
}
422
461
}
423
462
httpClient.close (force: true );
0 commit comments