0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-10-31 09:14:20 -04:00
denoland-deno/cli/tests/unit/signal_test.ts
Nayeem Rahman 45c49034a7
BREAKING(unstable): Improve Deno.spawn() stdio API (#14919)
- "SpawnOutput" extends "ChildStatus" instead of composing it
- "SpawnOutput::stdout", "SpawnOutput::stderr", "Child::stdin", 
"Child::stdout" and "Child::stderr" are no longer optional, instead 
made them getters that throw at runtime if that stream wasn't set 
to "piped". 
- Remove the complicated "<T extends SpawnOptions = SpawnOptions>" 
which we currently need to give proper type hints for the availability of 
these fields. Their typings for these would get increasingly complex 
if it became dependent on more options (e.g. "SpawnOptions::pty" 
which if set should make the stdio streams unavailable)
2022-07-18 15:16:12 +02:00

285 lines
6.2 KiB
TypeScript

// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertThrows, deferred, delay } from "./test_util.ts";
Deno.test(
{ ignore: Deno.build.os !== "windows" },
function signalsNotImplemented() {
const msg =
"Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK).";
assertThrows(
() => {
Deno.addSignalListener("SIGALRM", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGCHLD", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGHUP", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGIO", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGPIPE", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGQUIT", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGTERM", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGUSR1", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGUSR2", () => {});
},
Error,
msg,
);
assertThrows(
() => {
Deno.addSignalListener("SIGWINCH", () => {});
},
Error,
msg,
);
assertThrows(
() => Deno.addSignalListener("SIGKILL", () => {}),
Error,
msg,
);
assertThrows(
() => Deno.addSignalListener("SIGSTOP", () => {}),
Error,
msg,
);
assertThrows(
() => Deno.addSignalListener("SIGILL", () => {}),
Error,
msg,
);
assertThrows(
() => Deno.addSignalListener("SIGFPE", () => {}),
Error,
msg,
);
assertThrows(
() => Deno.addSignalListener("SIGSEGV", () => {}),
Error,
msg,
);
},
);
Deno.test(
{
ignore: Deno.build.os === "windows",
permissions: { run: true },
},
async function signalListenerTest() {
const resolvable = deferred();
let c = 0;
const listener = () => {
c += 1;
};
Deno.addSignalListener("SIGUSR1", listener);
setTimeout(async () => {
// Sends SIGUSR1 3 times.
for (const _ of Array(3)) {
await delay(20);
Deno.kill(Deno.pid, "SIGUSR1");
}
await delay(20);
Deno.removeSignalListener("SIGUSR1", listener);
resolvable.resolve();
});
await resolvable;
assertEquals(c, 3);
},
);
Deno.test(
{
ignore: Deno.build.os === "windows",
permissions: { run: true },
},
async function multipleSignalListenerTest() {
const resolvable = deferred();
let c = "";
const listener0 = () => {
c += "0";
};
const listener1 = () => {
c += "1";
};
Deno.addSignalListener("SIGUSR2", listener0);
Deno.addSignalListener("SIGUSR2", listener1);
setTimeout(async () => {
// Sends SIGUSR2 3 times.
for (const _ of Array(3)) {
await delay(20);
Deno.kill(Deno.pid, "SIGUSR2");
}
await delay(20);
Deno.removeSignalListener("SIGUSR2", listener1);
// Sends SIGUSR2 3 times.
for (const _ of Array(3)) {
await delay(20);
Deno.kill(Deno.pid, "SIGUSR2");
}
await delay(20);
// Sends SIGUSR1 (irrelevant signal) 3 times.
for (const _ of Array(3)) {
await delay(20);
Deno.kill(Deno.pid, "SIGUSR1");
}
await delay(20);
Deno.removeSignalListener("SIGUSR2", listener0);
resolvable.resolve();
});
await resolvable;
// The first 3 events are handled by both handlers
// The last 3 events are handled only by handler0
assertEquals(c, "010101000");
},
);
// This tests that pending op_signal_poll doesn't block the runtime from exiting the process.
Deno.test(
{
permissions: { run: true, read: true },
},
async function canExitWhileListeningToSignal() {
const { code } = await Deno.spawn(Deno.execPath(), {
args: [
"eval",
"--unstable",
"Deno.addSignalListener('SIGINT', () => {})",
],
});
assertEquals(code, 0);
},
);
Deno.test(
{
ignore: Deno.build.os !== "windows",
permissions: { run: true },
},
function windowsThrowsOnNegativeProcessIdTest() {
assertThrows(
() => {
Deno.kill(-1, "SIGKILL");
},
TypeError,
"Invalid pid",
);
},
);
Deno.test(
{
ignore: Deno.build.os !== "windows",
permissions: { run: true },
},
function noOpenSystemIdleProcessTest() {
let signal: Deno.Signal = "SIGKILL";
assertThrows(
() => {
Deno.kill(0, signal);
},
TypeError,
`Invalid pid`,
);
signal = "SIGTERM";
assertThrows(
() => {
Deno.kill(0, signal);
},
TypeError,
`Invalid pid`,
);
},
);
Deno.test(function signalInvalidHandlerTest() {
assertThrows(() => {
// deno-lint-ignore no-explicit-any
Deno.addSignalListener("SIGINT", "handler" as any);
});
assertThrows(() => {
// deno-lint-ignore no-explicit-any
Deno.removeSignalListener("SIGINT", "handler" as any);
});
});
Deno.test(
{
ignore: Deno.build.os === "windows",
permissions: { run: true },
},
function signalForbiddenSignalTest() {
assertThrows(
() => Deno.addSignalListener("SIGKILL", () => {}),
TypeError,
"Binding to signal 'SIGKILL' is not allowed",
);
assertThrows(
() => Deno.addSignalListener("SIGSTOP", () => {}),
TypeError,
"Binding to signal 'SIGSTOP' is not allowed",
);
assertThrows(
() => Deno.addSignalListener("SIGILL", () => {}),
TypeError,
"Binding to signal 'SIGILL' is not allowed",
);
assertThrows(
() => Deno.addSignalListener("SIGFPE", () => {}),
TypeError,
"Binding to signal 'SIGFPE' is not allowed",
);
assertThrows(
() => Deno.addSignalListener("SIGSEGV", () => {}),
TypeError,
"Binding to signal 'SIGSEGV' is not allowed",
);
},
);