Files
SnapOtter/tests/unit/scripts/run-fuzz-gate.node-test.mjs
T

116 lines
3.4 KiB
JavaScript
Raw Normal View History

import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import test from "node:test";
import {
acquireFuzzLock,
buildFuzzEnvironment,
fuzzLockPath,
parseFuzzArguments,
} from "../../../scripts/run-fuzz-gate.mjs";
test("parses canonical fuzz runner arguments", () => {
assert.deepEqual(parseFuzzArguments(["--runs", "50", "--seed=1234"]), {
help: false,
runs: 50,
seed: 1234,
});
assert.deepEqual(parseFuzzArguments(["--help"]), {
help: true,
runs: undefined,
seed: undefined,
});
assert.deepEqual(parseFuzzArguments(["--", "--runs", "25"]), {
help: false,
runs: 25,
seed: undefined,
});
assert.throws(() => parseFuzzArguments(["--runs", "0"]), /--runs.*between 1 and 10000/i);
assert.throws(() => parseFuzzArguments(["--seed", "NaN"]), /--seed.*integer/i);
assert.throws(() => parseFuzzArguments(["--unknown"]), /unknown argument/i);
});
test("forces the canonical single-fork fuzz environment", () => {
assert.deepEqual(
buildFuzzEnvironment(
{
FC_SEED: "5678",
FUZZ: "0",
FUZZ_RUNS: "10",
FUZZ_SEED: "8765",
VITEST_MAX_FORKS: "8",
},
{ help: false, runs: 50, seed: 1234 },
),
{
FUZZ: "1",
FUZZ_RUNS: "50",
FUZZ_SEED: "1234",
VITEST_MAX_FORKS: "1",
},
);
assert.deepEqual(buildFuzzEnvironment({ FC_SEED: "5678" }, { help: false }), {
FC_SEED: "5678",
FUZZ: "1",
VITEST_MAX_FORKS: "1",
});
});
test("derives a stable repo-scoped lock path", () => {
const firstRepo = mkdtempSync(join(tmpdir(), "snapotter-fuzz-repo-a-"));
const secondRepo = mkdtempSync(join(tmpdir(), "snapotter-fuzz-repo-b-"));
const nested = join(firstRepo, "nested");
try {
execFileSync("git", ["init", "--quiet"], { cwd: firstRepo });
execFileSync("git", ["init", "--quiet"], { cwd: secondRepo });
mkdirSync(nested);
assert.equal(fuzzLockPath(firstRepo), fuzzLockPath(nested));
assert.notEqual(fuzzLockPath(firstRepo), fuzzLockPath(secondRepo));
assert.match(fuzzLockPath(firstRepo), /snapotter-fuzz-[a-f0-9]{64}\.lock$/);
} finally {
rmSync(firstRepo, { force: true, recursive: true });
rmSync(secondRepo, { force: true, recursive: true });
}
});
test("refuses a second fuzz campaign and only releases its own lock", () => {
const root = mkdtempSync(join(tmpdir(), "snapotter-fuzz-lock-test-"));
const lockPath = join(root, "fuzz.lock");
try {
const first = acquireFuzzLock(lockPath, {
pid: process.pid,
startedAt: "2026-07-25T00:00:00.000Z",
token: "first-owner",
});
assert.equal(existsSync(lockPath), true);
assert.throws(
() =>
acquireFuzzLock(lockPath, {
pid: process.pid,
startedAt: "2026-07-25T00:00:01.000Z",
token: "second-owner",
}),
/another fuzz campaign is already running/i,
);
assert.equal(existsSync(lockPath), true);
first.release();
assert.equal(existsSync(lockPath), false);
const next = acquireFuzzLock(lockPath, {
pid: process.pid,
startedAt: "2026-07-25T00:00:02.000Z",
token: "next-owner",
});
next.release();
assert.equal(existsSync(lockPath), false);
} finally {
rmSync(root, { force: true, recursive: true });
}
});