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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161 | /**
* The lib/net and lib/log branches no other vector reaches.
*
* helpers/edges.mjs states which branches, why each one is unreachable from
* net.json/log.json, and — importantly — what makes a vector recorded from the
* ClojureScript dist trustworthy when every other fixture here was recorded from
* the retired TypeScript build. Read that header before changing anything in
* this file.
*
* Like every other vector in this suite: a failure here is a FINDING. The
* fixture is never regenerated to make the suite green.
*/
import { test } from "node:test";
import assert from "node:assert/strict";
import { load, readVector, priv } from "./helpers/load.mjs";
import { edgeScript } from "./helpers/edges.mjs";
const json = (x) => JSON.parse(JSON.stringify(x));
const NET_PRIVATES = [
"dialPeer", "recFor", "onConnChange", "refreshState", "maybeReady", "sweep", "endChannels",
"dropPeer", "hangUpStr", "beacon", "verified", "onTopicMessage", "onPresence", "beaconTo",
"onMsgFrame", "frame", "relayPeerId", "ensureRelay", "scheduleRedial", "setRelayUp", "pubsub",
];
const LOG_PRIVATES = ["emit", "onUpdate", "sweepUnseen", "authorOf", "canJoinLocally", "identityLocal"];
const run = async () => {
const { Net } = await load("lib/net.js", { Net: NET_PRIVATES });
const { RoomLog } = await load("lib/log.js", { RoomLog: LOG_PRIVATES });
const { RoomCrypto } = await load("lib/crypto.js");
const { makeLogEncryption } = await load("lib/encryption.js");
return json(await edgeScript({ Net, RoomLog, RoomCrypto, makeLogEncryption, priv }));
};
test("the uncovered branches of the membership machine and the log", async () => {
assert.deepEqual(await run(), await readVector("edges"));
});
/**
* A transcript is only worth what its assertions are, so name the specific
* properties this fixture exists to hold — each one a branch net.json cannot see.
*/
test("and the specific properties that transcript is for", async () => {
const at = new Map(await run());
// conn-state's two ZERO-CONNECTION branches. net.json only ever shows
// "relayed" and "direct".
assert.equal(at.get("refresh-zero-unverified").state, "connecting");
assert.equal(at.get("refresh-zero-verified").state, "disconnected");
// ... and the two effects that ride along: ready cleared, channels torn down
assert.equal(at.get("refresh-zero-verified").ready, false);
assert.equal(at.get("refresh-zero-verified").out, 0);
// the silent variant emits nothing at all
assert.deepEqual(at.get("refresh-zero-verified-silent").events, []);
// send-frame opens ONE stream and then reuses it. net.json's three
// dialProtocol calls are three different peers, one send each, so the reuse
// branch never runs there.
const first = at.get("first-send-opens-one-stream");
assert.equal(first.out, 1);
assert.equal(first.calls.filter((c) => c[0] === "dialProtocol").length, 1);
const more = at.get("three-more-sends-no-new-stream");
assert.equal(more.out, 1, "still the same one stream");
assert.deepEqual(more.calls, [], "three further sends, two of them binary, dialled nothing");
// a bye from a peer that never proved membership emits no peerGone
assert.deepEqual(at.get("bye-unverified").events, []);
// a non-string name must not overwrite the stored one
const named = at.get("presence-nonstring-name").state.find((r) => r[0] === "12D3KooP");
assert.equal(named[2], "pal");
assert.equal(at.get("presence-rename").state.find((r) => r[0] === "12D3KooP")[2], "renamed");
// both sweep verdicts, and only the right one at each boundary
assert.deepEqual(at.get("sweep-stranger-only").events, []);
assert.ok(at.get("sweep-stranger-only").state.every((r) => r[0] !== "12D3KooFRESH"), "stranger forgotten");
assert.ok(at.get("sweep-stale").events.some((e) => e[0] === "peerGone"), "stale member announced gone");
// close() removes every wake listener, clears every timer, and then
// everything is inert. The listeners and timers are planted by the script —
// start() never runs here, so without that this would pin 0 === 0.
const closed = at.get("after-close");
assert.deepEqual(closed.removed.map((r) => r[0]), ["visibilitychange", "pageshow", "online", "pagehide"]);
assert.deepEqual(closed.cleared, [["interval", 11], ["interval", 12], ["interval", 13], ["timeout", 99]]);
assert.equal(closed.listeners, 0, "and the array is emptied so a second close is a no-op");
assert.equal(at.get("beacon-after-close"), null);
assert.equal(at.get("dialPeer-after-close"), null);
assert.equal(at.get("scheduleRedial-after-close"), "undefined");
assert.deepEqual(at.get("final-calls"), []);
// log's defensive edges: none of these throw, all of them drop
assert.equal(at.get("emit-falsy"), null);
assert.equal(at.get("emit-no-hash"), null);
assert.equal(at.get("emit-empty-hash"), null);
assert.equal(at.get("entryMeta-null-payload"), null);
assert.equal(at.get("entryMeta-untyped"), null);
assert.equal(at.get("authorOf-no-key"), "");
assert.equal(at.get("authorOf-no-ref"), "");
assert.equal(at.get("identityLocal-no-ref"), false);
assert.equal(at.get("rawBlock-throwing-cid"), null);
assert.equal(at.get("sealedEntryBytes-missing"), null);
assert.deepEqual(at.get("imageDagBlocks-unparseable"), []);
assert.equal(at.get("myIdentityBlock-bad-hash"), null);
// and nothing reached the app through any of them
assert.deepEqual(at.get("emitted"), []);
});
/**
* Non-vacuity. A transcript comparison passes trivially if the transcript is
* empty, or if the interesting rows are constants the script would produce
* whatever the code did. Perturb each load-bearing row and assert the
* comparison notices — the executable half of the probe the plan requires; the
* manual mutation runs are recorded in the commit message.
*/
test("the edges vector is not vacuous", async () => {
const V = await readVector("edges");
const clone = () => JSON.parse(JSON.stringify(V));
const row = (v, label) => v.find((r) => r[0] === label);
assert.equal(V.length, 34);
assert.equal(new Set(V.map((r) => r[0])).size, 34, "every label is distinct");
// the zero-connection state strings
for (const [label, key, bad] of [
["refresh-zero-unverified", "state", "relayed"],
["refresh-zero-verified", "state", "connecting"],
["refresh-zero-verified", "ready", true],
["refresh-zero-verified", "out", 1],
]) {
const v = clone();
row(v, label)[1][key] = bad;
assert.notDeepEqual(v, V, `${label}.${key} perturbation went unnoticed`);
}
// the channel-reuse row: a stray dialProtocol must break it
const reused = clone();
row(reused, "three-more-sends-no-new-stream")[1].calls.push(["dialProtocol", "12D3KooP", "/sueta/2/msg/1.0"]);
assert.notDeepEqual(reused, V);
// a leaked wake listener, an unremoved handler, an uncleared timer
for (const patch of [
(r) => { r.listeners = 4; },
(r) => { r.removed.pop(); },
(r) => { r.cleared = r.cleared.filter((c) => c[0] !== "timeout"); },
]) {
const v = clone();
patch(row(v, "after-close")[1]);
assert.notDeepEqual(v, V);
}
// a log edge that surfaced something instead of dropping it
const surfaced = clone();
row(surfaced, "emitted")[1].push("z");
assert.notDeepEqual(surfaced, V);
// and the rows are real, not empty: the transcript records actual side effects
assert.ok(row(V, "first-send-opens-one-stream")[1].calls.length > 0, "the first send really dialled");
assert.ok(row(V, "peer-verified-direct")[1].events.length > 0, "the peer really verified");
assert.equal(row(V, "after-close")[1].removed.length, 4, "there were listeners to remove");
assert.equal(row(V, "after-close")[1].cleared.length, 4, "there were timers to clear");
});
|