Files
claudemesh/apps/broker/scripts/peer-b.ts
Alejandro Gutiérrez 76760c9b8c
Some checks failed
CI / Tests / 🧪 Test (push) Has been cancelled
test(broker): smoke test for hello + direct message flow
Adds scripts/{seed-test-mesh,peer-a,peer-b,smoke-test}.ts|.sh that
prove an end-to-end message flow works against a real Postgres:

- seed-test-mesh.ts creates user+mesh+2 members with deterministic
  hex pubkeys ("aa..aa", "bb..bb"), writes seed JSON to stdout
- peer-a.ts sends hello then a direct "send" message to peer B's
  pubkey with fake ciphertext "hello-from-a"
- peer-b.ts sends hello, waits up to 5s for a push, asserts
  senderPubkey matches peer A, exits 0/1
- smoke-test.sh wires the three together

Verified flow: hello registers presence row → send queues into
mesh.message_queue → fanout matches connected peer by pubkey →
drainForMember joins on mesh.member for senderPubkey → push lands
with ciphertext + correct sender attribution.

Also fixes a date-serialization bug that blocked the first run:
applyPendingHookStatus used `sql${col} >= ${jsDate}` which passed
JS Date.toString() to Postgres (failed to parse). Replaced raw
sql`` template with typed gte/desc/isNotNull operators from
drizzle-orm. Same fix applied in sweepPendingStatuses.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:53:33 +01:00

80 lines
2.0 KiB
TypeScript

#!/usr/bin/env bun
/**
* Smoke-test peer B (receiver).
*
* Connects, sends hello, then waits up to 5s for a push from peer A.
* Exits 0 on successful receive with matching senderPubkey, 1 on
* timeout or mismatch.
*/
import { readFileSync } from "node:fs";
import WebSocket from "ws";
const seed = JSON.parse(readFileSync("/tmp/smoke-seed.json", "utf-8")) as {
meshId: string;
peerA: { memberId: string; pubkey: string };
peerB: { memberId: string; pubkey: string };
};
const BROKER = process.env.BROKER_WS_URL ?? "ws://localhost:7900/ws";
const ws = new WebSocket(BROKER);
let received = false;
ws.on("open", () => {
console.log("[peer-b] connected, sending hello");
ws.send(
JSON.stringify({
type: "hello",
meshId: seed.meshId,
memberId: seed.peerB.memberId,
pubkey: seed.peerB.pubkey,
sessionId: "peer-b-session",
pid: process.pid,
cwd: "/tmp/peer-b",
signature: "stub",
nonce: "stub",
}),
);
});
ws.on("message", (raw) => {
const msg = JSON.parse(raw.toString()) as {
type: string;
senderPubkey?: string;
ciphertext?: string;
code?: string;
message?: string;
};
console.log("[peer-b] recv:", JSON.stringify(msg));
if (msg.type === "push") {
if (msg.senderPubkey === seed.peerA.pubkey) {
console.log("[peer-b] ✓ got expected push from peer-a");
received = true;
ws.close();
process.exit(0);
} else {
console.error(
`[peer-b] ✗ wrong senderPubkey: got ${msg.senderPubkey}, expected ${seed.peerA.pubkey}`,
);
ws.close();
process.exit(1);
}
}
if (msg.type === "error") {
console.error(`[peer-b] ✗ broker error: ${msg.code} ${msg.message}`);
ws.close();
process.exit(1);
}
});
ws.on("error", (e) => console.error("[peer-b] ws error:", e.message));
ws.on("close", () => console.log("[peer-b] closed"));
setTimeout(() => {
if (!received) {
console.error("[peer-b] ✗ timeout waiting for push (5s)");
process.exit(1);
}
}, 5000);