tests/windows.test.ts
Rama main · réplica de lectura del repositorio original.
// The cross-window protocol (client/windows/).
//
// The rule that matters is the LEASE tie-break, and what makes it a protocol
// rather than a coordinator is that both windows compute it independently and
// have to reach the same answer. So this is a test about agreement: for every
// pair of windows, exactly one of them believes it holds the pen.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { winsAgainst } from "../client/windows/identity.ts";
import { pick, rng } from "./helpers/vault.ts";
describe("the write lease", () => {
it("gives the pen to the window that has been open longest", () => {
const older = { at: 1000, id: "ffff" };
const newer = { at: 2000, id: "0000" };
assert.equal(winsAgainst(older, newer), true);
assert.equal(winsAgainst(newer, older), false);
});
it("breaks a same-millisecond tie on the id, not on luck", () => {
// Two windows opened in one millisecond is not exotic: a scripted pop-out
// does it every time. The id is arbitrary and, crucially, AGREED.
const a = { at: 5, id: "aaaa" };
const b = { at: 5, id: "bbbb" };
assert.equal(winsAgainst(a, b), true);
assert.equal(winsAgainst(b, a), false);
});
it("is ANTISYMMETRIC for every pair — exactly one window ever holds it", () => {
// The property the whole design rests on. If both sides could believe they
// held the pen, two windows would autosave into one file and the write
// precondition would be catching a conflict the app manufactured itself.
const next = rng(7);
const times = [1, 2, 3, 1000, 1000, 1000];
const ids = ["0000", "00ff", "a1b2", "ffff", "0a0a"];
for (let i = 0; i < 5000; i++) {
const a = { at: pick(next, times), id: pick(next, ids) };
const b = { at: pick(next, times), id: pick(next, ids) };
if (a.at === b.at && a.id === b.id) continue; // the same window
assert.notEqual(
winsAgainst(a, b),
winsAgainst(b, a),
`both or neither held the lease: ${JSON.stringify([a, b])}`,
);
}
});
it("is TRANSITIVE, so three windows cannot form a cycle", () => {
// Without this, three windows could each believe a different one of them
// was the writer and the note would never settle.
const next = rng(11);
const times = [1, 2, 2, 3];
const ids = ["a", "b", "c", "d"];
const mk = () => ({ at: pick(next, times), id: pick(next, ids) });
for (let i = 0; i < 5000; i++) {
const [a, b, c] = [mk(), mk(), mk()];
if (winsAgainst(a, b) && winsAgainst(b, c)) {
assert.equal(winsAgainst(a, c), true, `cycle: ${JSON.stringify([a, b, c])}`);
}
}
});
it("a window that reloads does not steal the pen back", () => {
// `windowBornAt` is in sessionStorage precisely so a refresh keeps the
// window's original age. If a reload minted a new "now", the refreshed
// window would look YOUNGER and lose — which is the correct outcome, and
// the reason the value is persisted rather than recomputed is the opposite
// case: it must not look older than it is and take the note from whoever
// legitimately holds it.
const original = { at: 1000, id: "aaaa" };
const peerWhoTookOver = { at: 900, id: "bbbb" };
assert.equal(winsAgainst(original, peerWhoTookOver), false);
});
});