2019-01-21 14:03:30 -05:00
|
|
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
2019-06-21 19:00:14 -04:00
|
|
|
import {
|
|
|
|
test,
|
|
|
|
testPerm,
|
|
|
|
assert,
|
|
|
|
assertEquals,
|
|
|
|
assertStrContains
|
|
|
|
} from "./test_util.ts";
|
|
|
|
const {
|
|
|
|
kill,
|
|
|
|
run,
|
|
|
|
DenoError,
|
|
|
|
ErrorKind,
|
|
|
|
readFile,
|
|
|
|
open,
|
|
|
|
makeTempDir,
|
|
|
|
writeFile
|
|
|
|
} = Deno;
|
2018-11-15 23:07:40 -05:00
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
test(function runPermissions(): void {
|
2018-11-15 23:07:40 -05:00
|
|
|
let caughtError = false;
|
|
|
|
try {
|
2019-02-12 10:08:56 -05:00
|
|
|
Deno.run({ args: ["python", "-c", "print('hello world')"] });
|
2018-11-15 23:07:40 -05:00
|
|
|
} catch (e) {
|
|
|
|
caughtError = true;
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(e.kind, Deno.ErrorKind.PermissionDenied);
|
|
|
|
assertEquals(e.name, "PermissionDenied");
|
2018-11-15 23:07:40 -05:00
|
|
|
}
|
|
|
|
assert(caughtError);
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runSuccess(): Promise<void> {
|
2018-11-15 23:07:40 -05:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "print('hello world')"]
|
|
|
|
});
|
|
|
|
const status = await p.status();
|
|
|
|
console.log("status", status);
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, true);
|
|
|
|
assertEquals(status.code, 0);
|
|
|
|
assertEquals(status.signal, undefined);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runCommandFailedWithCode(): Promise<
|
|
|
|
void
|
|
|
|
> {
|
2018-11-15 23:07:40 -05:00
|
|
|
let p = run({
|
|
|
|
args: ["python", "-c", "import sys;sys.exit(41 + 1)"]
|
|
|
|
});
|
|
|
|
let status = await p.status();
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, false);
|
|
|
|
assertEquals(status.code, 42);
|
|
|
|
assertEquals(status.signal, undefined);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runCommandFailedWithSignal(): Promise<
|
|
|
|
void
|
|
|
|
> {
|
2019-03-06 16:54:58 -05:00
|
|
|
if (Deno.build.os === "win") {
|
2018-11-15 23:07:40 -05:00
|
|
|
return; // No signals on windows.
|
|
|
|
}
|
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import os;os.kill(os.getpid(), 9)"]
|
|
|
|
});
|
|
|
|
const status = await p.status();
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, false);
|
|
|
|
assertEquals(status.code, undefined);
|
|
|
|
assertEquals(status.signal, 9);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, function runNotFound(): void {
|
2018-11-15 23:07:40 -05:00
|
|
|
let error;
|
|
|
|
try {
|
|
|
|
run({ args: ["this file hopefully doesn't exist"] });
|
|
|
|
} catch (e) {
|
|
|
|
error = e;
|
|
|
|
}
|
|
|
|
assert(error !== undefined);
|
|
|
|
assert(error instanceof DenoError);
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(error.kind, ErrorKind.NotFound);
|
2018-11-15 23:07:40 -05:00
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm(
|
|
|
|
{ write: true, run: true },
|
|
|
|
async function runWithCwdIsAsync(): Promise<void> {
|
|
|
|
const enc = new TextEncoder();
|
2019-06-21 19:00:14 -04:00
|
|
|
const cwd = await makeTempDir({ prefix: "deno_command_test" });
|
2018-11-15 23:07:40 -05:00
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
const exitCodeFile = "deno_was_here";
|
|
|
|
const pyProgramFile = "poll_exit.py";
|
|
|
|
const pyProgram = `
|
2018-11-15 23:07:40 -05:00
|
|
|
from sys import exit
|
|
|
|
from time import sleep
|
|
|
|
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
with open("${exitCodeFile}", "r") as f:
|
|
|
|
line = f.readline()
|
|
|
|
code = int(line)
|
|
|
|
exit(code)
|
|
|
|
except IOError:
|
|
|
|
# Retry if we got here before deno wrote the file.
|
|
|
|
sleep(0.01)
|
|
|
|
pass
|
|
|
|
`;
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram));
|
|
|
|
const p = run({
|
|
|
|
cwd,
|
|
|
|
args: ["python", `${pyProgramFile}.py`]
|
|
|
|
});
|
|
|
|
|
|
|
|
// Write the expected exit code *after* starting python.
|
|
|
|
// This is how we verify that `run()` is actually asynchronous.
|
|
|
|
const code = 84;
|
|
|
|
Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
|
|
|
|
|
|
|
|
const status = await p.status();
|
|
|
|
assertEquals(status.success, false);
|
|
|
|
assertEquals(status.code, code);
|
|
|
|
assertEquals(status.signal, undefined);
|
|
|
|
p.close();
|
|
|
|
}
|
|
|
|
);
|
2018-11-15 23:07:40 -05:00
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runStdinPiped(): Promise<void> {
|
2018-11-15 23:07:40 -05:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"],
|
|
|
|
stdin: "piped"
|
|
|
|
});
|
|
|
|
assert(!p.stdout);
|
|
|
|
assert(!p.stderr);
|
|
|
|
|
|
|
|
let msg = new TextEncoder().encode("hello");
|
|
|
|
let n = await p.stdin.write(msg);
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(n, msg.byteLength);
|
2018-11-15 23:07:40 -05:00
|
|
|
|
|
|
|
p.stdin.close();
|
|
|
|
|
|
|
|
const status = await p.status();
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, true);
|
|
|
|
assertEquals(status.code, 0);
|
|
|
|
assertEquals(status.signal, undefined);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runStdoutPiped(): Promise<void> {
|
2018-11-15 23:07:40 -05:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; sys.stdout.write('hello')"],
|
|
|
|
stdout: "piped"
|
|
|
|
});
|
|
|
|
assert(!p.stdin);
|
|
|
|
assert(!p.stderr);
|
|
|
|
|
|
|
|
const data = new Uint8Array(10);
|
|
|
|
let r = await p.stdout.read(data);
|
2019-07-06 10:16:03 -04:00
|
|
|
if (r === Deno.EOF) {
|
|
|
|
throw new Error("p.stdout.read(...) should not be EOF");
|
|
|
|
}
|
|
|
|
assertEquals(r, 5);
|
|
|
|
const s = new TextDecoder().decode(data.subarray(0, r));
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(s, "hello");
|
2018-11-15 23:07:40 -05:00
|
|
|
r = await p.stdout.read(data);
|
2019-07-06 10:16:03 -04:00
|
|
|
assertEquals(r, Deno.EOF);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.stdout.close();
|
|
|
|
|
|
|
|
const status = await p.status();
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, true);
|
|
|
|
assertEquals(status.code, 0);
|
|
|
|
assertEquals(status.signal, undefined);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runStderrPiped(): Promise<void> {
|
2018-11-15 23:07:40 -05:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; sys.stderr.write('hello')"],
|
|
|
|
stderr: "piped"
|
|
|
|
});
|
|
|
|
assert(!p.stdin);
|
|
|
|
assert(!p.stdout);
|
|
|
|
|
|
|
|
const data = new Uint8Array(10);
|
|
|
|
let r = await p.stderr.read(data);
|
2019-07-06 10:16:03 -04:00
|
|
|
if (r === Deno.EOF) {
|
|
|
|
throw new Error("p.stderr.read should not return EOF here");
|
|
|
|
}
|
|
|
|
assertEquals(r, 5);
|
|
|
|
const s = new TextDecoder().decode(data.subarray(0, r));
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(s, "hello");
|
2018-11-15 23:07:40 -05:00
|
|
|
r = await p.stderr.read(data);
|
2019-07-06 10:16:03 -04:00
|
|
|
assertEquals(r, Deno.EOF);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.stderr.close();
|
|
|
|
|
|
|
|
const status = await p.status();
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(status.success, true);
|
|
|
|
assertEquals(status.code, 0);
|
|
|
|
assertEquals(status.signal, undefined);
|
2018-11-15 23:07:40 -05:00
|
|
|
p.close();
|
|
|
|
});
|
2018-11-30 13:44:05 -05:00
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runOutput(): Promise<void> {
|
2018-11-30 13:44:05 -05:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; sys.stdout.write('hello')"],
|
|
|
|
stdout: "piped"
|
|
|
|
});
|
|
|
|
const output = await p.output();
|
|
|
|
const s = new TextDecoder().decode(output);
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(s, "hello");
|
2018-11-30 13:44:05 -05:00
|
|
|
p.close();
|
|
|
|
});
|
2019-02-15 10:37:04 -05:00
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runStderrOutput(): Promise<void> {
|
2019-03-28 16:09:46 -04:00
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; sys.stderr.write('error')"],
|
|
|
|
stderr: "piped"
|
|
|
|
});
|
|
|
|
const error = await p.stderrOutput();
|
|
|
|
const s = new TextDecoder().decode(error);
|
|
|
|
assertEquals(s, "error");
|
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
|
2019-06-21 19:00:14 -04:00
|
|
|
testPerm(
|
|
|
|
{ run: true, write: true, read: true },
|
|
|
|
async function runRedirectStdoutStderr(): Promise<void> {
|
|
|
|
const tempDir = await makeTempDir();
|
|
|
|
const fileName = tempDir + "/redirected_stdio.txt";
|
|
|
|
const file = await open(fileName, "w");
|
|
|
|
|
|
|
|
const p = run({
|
|
|
|
args: [
|
|
|
|
"python",
|
|
|
|
"-c",
|
|
|
|
"import sys; sys.stderr.write('error\\n'); sys.stdout.write('output\\n');"
|
|
|
|
],
|
|
|
|
stdout: file.rid,
|
|
|
|
stderr: file.rid
|
|
|
|
});
|
|
|
|
|
|
|
|
await p.status();
|
|
|
|
p.close();
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
const fileContents = await readFile(fileName);
|
|
|
|
const decoder = new TextDecoder();
|
|
|
|
const text = decoder.decode(fileContents);
|
|
|
|
|
|
|
|
assertStrContains(text, "error");
|
|
|
|
assertStrContains(text, "output");
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
testPerm(
|
|
|
|
{ run: true, write: true, read: true },
|
|
|
|
async function runRedirectStdin(): Promise<void> {
|
|
|
|
const tempDir = await makeTempDir();
|
|
|
|
const fileName = tempDir + "/redirected_stdio.txt";
|
|
|
|
const encoder = new TextEncoder();
|
|
|
|
await writeFile(fileName, encoder.encode("hello"));
|
|
|
|
const file = await open(fileName, "r");
|
|
|
|
|
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "import sys; assert 'hello' == sys.stdin.read();"],
|
|
|
|
stdin: file.rid
|
|
|
|
});
|
|
|
|
|
|
|
|
const status = await p.status();
|
|
|
|
assertEquals(status.code, 0);
|
|
|
|
p.close();
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2019-04-21 16:40:10 -04:00
|
|
|
testPerm({ run: true }, async function runEnv(): Promise<void> {
|
2019-02-15 10:37:04 -05:00
|
|
|
const p = run({
|
|
|
|
args: [
|
|
|
|
"python",
|
|
|
|
"-c",
|
|
|
|
"import os, sys; sys.stdout.write(os.environ.get('FOO', '') + os.environ.get('BAR', ''))"
|
|
|
|
],
|
|
|
|
env: {
|
|
|
|
FOO: "0123",
|
|
|
|
BAR: "4567"
|
|
|
|
},
|
|
|
|
stdout: "piped"
|
|
|
|
});
|
|
|
|
const output = await p.output();
|
|
|
|
const s = new TextDecoder().decode(output);
|
2019-03-06 20:48:46 -05:00
|
|
|
assertEquals(s, "01234567");
|
2019-02-15 10:37:04 -05:00
|
|
|
p.close();
|
|
|
|
});
|
2019-04-21 21:26:56 -04:00
|
|
|
|
|
|
|
testPerm({ run: true }, async function runClose(): Promise<void> {
|
|
|
|
const p = run({
|
|
|
|
args: [
|
|
|
|
"python",
|
|
|
|
"-c",
|
|
|
|
"from time import sleep; import sys; sleep(10000); sys.stderr.write('error')"
|
|
|
|
],
|
|
|
|
stderr: "piped"
|
|
|
|
});
|
|
|
|
assert(!p.stdin);
|
|
|
|
assert(!p.stdout);
|
|
|
|
|
|
|
|
p.close();
|
|
|
|
|
|
|
|
const data = new Uint8Array(10);
|
|
|
|
let r = await p.stderr.read(data);
|
2019-07-06 10:16:03 -04:00
|
|
|
assertEquals(r, Deno.EOF);
|
2019-04-21 21:26:56 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
test(function signalNumbers(): void {
|
|
|
|
if (Deno.platform.os === "mac") {
|
|
|
|
assertEquals(Deno.Signal.SIGSTOP, 17);
|
|
|
|
} else if (Deno.platform.os === "linux") {
|
|
|
|
assertEquals(Deno.Signal.SIGSTOP, 19);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Ignore signal tests on windows for now...
|
|
|
|
if (Deno.platform.os !== "win") {
|
2019-08-06 01:45:36 -04:00
|
|
|
test(function killPermissions(): void {
|
|
|
|
let caughtError = false;
|
|
|
|
try {
|
|
|
|
// Unlike the other test cases, we don't have permission to spawn a
|
|
|
|
// subprocess we can safely kill. Instead we send SIGCONT to the current
|
|
|
|
// process - assuming that Deno does not have a special handler set for it
|
|
|
|
// and will just continue even if a signal is erroneously sent.
|
|
|
|
Deno.kill(Deno.pid, Deno.Signal.SIGCONT);
|
|
|
|
} catch (e) {
|
|
|
|
caughtError = true;
|
|
|
|
assertEquals(e.kind, Deno.ErrorKind.PermissionDenied);
|
|
|
|
assertEquals(e.name, "PermissionDenied");
|
|
|
|
}
|
|
|
|
assert(caughtError);
|
|
|
|
});
|
|
|
|
|
2019-04-21 21:26:56 -04:00
|
|
|
testPerm({ run: true }, async function killSuccess(): Promise<void> {
|
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "from time import sleep; sleep(10000)"]
|
|
|
|
});
|
|
|
|
|
|
|
|
assertEquals(Deno.Signal.SIGINT, 2);
|
|
|
|
kill(p.pid, Deno.Signal.SIGINT);
|
|
|
|
const status = await p.status();
|
|
|
|
|
|
|
|
assertEquals(status.success, false);
|
2019-04-28 17:16:37 -04:00
|
|
|
// TODO(ry) On Linux, status.code is sometimes undefined and sometimes 1.
|
|
|
|
// The following assert is causing this test to be flaky. Investigate and
|
|
|
|
// re-enable when it can be made deterministic.
|
|
|
|
// assertEquals(status.code, 1);
|
2019-04-30 13:43:00 -04:00
|
|
|
// assertEquals(status.signal, Deno.Signal.SIGINT);
|
2019-04-21 21:26:56 -04:00
|
|
|
});
|
|
|
|
|
|
|
|
testPerm({ run: true }, async function killFailed(): Promise<void> {
|
|
|
|
const p = run({
|
|
|
|
args: ["python", "-c", "from time import sleep; sleep(10000)"]
|
|
|
|
});
|
|
|
|
assert(!p.stdin);
|
|
|
|
assert(!p.stdout);
|
|
|
|
|
|
|
|
let err;
|
|
|
|
try {
|
|
|
|
kill(p.pid, 12345);
|
|
|
|
} catch (e) {
|
|
|
|
err = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!!err);
|
|
|
|
assertEquals(err.kind, Deno.ErrorKind.InvalidInput);
|
|
|
|
assertEquals(err.name, "InvalidInput");
|
|
|
|
|
|
|
|
p.close();
|
|
|
|
});
|
|
|
|
}
|