A person's own client, and pins that the wire did not change #13
@@ -0,0 +1,54 @@
|
||||
// The TypeScript implementation, held to the shared fixtures (novox/hq ADR 0074, design 19).
|
||||
//
|
||||
// Run against a NATS server, because the question is what actually reaches the wire:
|
||||
//
|
||||
// docker run -d --rm --name c -p 14222:4222 nats:2.10-alpine -js
|
||||
// node test/conformance.mjs
|
||||
//
|
||||
// **The runner lives with the implementation it exercises; the fixture does not.** It is read
|
||||
// from the sdk's conformance directory by sibling path — the same file the Go suite reads. A
|
||||
// fixture copied into each implementation is two fixtures, and two fixtures drift, which is the
|
||||
// failure the suite exists to prevent.
|
||||
import { readFileSync } from "node:fs";
|
||||
import { connect } from "nats";
|
||||
|
||||
const clientPath = process.argv[2] ?? "../dist/broker-nats.js";
|
||||
const { connectNats } = await import(clientPath);
|
||||
const f = JSON.parse(readFileSync(new URL("../../mesh-sdk/conformance/events/module-event.json", import.meta.url)));
|
||||
const URL_ = process.env.MESH_TEST_NATS ?? "nats://127.0.0.1:14222";
|
||||
|
||||
let failed = 0;
|
||||
const check = (ok, what) => { console.log(` ${ok ? "ok " : "FAIL"} ${what}`); if (!ok) failed++; };
|
||||
|
||||
const admin = await connect({ servers: URL_ });
|
||||
const jsm = await admin.jetstreamManager();
|
||||
await jsm.streams.add({ name: "EVENTS", subjects: ["mesh.mod.*.event.>", "mesh.seat.*.event.>"] });
|
||||
|
||||
const shop = await connectNats({ url: URL_, node: f.given.node, module: f.given.module });
|
||||
await shop.publish({ key: f.given.key, node: f.given.node, body: f.given.body, headers: f.given.headers });
|
||||
|
||||
// What actually landed, read back from the stream rather than from the client that wrote it.
|
||||
const msg = await jsm.streams.getMessage("EVENTS", { last_by_subj: f.wire.subject });
|
||||
check(!!msg, `it lands on ${f.wire.subject}`);
|
||||
|
||||
if (msg) {
|
||||
const got = {};
|
||||
if (msg.header) for (const k of msg.header.keys()) got[k] = msg.header.get(k);
|
||||
for (const h of f.wire.requiredHeaders) {
|
||||
check(got[h] !== undefined && got[h] !== "", `${h} is set`);
|
||||
}
|
||||
check(got["content-type"] === f.wire.headerFormats["content-type"], "content-type is as pinned");
|
||||
check(new RegExp(f.wire.headerFormats["x-event-id"]).test(got["x-event-id"]), "x-event-id is as pinned");
|
||||
check(!Number.isNaN(Date.parse(got["x-time"])), "x-time parses as a date");
|
||||
check(got["x-source"] === f.given.module, "x-source agrees with the subject's module");
|
||||
|
||||
const payload = JSON.parse(new TextDecoder().decode(msg.data));
|
||||
check(payload.envelope === undefined && payload.key === undefined,
|
||||
"the payload is the body alone, not the envelope (the fixture refuses nesting)");
|
||||
check(JSON.stringify(payload) === JSON.stringify(f.given.body),
|
||||
"the body round-trips — semantic, not byte-exact, per the README");
|
||||
}
|
||||
|
||||
await shop.close(); await admin.close();
|
||||
console.log(failed ? `\n${failed} failed` : "\nall passed");
|
||||
process.exit(failed ? 1 : 0);
|
||||
Reference in New Issue
Block a user