64 lines
2.3 KiB
TypeScript
64 lines
2.3 KiB
TypeScript
import { afterAll, describe, expect, it } from "vitest";
|
|
|
|
import { __resetBrokenPipeGuard, ignoreBrokenPipe } from "./process";
|
|
|
|
function makeError(code: string, message: string): NodeJS.ErrnoException {
|
|
return Object.assign(new Error(message), { code });
|
|
}
|
|
|
|
function lastErrorListener(stream: NodeJS.WriteStream): (err: NodeJS.ErrnoException) => void {
|
|
const listeners = stream.listeners("error");
|
|
return listeners[listeners.length - 1] as (err: NodeJS.ErrnoException) => void;
|
|
}
|
|
|
|
describe("ignoreBrokenPipe", () => {
|
|
// Capture the handler we install so we can both exercise and clean it up.
|
|
let installed: ((err: NodeJS.ErrnoException) => void) | undefined;
|
|
|
|
afterAll(() => {
|
|
if (installed) {
|
|
process.stdout.removeListener("error", installed);
|
|
process.stderr.removeListener("error", installed);
|
|
}
|
|
// Reset the module guard alongside listener removal so a later
|
|
// ignoreBrokenPipe() reattaches instead of hitting a no-op with no
|
|
// listeners present (order-independent for other tests in this worker).
|
|
__resetBrokenPipeGuard();
|
|
});
|
|
|
|
it("attaches an error handler to stdout and stderr", () => {
|
|
const stdoutBefore = process.stdout.listeners("error").length;
|
|
const stderrBefore = process.stderr.listeners("error").length;
|
|
|
|
ignoreBrokenPipe();
|
|
|
|
expect(process.stdout.listeners("error").length).toBe(stdoutBefore + 1);
|
|
expect(process.stderr.listeners("error").length).toBe(stderrBefore + 1);
|
|
|
|
// stdout and stderr share the same handler reference.
|
|
installed = lastErrorListener(process.stdout);
|
|
expect(lastErrorListener(process.stderr)).toBe(installed);
|
|
});
|
|
|
|
it("swallows EPIPE errors without throwing", () => {
|
|
const handler = lastErrorListener(process.stdout);
|
|
expect(() => handler(makeError("EPIPE", "write EPIPE"))).not.toThrow();
|
|
});
|
|
|
|
it("rethrows non-EPIPE errors", () => {
|
|
const handler = lastErrorListener(process.stdout);
|
|
expect(() => handler(makeError("EACCES", "boom"))).toThrow("boom");
|
|
});
|
|
|
|
it("is idempotent across repeated calls", () => {
|
|
const stdoutCount = process.stdout.listeners("error").length;
|
|
const stderrCount = process.stderr.listeners("error").length;
|
|
|
|
ignoreBrokenPipe();
|
|
ignoreBrokenPipe();
|
|
|
|
expect(process.stdout.listeners("error").length).toBe(stdoutCount);
|
|
expect(process.stderr.listeners("error").length).toBe(stderrCount);
|
|
});
|
|
});
|