Skip to content

Commit 483f207

Browse files
ralyodioclaude
andauthored
test: catch the vendored DNS bridge drifting from the published one (#162)
src/dns.mjs is a copy of @moshcoder/moshpit-dns, and it stays a copy on purpose: moshcode ships as a tarball that nothing runs `npm install` over, so a runtime dependency would break every install. The cost of that choice is drift, and this makes drift loud instead of silent. Behaviour, not bytes. The two differ cosmetically — the standalone tool names itself in the config comments it writes — so a byte comparison would fail on that forever while missing a real divergence in what the protocol does. This runs both over the same inputs and requires the same answers: encoded names, decoded names including the rejections, parsed queries, and responses compared byte-for-byte on the wire, which is the one that matters most. A resolver that disagrees about bytes answers differently depending on which copy ran. A dev dependency, so the shipped tarball is unaffected and only CI pays for it. Skips cleanly when the package is not installed. Verified it can fail: changing DEFAULT_TTL in the vendored copy alone turns the suite red. A drift test that cannot catch drift is worse than none, because it reads like assurance. 485 pass, 120 skipped. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent abfc582 commit 483f207

3 files changed

Lines changed: 140 additions & 2 deletions

File tree

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,8 @@
2121
"README.md"
2222
],
2323
"license": "MIT",
24-
"packageManager": "pnpm@10.32.1"
24+
"packageManager": "pnpm@10.32.1",
25+
"devDependencies": {
26+
"@moshcoder/moshpit-dns": "^0.2.1"
27+
}
2528
}

pnpm-lock.yaml

Lines changed: 16 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/dns-drift.test.mjs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// The vendored DNS bridge, against the published one.
2+
//
3+
// src/dns.mjs is a copy of @moshcoder/moshpit-dns. It is a copy on purpose:
4+
// moshcode ships as a tarball that nothing runs `npm install` over, so a
5+
// runtime dependency would break every install. The cost of that choice is
6+
// drift, and the point of this file is to make drift loud instead of silent.
7+
//
8+
// Behaviour rather than bytes. The two differ cosmetically — the standalone
9+
// tool names itself in the config comments it writes — and a byte comparison
10+
// would fail on that forever while missing a real divergence in what the
11+
// protocol actually does. So this runs both over the same inputs and requires
12+
// the same answers.
13+
//
14+
// Skips when the package is not installed, so a checkout without dev
15+
// dependencies still runs the rest of the suite.
16+
import assert from "node:assert/strict";
17+
import test from "node:test";
18+
import { createRequire } from "node:module";
19+
20+
import * as vendored from "../src/dns.mjs";
21+
22+
const require = createRequire(import.meta.url);
23+
let published = null;
24+
try {
25+
published = await import("@moshcoder/moshpit-dns");
26+
} catch {
27+
published = null;
28+
}
29+
30+
test("vendored DNS bridge matches the published package", {
31+
skip: published ? false : "@moshcoder/moshpit-dns not installed",
32+
}, async (t) => {
33+
await t.test("the wire codec encodes names identically", () => {
34+
for (const name of ["blue.eggs", "a.b", "x".repeat(63) + ".eggs", "california.oranges"]) {
35+
assert.deepEqual(
36+
[...vendored.encodeName(name)],
37+
[...published.encodeName(name)],
38+
name,
39+
);
40+
}
41+
});
42+
43+
await t.test("names decode identically, including the failures", () => {
44+
for (const name of ["blue.eggs", "california.oranges"]) {
45+
const buf = vendored.encodeName(name);
46+
assert.deepEqual(vendored.decodeName(buf, 0), published.decodeName(buf, 0), name);
47+
}
48+
// A compression pointer in a question is rejected by both, or neither is
49+
// safe to put on a socket.
50+
const pointer = Buffer.from([0xc0, 0x0c]);
51+
assert.throws(() => vendored.decodeName(pointer, 0));
52+
assert.throws(() => published.decodeName(pointer, 0));
53+
});
54+
55+
await t.test("a query parses to the same question", () => {
56+
const question = Buffer.concat([
57+
Buffer.from([0x12, 0x34, 0x01, 0x00, 0, 1, 0, 0, 0, 0, 0, 0]),
58+
vendored.encodeName("blue.eggs"),
59+
Buffer.from([0, 1, 0, 1]),
60+
]);
61+
assert.deepEqual(vendored.parseQuery(question), published.parseQuery(question));
62+
});
63+
64+
await t.test("responses are byte-identical on the wire", () => {
65+
const question = Buffer.concat([
66+
Buffer.from([0x12, 0x34, 0x01, 0x00, 0, 1, 0, 0, 0, 0, 0, 0]),
67+
vendored.encodeName("blue.eggs"),
68+
Buffer.from([0, 1, 0, 1]),
69+
]);
70+
const q = vendored.parseQuery(question);
71+
// This is the one that matters most: a resolver that disagrees about bytes
72+
// is a resolver that answers differently depending on which copy ran.
73+
assert.deepEqual(
74+
[...vendored.buildResponse(q, question, "203.0.113.7", 30)],
75+
[...published.buildResponse(q, question, "203.0.113.7", 30)],
76+
);
77+
});
78+
79+
await t.test("the same hostnames are Moshpit names", () => {
80+
for (const h of ["blue.eggs", "a.b.c", "1.2.3.4", "localhost", "", "eggs", "blue.420", "1.420"]) {
81+
assert.deepEqual(vendored.parseRegistryName(h), published.parseRegistryName(h), h);
82+
}
83+
});
84+
85+
await t.test("resolution decides the same way on the same registry answer", async () => {
86+
const cases = [
87+
{ registered: true, name_registered: true, target: "203.0.113.9" },
88+
{ registered: true, name_registered: true, target: null },
89+
{ registered: true, name_registered: false, target: null },
90+
{ registered: false },
91+
];
92+
for (const body of cases) {
93+
const fetchImpl = async () => ({ ok: true, status: 200, json: async () => body });
94+
assert.deepEqual(
95+
await vendored.resolveName("blue.eggs", { fetchImpl }),
96+
await published.resolveName("blue.eggs", { fetchImpl }),
97+
JSON.stringify(body),
98+
);
99+
}
100+
});
101+
102+
await t.test("an unreachable registry fails the same way in both", async () => {
103+
const fetchImpl = async () => { throw new Error("offline"); };
104+
assert.deepEqual(
105+
await vendored.resolveName("blue.eggs", { fetchImpl }),
106+
await published.resolveName("blue.eggs", { fetchImpl }),
107+
);
108+
});
109+
110+
await t.test("the defaults have not drifted apart", () => {
111+
for (const key of ["DEFAULT_REGISTRY_BASE", "DEFAULT_PORT", "DEFAULT_HOST", "DEFAULT_TTL"]) {
112+
assert.equal(vendored[key], published[key], key);
113+
}
114+
});
115+
116+
await t.test("the published version is recorded, so a bump is a visible change", () => {
117+
const { version } = require("@moshcoder/moshpit-dns/package.json");
118+
assert.match(version, /^\d+\.\d+\.\d+/);
119+
});
120+
});

0 commit comments

Comments
 (0)