mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
After socket.setEncoding(enc), socket.pipe(destination) wrote the raw bytes it read to the destination. It now writes the decoded strings, as Node's pipe writes each string chunk: the destination receives their UTF-8 bytes, and a partial character the decoder holds at EOF is written before the destination ends. tests/node-parallel/run.mjs runs each job's files with its own TEST_THREAD_ID, as Node's test runner does, so test/common/tmpdir gives concurrent files different directories instead of one shared .tmp.0.
109 lines
4.4 KiB
TypeScript
109 lines
4.4 KiB
TypeScript
import { spawnSync } from "node:child_process";
|
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join, relative, resolve } from "node:path";
|
|
import { afterAll, expect, test } from "vitest";
|
|
// @ts-expect-error -- a plain ESM helper of the runner script
|
|
import { sameTermination, termination } from "../node-parallel/verdict.mjs";
|
|
|
|
const repo = resolve(import.meta.dirname, "../..");
|
|
const scratch = mkdtempSync(join(tmpdir(), "scriptc-node-parallel-"));
|
|
afterAll(() => rmSync(scratch, { recursive: true, force: true }));
|
|
|
|
test("runs that end by different signals, or by a signal and an exit, differ", () => {
|
|
expect(sameTermination({ code: 0, signal: null }, { code: 0, signal: null })).toBe(true);
|
|
expect(
|
|
sameTermination({ code: null, signal: "SIGABRT" }, { code: null, signal: "SIGABRT" }),
|
|
).toBe(true);
|
|
expect(
|
|
sameTermination({ code: null, signal: "SIGABRT" }, { code: null, signal: "SIGSEGV" }),
|
|
).toBe(false);
|
|
expect(sameTermination({ code: 1, signal: null }, { code: null, signal: "SIGKILL" })).toBe(false);
|
|
expect(sameTermination({ code: 0, signal: null }, { code: 1, signal: null })).toBe(false);
|
|
expect(termination({ code: null, signal: "SIGSEGV" })).toBe("SIGSEGV");
|
|
expect(termination({ code: 0, signal: null })).toBe(0);
|
|
});
|
|
|
|
test("a relative --node path links the checkout's fixtures and common helpers into the minimal tree", () => {
|
|
const checkout = join(scratch, "node");
|
|
mkdirSync(join(checkout, "test", "parallel"), { recursive: true });
|
|
mkdirSync(join(checkout, "test", "fixtures"), { recursive: true });
|
|
mkdirSync(join(checkout, "test", "common"), { recursive: true });
|
|
writeFileSync(join(checkout, "test", "fixtures", "marker.txt"), "fixture\n");
|
|
for (const helper of ["fixtures.js", "dns.js", "internet.js"])
|
|
writeFileSync(
|
|
join(checkout, "test", "common", helper),
|
|
`module.exports = ${JSON.stringify(helper)};\n`,
|
|
);
|
|
const out = join(scratch, "out");
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[
|
|
join(repo, "tests/node-parallel/run.mjs"),
|
|
"--node",
|
|
relative(scratch, checkout),
|
|
"--pattern",
|
|
"^no-such-test$",
|
|
"--out",
|
|
out,
|
|
],
|
|
{ cwd: scratch, encoding: "utf8" },
|
|
);
|
|
expect(result.status, result.stderr).toBe(0);
|
|
const linked = join(out, "tree", "test", "fixtures", "marker.txt");
|
|
expect(existsSync(linked)).toBe(true);
|
|
expect(readFileSync(linked, "utf8")).toBe("fixture\n");
|
|
for (const helper of ["dns.js", "internet.js"])
|
|
expect(readFileSync(join(out, "tree", "test", "common", helper), "utf8")).toBe(
|
|
`module.exports = ${JSON.stringify(helper)};\n`,
|
|
);
|
|
expect(existsSync(join(out, "tree", "test", "common", "tmpdir.js"))).toBe(true);
|
|
});
|
|
|
|
test("concurrent files get their own test/common tmpdir", () => {
|
|
const checkout = join(scratch, "node-tmpdir");
|
|
mkdirSync(join(checkout, "test", "parallel"), { recursive: true });
|
|
mkdirSync(join(checkout, "test", "fixtures"), { recursive: true });
|
|
mkdirSync(join(checkout, "test", "common"), { recursive: true });
|
|
for (const helper of ["fixtures.js", "dns.js", "internet.js"])
|
|
writeFileSync(join(checkout, "test", "common", helper), "module.exports = {};\n");
|
|
// Each file refreshes the tmpdir, writes a marker and reads it back after
|
|
// the other file has refreshed its own: with a shared directory the
|
|
// marker is gone and the file exits with 1.
|
|
const body = `const fs = require("fs");
|
|
const tmpdir = require("../common/tmpdir");
|
|
tmpdir.refresh();
|
|
fs.writeFileSync(tmpdir.resolve("marker"), __filename);
|
|
setTimeout(() => {
|
|
process.exit(fs.existsSync(tmpdir.resolve("marker")) ? 0 : 1);
|
|
}, 500);
|
|
`;
|
|
for (const name of ["test-tmp-a.js", "test-tmp-b.js"])
|
|
writeFileSync(join(checkout, "test", "parallel", name), body);
|
|
const failingCli = join(scratch, "failing-cli.mjs");
|
|
writeFileSync(failingCli, "process.exit(1);\n");
|
|
const out = join(scratch, "out-tmpdir");
|
|
const result = spawnSync(
|
|
process.execPath,
|
|
[
|
|
join(repo, "tests/node-parallel/run.mjs"),
|
|
"--node",
|
|
checkout,
|
|
"--pattern",
|
|
"^test-tmp-",
|
|
"--out",
|
|
out,
|
|
"--cli",
|
|
failingCli,
|
|
"--jobs",
|
|
"2",
|
|
],
|
|
{ cwd: scratch, encoding: "utf8" },
|
|
);
|
|
expect(result.status, result.stderr).toBe(0);
|
|
const results = JSON.parse(readFileSync(join(out, "results.json"), "utf8")) as {
|
|
nodeExit: number;
|
|
}[];
|
|
expect(results.map((r) => r.nodeExit)).toEqual([0, 0]);
|
|
});
|