test: expand dns zone and runner coverage

This commit is contained in:
Peter Steinberger 2026-03-13 19:10:11 +00:00
parent f155d8febc
commit 5024fd0908
2 changed files with 172 additions and 1 deletions

View File

@ -13,6 +13,17 @@ async function withTempDir<T>(run: (dir: string) => Promise<T>): Promise<T> {
} }
} }
function createExitedProcess(code: number | null, signal: string | null = null) {
return {
on: (event: string, cb: (code: number | null, signal: string | null) => void) => {
if (event === "exit") {
queueMicrotask(() => cb(code, signal));
}
return undefined;
},
};
}
describe("run-node script", () => { describe("run-node script", () => {
it.runIf(process.platform !== "win32")( it.runIf(process.platform !== "win32")(
"preserves control-ui assets by building with tsdown --no-clean", "preserves control-ui assets by building with tsdown --no-clean",
@ -66,4 +77,88 @@ describe("run-node script", () => {
}); });
}, },
); );
it("skips rebuilding when dist is current and the source tree is clean", async () => {
await withTempDir(async (tmp) => {
const srcPath = path.join(tmp, "src", "index.ts");
const distEntryPath = path.join(tmp, "dist", "entry.js");
const buildStampPath = path.join(tmp, "dist", ".buildstamp");
const tsconfigPath = path.join(tmp, "tsconfig.json");
const packageJsonPath = path.join(tmp, "package.json");
await fs.mkdir(path.dirname(srcPath), { recursive: true });
await fs.mkdir(path.dirname(distEntryPath), { recursive: true });
await fs.writeFile(srcPath, "export const value = 1;\n", "utf-8");
await fs.writeFile(tsconfigPath, "{}\n", "utf-8");
await fs.writeFile(packageJsonPath, '{"name":"openclaw-test"}\n', "utf-8");
await fs.writeFile(distEntryPath, "console.log('built');\n", "utf-8");
await fs.writeFile(buildStampPath, '{"head":"abc123"}\n', "utf-8");
const oldTime = new Date("2026-03-13T10:00:00.000Z");
const stampTime = new Date("2026-03-13T12:00:00.000Z");
await fs.utimes(srcPath, oldTime, oldTime);
await fs.utimes(tsconfigPath, oldTime, oldTime);
await fs.utimes(packageJsonPath, oldTime, oldTime);
await fs.utimes(distEntryPath, stampTime, stampTime);
await fs.utimes(buildStampPath, stampTime, stampTime);
const spawnCalls: string[][] = [];
const spawn = (cmd: string, args: string[]) => {
spawnCalls.push([cmd, ...args]);
return createExitedProcess(0);
};
const spawnSync = (cmd: string, args: string[]) => {
if (cmd === "git" && args[0] === "rev-parse") {
return { status: 0, stdout: "abc123\n" };
}
if (cmd === "git" && args[0] === "status") {
return { status: 0, stdout: "" };
}
return { status: 1, stdout: "" };
};
const { runNodeMain } = await import("../../scripts/run-node.mjs");
const exitCode = await runNodeMain({
cwd: tmp,
args: ["status"],
env: {
...process.env,
OPENCLAW_RUNNER_LOG: "0",
},
spawn,
spawnSync,
execPath: process.execPath,
platform: process.platform,
});
expect(exitCode).toBe(0);
expect(spawnCalls).toEqual([[process.execPath, "openclaw.mjs", "status"]]);
});
});
it("returns the build exit code when the compiler step fails", async () => {
await withTempDir(async (tmp) => {
const spawn = (cmd: string) => {
if (cmd === "pnpm") {
return createExitedProcess(23);
}
return createExitedProcess(0);
};
const { runNodeMain } = await import("../../scripts/run-node.mjs");
const exitCode = await runNodeMain({
cwd: tmp,
args: ["status"],
env: {
...process.env,
OPENCLAW_FORCE_BUILD: "1",
OPENCLAW_RUNNER_LOG: "0",
},
spawn,
execPath: process.execPath,
platform: process.platform,
});
expect(exitCode).toBe(23);
});
});
}); });

View File

@ -1,10 +1,33 @@
import { describe, expect, it } from "vitest"; import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import * as utils from "../utils.js";
import { import {
getWideAreaZonePath,
normalizeWideAreaDomain, normalizeWideAreaDomain,
renderWideAreaGatewayZoneText, renderWideAreaGatewayZoneText,
resolveWideAreaDiscoveryDomain, resolveWideAreaDiscoveryDomain,
writeWideAreaGatewayZone,
} from "./widearea-dns.js"; } from "./widearea-dns.js";
const baseZoneOpts = {
domain: "openclaw.internal.",
gatewayPort: 18789,
displayName: "Mac Studio (OpenClaw)",
tailnetIPv4: "100.123.224.76",
hostLabel: "studio-london",
instanceLabel: "studio-london",
} as const;
function makeZoneOpts(overrides: Partial<typeof baseZoneOpts> = {}) {
return { ...baseZoneOpts, ...overrides };
}
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();
});
describe("wide-area DNS discovery domain helpers", () => { describe("wide-area DNS discovery domain helpers", () => {
it.each([ it.each([
{ value: "openclaw.internal", expected: "openclaw.internal." }, { value: "openclaw.internal", expected: "openclaw.internal." },
@ -45,6 +68,12 @@ describe("wide-area DNS discovery domain helpers", () => {
])("$name", ({ params, expected }) => { ])("$name", ({ params, expected }) => {
expect(resolveWideAreaDiscoveryDomain(params)).toBe(expected); expect(resolveWideAreaDiscoveryDomain(params)).toBe(expected);
}); });
it("builds the default zone path from the normalized domain", () => {
expect(getWideAreaZonePath("openclaw.internal.")).toBe(
path.join(utils.CONFIG_DIR, "dns", "openclaw.internal.db"),
);
});
}); });
describe("wide-area DNS-SD zone rendering", () => { describe("wide-area DNS-SD zone rendering", () => {
@ -113,3 +142,50 @@ describe("wide-area DNS-SD zone rendering", () => {
expect(txt).toContain(`cliPath=/opt/homebrew/bin/openclaw`); expect(txt).toContain(`cliPath=/opt/homebrew/bin/openclaw`);
}); });
}); });
describe("wide-area DNS zone writes", () => {
it("rejects blank domains", async () => {
await expect(writeWideAreaGatewayZone(makeZoneOpts({ domain: " " }))).rejects.toThrow(
"wide-area discovery domain is required",
);
});
it("skips rewriting unchanged content", async () => {
vi.spyOn(utils, "ensureDir").mockResolvedValue(undefined);
const existing = renderWideAreaGatewayZoneText({ ...makeZoneOpts(), serial: 2026031301 });
vi.spyOn(fs, "readFileSync").mockReturnValue(existing);
const writeSpy = vi.spyOn(fs, "writeFileSync").mockImplementation(() => undefined);
const result = await writeWideAreaGatewayZone(makeZoneOpts());
expect(result).toEqual({
zonePath: getWideAreaZonePath("openclaw.internal."),
changed: false,
});
expect(writeSpy).not.toHaveBeenCalled();
});
it("increments same-day serials when content changes", async () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-03-13T12:00:00.000Z"));
vi.spyOn(utils, "ensureDir").mockResolvedValue(undefined);
vi.spyOn(fs, "readFileSync").mockReturnValue(
renderWideAreaGatewayZoneText({ ...makeZoneOpts(), serial: 2026031304 }),
);
const writeSpy = vi.spyOn(fs, "writeFileSync").mockImplementation(() => undefined);
const result = await writeWideAreaGatewayZone(
makeZoneOpts({ gatewayTlsEnabled: true, gatewayTlsFingerprintSha256: "abc123" }),
);
expect(result).toEqual({
zonePath: getWideAreaZonePath("openclaw.internal."),
changed: true,
});
expect(writeSpy).toHaveBeenCalledWith(
getWideAreaZonePath("openclaw.internal."),
expect.stringContaining("@ IN SOA ns1 hostmaster 2026031305 7200 3600 1209600 60"),
"utf-8",
);
});
});