atagen

malice

public
Star0
Watch0
9ad1d568a721b95f4c11c07b836f1ee0be6a81ae
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/test/arrivals.test.ts

d2a34d0f4861atagen2026-10-25 07:29 UTC1
import assert from 'node:assert/strict';
d2a34d0f4861atagen2026-10-25 07:29 UTC2
import { test } from 'node:test';
d2a34d0f4861atagen2026-10-25 07:29 UTC3
import { observeArrivals } from '../src/lib/arrivals.ts';
d2a34d0f4861atagen2026-10-25 07:29 UTC4
import type { TimelineEvent, TimelineItem } from '../src/lib/types.ts';
d2a34d0f4861atagen2026-10-25 07:29 UTC5
d2a34d0f4861atagen2026-10-25 07:29 UTC6
const MINUTE = 60 * 1000;
d2a34d0f4861atagen2026-10-25 07:29 UTC7
d2a34d0f4861atagen2026-10-25 07:29 UTC8
function event(id: string, timestamp_ms: number, extra: Partial<TimelineEvent> = {}): TimelineItem {
d2a34d0f4861atagen2026-10-25 07:29 UTC9
  return { kind: 'event', event: { item_id: id, timestamp_ms, own: false, ...extra } as TimelineEvent };
d2a34d0f4861atagen2026-10-25 07:29 UTC10
}
d2a34d0f4861atagen2026-10-25 07:29 UTC11
d2a34d0f4861atagen2026-10-25 07:29 UTC12
function lagOf(items: TimelineItem[] | null, id: string): number | undefined {
d2a34d0f4861atagen2026-10-25 07:29 UTC13
  const found = items?.find((item) => item.kind === 'event' && item.event.item_id === id);
d2a34d0f4861atagen2026-10-25 07:29 UTC14
  return found?.kind === 'event' ? found.event.delivery_lag_ms : undefined;
d2a34d0f4861atagen2026-10-25 07:29 UTC15
}
d2a34d0f4861atagen2026-10-25 07:29 UTC16
d2a34d0f4861atagen2026-10-25 07:29 UTC17
test('flags a delayed event appended after newer known events', () => {
d2a34d0f4861atagen2026-10-25 07:29 UTC18
  const now = 100 * MINUTE;
d2a34d0f4861atagen2026-10-25 07:29 UTC19
  const previous = [event('a', 90 * MINUTE), event('b', 95 * MINUTE)];
d2a34d0f4861atagen2026-10-25 07:29 UTC20
  const next = observeArrivals(previous, [...previous, event('late', 80 * MINUTE)], 0, now);
d2a34d0f4861atagen2026-10-25 07:29 UTC21
  assert.equal(lagOf(next, 'late'), 20 * MINUTE);
d2a34d0f4861atagen2026-10-25 07:29 UTC22
});
d2a34d0f4861atagen2026-10-25 07:29 UTC23
d2a34d0f4861atagen2026-10-25 07:29 UTC24
test('ignores backfill and prompt arrivals', () => {
d2a34d0f4861atagen2026-10-25 07:29 UTC25
  const now = 100 * MINUTE;
d2a34d0f4861atagen2026-10-25 07:29 UTC26
  const previous = [event('a', 99 * MINUTE)];
d2a34d0f4861atagen2026-10-25 07:29 UTC27
  const next = observeArrivals(previous, [event('old', 10 * MINUTE), ...previous, event('new', now - 1000)], 0, now);
d2a34d0f4861atagen2026-10-25 07:29 UTC28
  assert.equal(lagOf(next, 'old'), undefined);
d2a34d0f4861atagen2026-10-25 07:29 UTC29
  assert.equal(lagOf(next, 'new'), undefined);
d2a34d0f4861atagen2026-10-25 07:29 UTC30
});
d2a34d0f4861atagen2026-10-25 07:29 UTC31
d2a34d0f4861atagen2026-10-25 07:29 UTC32
test('measures from when the room became live, not from the send time', () => {
d2a34d0f4861atagen2026-10-25 07:29 UTC33
  const now = 100 * MINUTE;
d2a34d0f4861atagen2026-10-25 07:29 UTC34
  const previous = [event('a', 10 * MINUTE)];
d2a34d0f4861atagen2026-10-25 07:29 UTC35
  const caughtUp = observeArrivals(previous, [...previous, event('offline', 20 * MINUTE)], now - 5000, now);
d2a34d0f4861atagen2026-10-25 07:29 UTC36
  assert.equal(lagOf(caughtUp, 'offline'), undefined);
d2a34d0f4861atagen2026-10-25 07:29 UTC37
  const delayed = observeArrivals(previous, [...previous, event('stuck', 20 * MINUTE)], now - 3 * MINUTE, now);
d2a34d0f4861atagen2026-10-25 07:29 UTC38
  assert.equal(lagOf(delayed, 'stuck'), 3 * MINUTE);
d2a34d0f4861atagen2026-10-25 07:29 UTC39
});
d2a34d0f4861atagen2026-10-25 07:29 UTC40
d2a34d0f4861atagen2026-10-25 07:29 UTC41
test('carries a flag across later updates', () => {
d2a34d0f4861atagen2026-10-25 07:29 UTC42
  const now = 100 * MINUTE;
d2a34d0f4861atagen2026-10-25 07:29 UTC43
  const previous = [event('a', 99 * MINUTE), event('late', 50 * MINUTE, { delivery_lag_ms: 50 * MINUTE })];
d2a34d0f4861atagen2026-10-25 07:29 UTC44
  const next = observeArrivals(previous, [...previous.map((item) => item.kind === 'event' ? event(item.event.item_id, item.event.timestamp_ms) : item), event('c', now)], 0, now + MINUTE);
d2a34d0f4861atagen2026-10-25 07:29 UTC45
  assert.equal(lagOf(next, 'late'), 50 * MINUTE);
d2a34d0f4861atagen2026-10-25 07:29 UTC46
});
d2a34d0f4861atagen2026-10-25 07:29 UTC47
d2a34d0f4861atagen2026-10-25 07:29 UTC48
test('skips own events and replaced lists', () => {
d2a34d0f4861atagen2026-10-25 07:29 UTC49
  const now = 100 * MINUTE;
d2a34d0f4861atagen2026-10-25 07:29 UTC50
  const previous = [event('a', 99 * MINUTE)];
d2a34d0f4861atagen2026-10-25 07:29 UTC51
  const own = observeArrivals(previous, [...previous, event('mine', 10 * MINUTE, { own: true })], 0, now);
d2a34d0f4861atagen2026-10-25 07:29 UTC52
  assert.equal(lagOf(own, 'mine'), undefined);
d2a34d0f4861atagen2026-10-25 07:29 UTC53
  assert.equal(observeArrivals(previous, [event('x', 10 * MINUTE)], 0, now), null);
d2a34d0f4861atagen2026-10-25 07:29 UTC54
});