scenarioSendOffline function

Future<void> scenarioSendOffline(
  1. FakeServer server,
  2. WorldSeed w,
  3. ScenarioClient client
)

04 16.2: a message written offline is sent after the reconnect and its catch-up; the first response is lost after the commit, the retry with the same client_msg_id is a replay (200, Idempotent-Replay: true), and exactly one message exists.

Implementation

Future<void> scenarioSendOffline(
  FakeServer server,
  WorldSeed w,
  ScenarioClient client,
) async {
  await client.start();
  await client.goOffline();
  for (var i = 1; i <= 3; i++) {
    w.post(w.sam, w.releaseNotes, 'While Alex is away $i');
  }
  final id = await client.send(w.releaseNotes, 'Written offline');
  _check(
    server.requestsOf('createMessage').isEmpty,
    'nothing is sent while offline',
  );
  _check((await client.outbox()).length == 1, 'the entry waits in the outbox');
  server.faults
    ..dropResponseAfterCommit('createMessage')
    ..holdDispatches();
  await client.goOnline();
  await waitFor(
    'the retry',
    () => server.requestsOf('createMessage').length >= 2,
  );
  final attempts = server.requestsOf('createMessage');
  final statuses = [for (final r in attempts) r.status];
  _check(attempts.first.status == 0, 'the first response was lost: $statuses');
  _check(
    attempts[1].status == 200,
    'the retry was a replay with 200: $statuses',
  );
  _check(
    attempts.every((r) => (r.body! as JsonMap)['client_msg_id'] == id),
    'every attempt carried the same client_msg_id',
  );
  server.faults.releaseDispatches();
  await waitFor(
    'the echo of $id',
    () async => (await _withId(client, w.releaseNotes, id)).isNotEmpty,
  );
  await waitFor(
    'the empty outbox',
    () async => (await client.outbox()).isEmpty,
  );
  _check(
    (await _withId(client, w.releaseNotes, id)).length == 1,
    'exactly one local message',
  );
  _check(
    server.world
            .messagesOf(w.releaseNotes)
            .where((m) => m['client_msg_id'] == id)
            .length ==
        1,
    'exactly one message on the server',
  );
  final texts = [for (final m in await client.messages(w.releaseNotes)) m.text];
  _check(
    texts.contains('While Alex is away 3'),
    'the catch-up delivered the missed messages',
  );
  _contract(server);
}