summaryrefslogtreecommitdiff
path: root/cli/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'cli/tests/unit')
-rw-r--r--cli/tests/unit/command_test.ts687
-rw-r--r--cli/tests/unit/process_test.ts5
2 files changed, 690 insertions, 2 deletions
diff --git a/cli/tests/unit/command_test.ts b/cli/tests/unit/command_test.ts
new file mode 100644
index 000000000..f7213f034
--- /dev/null
+++ b/cli/tests/unit/command_test.ts
@@ -0,0 +1,687 @@
+// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
+import {
+ assert,
+ assertEquals,
+ assertRejects,
+ assertStringIncludes,
+ assertThrows,
+} from "./test_util.ts";
+
+Deno.test(
+ { permissions: { write: true, run: true, read: true } },
+ async function spawnWithCwdIsAsync() {
+ const enc = new TextEncoder();
+ const cwd = await Deno.makeTempDir({ prefix: "deno_command_test" });
+
+ const exitCodeFile = "deno_was_here";
+ const programFile = "poll_exit.ts";
+ const program = `
+async function tryExit() {
+ try {
+ const code = parseInt(await Deno.readTextFile("${exitCodeFile}"));
+ Deno.exit(code);
+ } catch {
+ // Retry if we got here before deno wrote the file.
+ setTimeout(tryExit, 0.01);
+ }
+}
+
+tryExit();
+`;
+
+ Deno.writeFileSync(`${cwd}/${programFile}`, enc.encode(program));
+
+ const child = Deno.spawnChild(Deno.execPath(), {
+ cwd,
+ args: ["run", "--allow-read", programFile],
+ stdout: "inherit",
+ stderr: "inherit",
+ });
+
+ // Write the expected exit code *after* starting deno.
+ // This is how we verify that `Child` is actually asynchronous.
+ const code = 84;
+ Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
+
+ const status = await child.status;
+ await Deno.remove(cwd, { recursive: true });
+ assertEquals(status.success, false);
+ assertEquals(status.code, code);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnStdinPiped() {
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: [
+ "eval",
+ "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
+ ],
+ stdin: "piped",
+ stdout: "null",
+ stderr: "null",
+ });
+
+ assert(child.stdin !== null);
+ assert(child.stdout === null);
+ assert(child.stderr === null);
+
+ const msg = new TextEncoder().encode("hello");
+ const writer = child.stdin.getWriter();
+ await writer.write(msg);
+ writer.releaseLock();
+
+ await child.stdin.close();
+ const status = await child.status;
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnStdoutPiped() {
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stdout.write(new TextEncoder().encode('hello'))",
+ ],
+ stderr: "null",
+ });
+
+ assert(child.stdin === null);
+ assert(child.stdout !== null);
+ assert(child.stderr === null);
+
+ const readable = child.stdout.pipeThrough(new TextDecoderStream());
+ const reader = readable.getReader();
+ const res = await reader.read();
+ assert(!res.done);
+ assertEquals(res.value, "hello");
+
+ const resEnd = await reader.read();
+ assert(resEnd.done);
+ assertEquals(resEnd.value, undefined);
+ reader.releaseLock();
+
+ const status = await child.status;
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnStderrPiped() {
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stderr.write(new TextEncoder().encode('hello'))",
+ ],
+ stderr: "piped",
+ stdout: "null",
+ });
+
+ assert(child.stdin === null);
+ assert(child.stdout === null);
+ assert(child.stderr !== null);
+
+ const readable = child.stderr.pipeThrough(new TextDecoderStream());
+ const reader = readable.getReader();
+ const res = await reader.read();
+ assert(!res.done);
+ assertEquals(res.value, "hello");
+
+ const resEnd = await reader.read();
+ assert(resEnd.done);
+ assertEquals(resEnd.value, undefined);
+ reader.releaseLock();
+
+ const status = await child.status;
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, write: true, read: true } },
+ async function spawnRedirectStdoutStderr() {
+ const tempDir = await Deno.makeTempDir();
+ const fileName = tempDir + "/redirected_stdio.txt";
+ const file = await Deno.open(fileName, {
+ create: true,
+ write: true,
+ });
+
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: [
+ "eval",
+ "Deno.stderr.write(new TextEncoder().encode('error\\n')); Deno.stdout.write(new TextEncoder().encode('output\\n'));",
+ ],
+ });
+ await child.stdout.pipeTo(file.writable, {
+ preventClose: true,
+ });
+ await child.stderr.pipeTo(file.writable);
+ await child.status;
+
+ const fileContents = await Deno.readFile(fileName);
+ const decoder = new TextDecoder();
+ const text = decoder.decode(fileContents);
+
+ assertStringIncludes(text, "error");
+ assertStringIncludes(text, "output");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, write: true, read: true } },
+ async function spawnRedirectStdin() {
+ const tempDir = await Deno.makeTempDir();
+ const fileName = tempDir + "/redirected_stdio.txt";
+ const encoder = new TextEncoder();
+ await Deno.writeFile(fileName, encoder.encode("hello"));
+ const file = await Deno.open(fileName);
+
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: [
+ "eval",
+ "if (new TextDecoder().decode(await Deno.readAll(Deno.stdin)) !== 'hello') throw new Error('Expected \\'hello\\'')",
+ ],
+ stdin: "piped",
+ stdout: "null",
+ stderr: "null",
+ });
+ await file.readable.pipeTo(child.stdin, {
+ preventClose: true,
+ });
+
+ await child.stdin.close();
+ const status = await child.status;
+ assertEquals(status.code, 0);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnKillSuccess() {
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: ["eval", "setTimeout(() => {}, 10000)"],
+ stdout: "null",
+ stderr: "null",
+ });
+
+ child.kill("SIGKILL");
+ const status = await child.status;
+
+ assertEquals(status.success, false);
+ if (Deno.build.os === "windows") {
+ assertEquals(status.code, 1);
+ assertEquals(status.signal, null);
+ } else {
+ assertEquals(status.code, 137);
+ assertEquals(status.signal, 9);
+ }
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnKillFailed() {
+ const child = Deno.spawnChild(Deno.execPath(), {
+ args: ["eval", "setTimeout(() => {}, 5000)"],
+ stdout: "null",
+ stderr: "null",
+ });
+
+ assertThrows(() => {
+ // @ts-expect-error testing runtime error of bad signal
+ child.kill("foobar");
+ }, TypeError);
+
+ await child.status;
+ },
+);
+
+Deno.test(
+ { permissions: { read: true, run: false } },
+ async function spawnPermissions() {
+ await assertRejects(async () => {
+ await Deno.spawn(Deno.execPath(), {
+ args: ["eval", "console.log('hello world')"],
+ });
+ }, Deno.errors.PermissionDenied);
+ },
+);
+
+Deno.test(
+ { permissions: { read: true, run: false } },
+ function spawnSyncPermissions() {
+ assertThrows(() => {
+ Deno.spawnSync(Deno.execPath(), {
+ args: ["eval", "console.log('hello world')"],
+ });
+ }, Deno.errors.PermissionDenied);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnSuccess() {
+ const { status } = await Deno.spawn(Deno.execPath(), {
+ args: ["eval", "console.log('hello world')"],
+ });
+
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncSuccess() {
+ const { status } = Deno.spawnSync(Deno.execPath(), {
+ args: ["eval", "console.log('hello world')"],
+ });
+
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnUrl() {
+ const { status, stdout } = await Deno.spawn(
+ new URL(`file:///${Deno.execPath()}`),
+ {
+ args: ["eval", "console.log('hello world')"],
+ },
+ );
+
+ assertEquals(new TextDecoder().decode(stdout), "hello world\n");
+
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncUrl() {
+ const { status, stdout } = Deno.spawnSync(
+ new URL(`file:///${Deno.execPath()}`),
+ {
+ args: ["eval", "console.log('hello world')"],
+ },
+ );
+
+ assertEquals(new TextDecoder().decode(stdout), "hello world\n");
+
+ assertEquals(status.success, true);
+ assertEquals(status.code, 0);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test({ permissions: { run: true } }, async function spawnNotFound() {
+ await assertRejects(
+ () => Deno.spawn("this file hopefully doesn't exist"),
+ Deno.errors.NotFound,
+ );
+});
+
+Deno.test({ permissions: { run: true } }, function spawnSyncNotFound() {
+ assertThrows(
+ () => Deno.spawnSync("this file hopefully doesn't exist"),
+ Deno.errors.NotFound,
+ );
+});
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnFailedWithCode() {
+ const { status } = await Deno.spawn(Deno.execPath(), {
+ args: ["eval", "Deno.exit(41 + 1)"],
+ });
+ assertEquals(status.success, false);
+ assertEquals(status.code, 42);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncFailedWithCode() {
+ const { status } = Deno.spawnSync(Deno.execPath(), {
+ args: ["eval", "Deno.exit(41 + 1)"],
+ });
+ assertEquals(status.success, false);
+ assertEquals(status.code, 42);
+ assertEquals(status.signal, null);
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ },
+ async function spawnFailedWithSignal() {
+ const { status } = await Deno.spawn(Deno.execPath(), {
+ args: ["eval", "--unstable", "Deno.kill(Deno.pid, 'SIGKILL')"],
+ });
+ assertEquals(status.success, false);
+ if (Deno.build.os === "windows") {
+ assertEquals(status.code, 1);
+ assertEquals(status.signal, null);
+ } else {
+ assertEquals(status.code, 128 + 9);
+ assertEquals(status.signal, 9);
+ }
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ },
+ function spawnSyncFailedWithSignal() {
+ const { status } = Deno.spawnSync(Deno.execPath(), {
+ args: ["eval", "--unstable", "Deno.kill(Deno.pid, 'SIGKILL')"],
+ });
+ assertEquals(status.success, false);
+ if (Deno.build.os === "windows") {
+ assertEquals(status.code, 1);
+ assertEquals(status.signal, null);
+ } else {
+ assertEquals(status.code, 128 + 9);
+ assertEquals(status.signal, 9);
+ }
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnOutput() {
+ const { stdout } = await Deno.spawn(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stdout.write(new TextEncoder().encode('hello'))",
+ ],
+ });
+
+ const s = new TextDecoder().decode(stdout);
+ assertEquals(s, "hello");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncOutput() {
+ const { stdout } = Deno.spawnSync(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stdout.write(new TextEncoder().encode('hello'))",
+ ],
+ });
+
+ const s = new TextDecoder().decode(stdout);
+ assertEquals(s, "hello");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnStderrOutput() {
+ const { stderr } = await Deno.spawn(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stderr.write(new TextEncoder().encode('error'))",
+ ],
+ });
+
+ const s = new TextDecoder().decode(stderr);
+ assertEquals(s, "error");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncStderrOutput() {
+ const { stderr } = Deno.spawnSync(Deno.execPath(), {
+ args: [
+ "eval",
+ "await Deno.stderr.write(new TextEncoder().encode('error'))",
+ ],
+ });
+
+ const s = new TextDecoder().decode(stderr);
+ assertEquals(s, "error");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnOverrideStdio() {
+ const { stdout, stderr } = await Deno.spawn(Deno.execPath(), {
+ args: [
+ "eval",
+ "console.log('hello'); console.error('world')",
+ ],
+ stdin: "piped",
+ stdout: "null",
+ stderr: "null",
+ });
+
+ // @ts-ignore: for testing
+ assertEquals(new TextDecoder().decode(stdout), "hello\n");
+ // @ts-ignore: for testing
+ assertEquals(new TextDecoder().decode(stderr), "world\n");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnSyncOverrideStdio() {
+ const { stdout, stderr } = Deno.spawnSync(Deno.execPath(), {
+ args: [
+ "eval",
+ "console.log('hello'); console.error('world')",
+ ],
+ stdin: "piped",
+ stdout: "null",
+ stderr: "null",
+ });
+
+ // @ts-ignore: for testing
+ assertEquals(new TextDecoder().decode(stdout), "hello\n");
+ // @ts-ignore: for testing
+ assertEquals(new TextDecoder().decode(stderr), "world\n");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ async function spawnEnv() {
+ const { stdout } = await Deno.spawn(Deno.execPath(), {
+ args: [
+ "eval",
+ "Deno.stdout.write(new TextEncoder().encode(Deno.env.get('FOO') + Deno.env.get('BAR')))",
+ ],
+ env: {
+ FOO: "0123",
+ BAR: "4567",
+ },
+ });
+ const s = new TextDecoder().decode(stdout);
+ assertEquals(s, "01234567");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true } },
+ function spawnEnv() {
+ const { stdout } = Deno.spawnSync(Deno.execPath(), {
+ args: [
+ "eval",
+ "Deno.stdout.write(new TextEncoder().encode(Deno.env.get('FOO') + Deno.env.get('BAR')))",
+ ],
+ env: {
+ FOO: "0123",
+ BAR: "4567",
+ },
+ });
+ const s = new TextDecoder().decode(stdout);
+ assertEquals(s, "01234567");
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true, env: true } },
+ async function spawnClearEnv() {
+ const { stdout } = await Deno.spawn(Deno.execPath(), {
+ args: [
+ "eval",
+ "-p",
+ "JSON.stringify(Deno.env.toObject())",
+ ],
+ clearEnv: true,
+ env: {
+ FOO: "23147",
+ },
+ });
+
+ const obj = JSON.parse(new TextDecoder().decode(stdout));
+
+ // can't check for object equality because the OS may set additional env
+ // vars for processes, so we check if PATH isn't present as that is a common
+ // env var across OS's and isn't set for processes.
+ assertEquals(obj.FOO, "23147");
+ assert(!("PATH" in obj));
+ },
+);
+
+Deno.test(
+ { permissions: { run: true, read: true, env: true } },
+ function spawnSyncClearEnv() {
+ const { stdout } = Deno.spawnSync(Deno.execPath(), {
+ args: [
+ "eval",
+ "-p",
+ "JSON.stringify(Deno.env.toObject())",
+ ],
+ clearEnv: true,
+ env: {
+ FOO: "23147",
+ },
+ });
+
+ const obj = JSON.parse(new TextDecoder().decode(stdout));
+
+ // can't check for object equality because the OS may set additional env
+ // vars for processes, so we check if PATH isn't present as that is a common
+ // env var across OS's and isn't set for processes.
+ assertEquals(obj.FOO, "23147");
+ assert(!("PATH" in obj));
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ ignore: Deno.build.os === "windows",
+ },
+ async function spawnUid() {
+ const { stdout } = await Deno.spawn("id", {
+ args: ["-u"],
+ });
+
+ const currentUid = new TextDecoder().decode(stdout);
+
+ if (currentUid !== "0") {
+ await assertRejects(async () => {
+ await Deno.spawn("echo", {
+ args: ["fhqwhgads"],
+ uid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ ignore: Deno.build.os === "windows",
+ },
+ function spawnSyncUid() {
+ const { stdout } = Deno.spawnSync("id", {
+ args: ["-u"],
+ });
+
+ const currentUid = new TextDecoder().decode(stdout);
+
+ if (currentUid !== "0") {
+ assertThrows(() => {
+ Deno.spawnSync("echo", {
+ args: ["fhqwhgads"],
+ uid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ ignore: Deno.build.os === "windows",
+ },
+ async function spawnGid() {
+ const { stdout } = await Deno.spawn("id", {
+ args: ["-g"],
+ });
+
+ const currentGid = new TextDecoder().decode(stdout);
+
+ if (currentGid !== "0") {
+ await assertRejects(async () => {
+ await Deno.spawn("echo", {
+ args: ["fhqwhgads"],
+ gid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
+
+Deno.test(
+ {
+ permissions: { run: true, read: true },
+ ignore: Deno.build.os === "windows",
+ },
+ function spawnSyncGid() {
+ const { stdout } = Deno.spawnSync("id", {
+ args: ["-g"],
+ });
+
+ const currentGid = new TextDecoder().decode(stdout);
+
+ if (currentGid !== "0") {
+ assertThrows(() => {
+ Deno.spawnSync("echo", {
+ args: ["fhqwhgads"],
+ gid: 0,
+ });
+ }, Deno.errors.PermissionDenied);
+ }
+ },
+);
diff --git a/cli/tests/unit/process_test.ts b/cli/tests/unit/process_test.ts
index e4e2cc3c5..5acb92226 100644
--- a/cli/tests/unit/process_test.ts
+++ b/cli/tests/unit/process_test.ts
@@ -557,8 +557,9 @@ Deno.test(
const obj = JSON.parse(new TextDecoder().decode(await p.output()));
- // can't check for object equality because the OS may set additional env vars for processes
- // so we check if PATH isn't present as that is a common env var across OS's and isn't set for processes.
+ // can't check for object equality because the OS may set additional env
+ // vars for processes, so we check if PATH isn't present as that is a common
+ // env var across OS's and isn't set for processes.
assertEquals(obj.FOO, "23147");
assert(!("PATH" in obj));