chat / client / test / mailbox.test.mjs
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/**
 * The offline mailbox (PROTOCOL.md §9): the bearer-token cache, the HTTP
 * status → typed-result table, the deposit envelope BYTES (0x01 raw block /
 * 0x02 kMbx-sealed identity record), the persistent queue with its dedup and
 * caps, and the replay classifier's CID re-hash.
 *
 * Fixture: test/vectors/mailbox.json. The deposit envelopes are pinned under a
 * deterministic getRandomValues stream (helpers/det-random.mjs), because the
 * kMbx seal uses a random IV by design.
 */
import { test } from "node:test";
import assert from "node:assert/strict";
import { installDom, localStorageStub } from "./harness/dom.mjs";
import { mods, readVector, priv } from "./helpers/load.mjs";

installDom();
const M = await mods();
const { mailboxScript } = await import("./helpers/app-fakes.mjs");

test("the mailbox client, envelope bytes, queue and replay classifier", async () => {
  const v = readVector("mailbox");
  const got = await mailboxScript({ ...M, priv, localStorageStub });
  assert.deepEqual(got.keys, v.keys, "the per-room localStorage keys are a storage contract");
  assert.deepEqual(got.auth, v.auth);
  assert.deepEqual(got.deposit, v.deposit);
  assert.deepEqual(got.replay, v.replay);
  assert.deepEqual(got.stateEmpty, v.stateEmpty);
  assert.deepEqual(got.queueAfterEntry, v.queueAfterEntry, "the identity record is enqueued AHEAD of the entry");
  // THE wire bytes: 0x02 | kMbx-seal(cid||block) then 0x01 | cid | block
  assert.deepEqual(got.deposits, v.deposits);
  assert.deepEqual(got.identEnvelopePrefix, v.identEnvelopePrefix);
  assert.equal(got.identFlag, v.identFlag);
  assert.deepEqual(got.sent, v.sent);
  assert.deepEqual(got.queueAfterRepeat, v.queueAfterRepeat, "an already-deposited hash is never re-queued");
  assert.deepEqual(got.qItemShapes, v.qItemShapes);
  assert.deepEqual(got.overCapQueue, v.overCapQueue, "an over-frame-cap item is dropped like a 413");
  assert.deepEqual(got.processed, v.processed);
  // the stored queue-item shapes, key order spelled out (localStorage JSON)
  assert.deepEqual(Object.keys(JSON.parse(v.qItemShapes.entry)), ["t", "hash"]);
  assert.deepEqual(Object.keys(JSON.parse(v.qItemShapes.img)), ["t", "cid", "group"]);
});

test("a failed queue persist is SURFACED through onNotice, once — never swallowed", () => {
  // The outgoing queue is uncapped (no silent drop-oldest — the suite's rule is
  // bound WORK, never HISTORY), so the one remaining way to lose a queued item
  // is localStorage refusing the write (quota, private mode). That failure must
  // reach the user: save-queue! reads save-json's verdict and raises the room's
  // onNotice exactly once per session.
  localStorageStub.clear();
  const notices = [];
  const m = new M.MailboxSync({
    log: {},
    client: {},
    cipher: {},
    maxMessageKb: 64,
    keys: {
      cursor: M.nsKey("mbx-cursor:R"),
      queue: M.nsKey("mbx-queue:R"),
      sent: M.nsKey("mbx-sent:R"),
      retry: M.nsKey("mbx-retry:R"),
      ident: M.nsKey("mbx-ident:R"),
    },
    hasIdentity: false,
    onNotice: (msg) => notices.push(msg),
  });
  const item = { t: "entry", hash: "h0" };
  m._push(item);
  // …and the queue itself is uncapped: well past the retired 500 drop-oldest
  for (let i = 1; i <= 600; i++) m._push({ t: "entry", hash: `h${i}` });
  assert.equal(m._queue.length, 601, "every queued op survives — nothing was dropped");
  assert.equal(m._queue[0].hash, "h0", "the EARLIEST op survives — drop-oldest is gone");

  const realSetItem = localStorageStub.setItem;
  try {
    localStorageStub.setItem = () => { throw new Error("QuotaExceededError"); };
    m._dropHead(item);                      // synchronous persist path
    assert.deepEqual(notices.length, 1, "the failed persist must be surfaced");
    m._dropHead({ t: "entry", hash: "h1" });
    assert.deepEqual(notices.length, 1, "…and only once per session");
  } finally {
    localStorageStub.setItem = realSetItem;
  }
});

static mirror of HEAD · about · clone: git clone https://git.ardegazu.ro/chat.git