scenarioCatchUp function

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

04 16.3: a reconnect catches up from the cursor in pages with cursor frames (the private channel's events are skipped), then catchup.complete; only visible events arrive.

Implementation

Future<void> scenarioCatchUp(
  FakeServer server,
  WorldSeed w,
  ScenarioClient client,
) async {
  server.world
    ..catchupPageSize = 3
    ..cursorAdvanceEvery = 2;
  await client.start();
  await client.goOffline();
  for (var i = 1; i <= 4; i++) {
    w
      ..post(w.sam, w.releaseNotes, 'Visible $i')
      ..post(w.sam, w.budget, 'Hidden $i');
  }
  final before = server.gateway.connections.length;
  await client.goOnline();
  await waitFor(
    'live again',
    () => client.live && server.gateway.connections.length > before,
  );
  await waitFor(
    'the cursor at the head',
    () async => await client.cursor() == server.world.headSeq,
  );
  final number = server.gateway.connections.last.number;
  final sent = server.gateway.sentOn(number);
  final ops = [for (final f in sent) f.op];
  _check(
    ops.where((o) => o == 'cursor').length >= 3,
    'several pages with cursor frames: $ops',
  );
  _check(
    ops.contains('catchup.complete'),
    'catchup.complete ends the catch-up',
  );
  _check(
    sent
        .where((f) => f.op == 'dispatch')
        .every(
          (f) =>
              f.data['scope'] is! Map ||
              (f.data['scope']! as Map)['channel_id'] != w.private,
        ),
    'no event of the hidden channel arrives',
  );
  final texts = [for (final m in await client.messages(w.releaseNotes)) m.text];
  for (var i = 1; i <= 4; i++) {
    _check(texts.contains('Visible $i'), 'message "Visible $i" was caught up');
  }
  _check(
    !await client.holdsChannel(w.private),
    'the hidden channel is not stored',
  );
  _contract(server);
}