mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-08 00:38:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
5
toolkit/modules/subprocess/test/xpcshell/.eslintrc.js
Normal file
5
toolkit/modules/subprocess/test/xpcshell/.eslintrc.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = { // eslint-disable-line no-undef
|
||||
"extends": "../../../../../testing/xpcshell/xpcshell.eslintrc.js",
|
||||
};
|
||||
55
toolkit/modules/subprocess/test/xpcshell/data_test_script.py
Normal file
55
toolkit/modules/subprocess/test/xpcshell/data_test_script.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python2
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def output(line):
|
||||
sys.stdout.write(struct.pack('@I', len(line)))
|
||||
sys.stdout.write(line)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def echo_loop():
|
||||
while True:
|
||||
line = sys.stdin.readline()
|
||||
if not line:
|
||||
break
|
||||
|
||||
output(line)
|
||||
|
||||
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
|
||||
|
||||
|
||||
cmd = sys.argv[1]
|
||||
if cmd == 'echo':
|
||||
echo_loop()
|
||||
elif cmd == 'exit':
|
||||
sys.exit(int(sys.argv[2]))
|
||||
elif cmd == 'env':
|
||||
for var in sys.argv[2:]:
|
||||
output(os.environ.get(var, ''))
|
||||
elif cmd == 'pwd':
|
||||
output(os.path.abspath(os.curdir))
|
||||
elif cmd == 'print_args':
|
||||
for arg in sys.argv[2:]:
|
||||
output(arg)
|
||||
elif cmd == 'ignore_sigterm':
|
||||
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
||||
|
||||
output('Ready')
|
||||
while True:
|
||||
try:
|
||||
signal.pause()
|
||||
except AttributeError:
|
||||
import time
|
||||
time.sleep(3600)
|
||||
elif cmd == 'print':
|
||||
sys.stdout.write(sys.argv[2])
|
||||
sys.stderr.write(sys.argv[3])
|
||||
14
toolkit/modules/subprocess/test/xpcshell/head.js
Normal file
14
toolkit/modules/subprocess/test/xpcshell/head.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"use strict";
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
|
||||
"resource://gre/modules/AppConstants.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Subprocess",
|
||||
"resource://gre/modules/Subprocess.jsm");
|
||||
769
toolkit/modules/subprocess/test/xpcshell/test_subprocess.js
Normal file
769
toolkit/modules/subprocess/test/xpcshell/test_subprocess.js
Normal file
|
|
@ -0,0 +1,769 @@
|
|||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
|
||||
|
||||
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
const MAX_ROUND_TRIP_TIME_MS = AppConstants.DEBUG || AppConstants.ASAN ? 18 : 9;
|
||||
const MAX_RETRIES = 5;
|
||||
|
||||
let PYTHON;
|
||||
let PYTHON_BIN;
|
||||
let PYTHON_DIR;
|
||||
|
||||
const TEST_SCRIPT = do_get_file("data_test_script.py").path;
|
||||
|
||||
let read = pipe => {
|
||||
return pipe.readUint32().then(count => {
|
||||
return pipe.readString(count);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
let readAll = Task.async(function* (pipe) {
|
||||
let result = [];
|
||||
let string;
|
||||
while ((string = yield pipe.readString())) {
|
||||
result.push(string);
|
||||
}
|
||||
|
||||
return result.join("");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* setup() {
|
||||
PYTHON = yield Subprocess.pathSearch(env.get("PYTHON"));
|
||||
|
||||
PYTHON_BIN = OS.Path.basename(PYTHON);
|
||||
PYTHON_DIR = OS.Path.dirname(PYTHON);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_io() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
Assert.throws(() => { proc.stdout.read(-1); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.read(1.1); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.read(Infinity); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.read(NaN); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.readString(-1); },
|
||||
/non-negative integer/);
|
||||
Assert.throws(() => { proc.stdout.readString(1.1); },
|
||||
/non-negative integer/);
|
||||
|
||||
Assert.throws(() => { proc.stdout.readJSON(-1); },
|
||||
/positive integer/);
|
||||
Assert.throws(() => { proc.stdout.readJSON(0); },
|
||||
/positive integer/);
|
||||
Assert.throws(() => { proc.stdout.readJSON(1.1); },
|
||||
/positive integer/);
|
||||
|
||||
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
|
||||
let outputPromise = read(proc.stdout);
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
let [output] = yield Promise.all([
|
||||
outputPromise,
|
||||
proc.stdin.write(LINE1),
|
||||
]);
|
||||
|
||||
equal(output, LINE1, "Got expected output");
|
||||
|
||||
|
||||
// Make sure it succeeds whether the write comes before or after the
|
||||
// read.
|
||||
let inputPromise = proc.stdin.write(LINE2);
|
||||
|
||||
yield new Promise(resolve => setTimeout(resolve, 100));
|
||||
|
||||
[output] = yield Promise.all([
|
||||
read(proc.stdout),
|
||||
inputPromise,
|
||||
]);
|
||||
|
||||
equal(output, LINE2, "Got expected output");
|
||||
|
||||
|
||||
let JSON_BLOB = {foo: {bar: "baz"}};
|
||||
|
||||
inputPromise = proc.stdin.write(JSON.stringify(JSON_BLOB) + "\n");
|
||||
|
||||
output = yield proc.stdout.readUint32().then(count => {
|
||||
return proc.stdout.readJSON(count);
|
||||
});
|
||||
|
||||
Assert.deepEqual(output, JSON_BLOB, "Got expected JSON output");
|
||||
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_large_io() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
const BUFFER_SIZE = 4096;
|
||||
|
||||
// Create a message that's ~3/4 the input buffer size.
|
||||
let msg = Array(BUFFER_SIZE * .75 / 16 | 0).fill("0123456789abcdef").join("") + "\n";
|
||||
|
||||
// This sequence of writes and reads crosses several buffer size
|
||||
// boundaries, and causes some branches of the read buffer code to be
|
||||
// exercised which are not exercised by other tests.
|
||||
proc.stdin.write(msg);
|
||||
proc.stdin.write(msg);
|
||||
proc.stdin.write(LINE);
|
||||
|
||||
let output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
output = yield read(proc.stdout);
|
||||
equal(output, LINE, "Got the expected output");
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_huge() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// This should be large enough to fill most pipe input/output buffers.
|
||||
const MESSAGE_SIZE = 1024 * 16;
|
||||
|
||||
let msg = Array(MESSAGE_SIZE).fill("0123456789abcdef").join("") + "\n";
|
||||
|
||||
proc.stdin.write(msg);
|
||||
|
||||
let output = yield read(proc.stdout);
|
||||
equal(output, msg, "Got the expected output");
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_round_trip_perf() {
|
||||
let roundTripTime = Infinity;
|
||||
for (let i = 0; i < MAX_RETRIES && roundTripTime > MAX_ROUND_TRIP_TIME_MS; i++) {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
let now = Date.now();
|
||||
const COUNT = 1000;
|
||||
for (let j = 0; j < COUNT; j++) {
|
||||
let [output] = yield Promise.all([
|
||||
read(proc.stdout),
|
||||
proc.stdin.write(LINE),
|
||||
]);
|
||||
|
||||
// We don't want to log this for every iteration, but we still need
|
||||
// to fail if it goes wrong.
|
||||
if (output !== LINE) {
|
||||
equal(output, LINE, "Got expected output");
|
||||
}
|
||||
}
|
||||
|
||||
roundTripTime = (Date.now() - now) / COUNT;
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
}
|
||||
|
||||
ok(roundTripTime <= MAX_ROUND_TRIP_TIME_MS,
|
||||
`Expected round trip time (${roundTripTime}ms) to be less than ${MAX_ROUND_TRIP_TIME_MS}ms`);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_default() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
});
|
||||
|
||||
equal(proc.stderr, undefined, "There should be no stderr pipe by default");
|
||||
|
||||
let stdout = yield readAll(proc.stdout);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_pipe() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
let [stdout, stderr] = yield Promise.all([
|
||||
readAll(proc.stdout),
|
||||
readAll(proc.stderr),
|
||||
]);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
equal(stderr, LINE2, "Got the expected stderr output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_stderr_merged() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "stdout",
|
||||
});
|
||||
|
||||
equal(proc.stderr, undefined, "There should be no stderr pipe by default");
|
||||
|
||||
let stdout = yield readAll(proc.stdout);
|
||||
|
||||
equal(stdout, LINE1 + LINE2, "Got the expected merged stdout output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_read_after_exit() {
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print", LINE1, LINE2],
|
||||
stderr: "pipe",
|
||||
});
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
equal(exitCode, 0, "Process exited with expected code");
|
||||
|
||||
|
||||
let [stdout, stderr] = yield Promise.all([
|
||||
readAll(proc.stdout),
|
||||
readAll(proc.stderr),
|
||||
]);
|
||||
|
||||
equal(stdout, LINE1, "Got the expected stdout output");
|
||||
equal(stderr, LINE2, "Got the expected stderr output");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_lazy_close_output() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE1 = "I'm a leaf on the wind.\n";
|
||||
const LINE2 = "Watch how I soar.\n";
|
||||
|
||||
let writePromises = [
|
||||
proc.stdin.write(LINE1),
|
||||
proc.stdin.write(LINE2),
|
||||
];
|
||||
let closedPromise = proc.stdin.close();
|
||||
|
||||
|
||||
let output1 = yield read(proc.stdout);
|
||||
let output2 = yield read(proc.stdout);
|
||||
|
||||
yield Promise.all([...writePromises, closedPromise]);
|
||||
|
||||
equal(output1, LINE1, "Got expected output");
|
||||
equal(output2, LINE2, "Got expected output");
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_lazy_close_input() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
let closedPromise = proc.stdout.close();
|
||||
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
proc.stdin.write(LINE);
|
||||
proc.stdin.close();
|
||||
|
||||
let len = yield readPromise;
|
||||
equal(len, LINE.length);
|
||||
|
||||
yield closedPromise;
|
||||
|
||||
|
||||
// Don't test for a successful exit here. The process may exit with a
|
||||
// write error if we close the pipe after it's written the message
|
||||
// size but before it's written the message.
|
||||
yield proc.wait();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_force_close() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
let closedPromise = proc.stdout.close(true);
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_END_OF_FILE,
|
||||
"Got the expected error code");
|
||||
return /File closed/.test(e.message);
|
||||
},
|
||||
"Promise should be rejected when file is closed");
|
||||
|
||||
yield closedPromise;
|
||||
yield proc.stdin.close();
|
||||
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_eof() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
let readPromise = proc.stdout.readUint32();
|
||||
|
||||
yield proc.stdin.close();
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_END_OF_FILE,
|
||||
"Got the expected error code");
|
||||
return /File closed/.test(e.message);
|
||||
},
|
||||
"Promise should be rejected on EOF");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_invalid_json() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
const LINE = "I'm a leaf on the wind.\n";
|
||||
|
||||
proc.stdin.write(LINE);
|
||||
proc.stdin.close();
|
||||
|
||||
let count = yield proc.stdout.readUint32();
|
||||
let readPromise = proc.stdout.readJSON(count);
|
||||
|
||||
yield Assert.rejects(
|
||||
readPromise,
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_INVALID_JSON,
|
||||
"Got the expected error code");
|
||||
return /SyntaxError/.test(e);
|
||||
},
|
||||
"Promise should be rejected on EOF");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) {
|
||||
add_task(function* test_subprocess_inherited_descriptors() {
|
||||
let {ctypes, libc, win32} = Cu.import("resource://gre/modules/subprocess/subprocess_win.jsm");
|
||||
|
||||
let secAttr = new win32.SECURITY_ATTRIBUTES();
|
||||
secAttr.nLength = win32.SECURITY_ATTRIBUTES.size;
|
||||
secAttr.bInheritHandle = true;
|
||||
|
||||
let handles = win32.createPipe(secAttr, 0);
|
||||
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
|
||||
// Close the output end of the pipe.
|
||||
// Ours should be the only copy, so reads should fail after this.
|
||||
handles[1].dispose();
|
||||
|
||||
let buffer = new ArrayBuffer(1);
|
||||
let succeeded = libc.ReadFile(handles[0], buffer, buffer.byteLength,
|
||||
null, null);
|
||||
|
||||
ok(!succeeded, "ReadFile should fail on broken pipe");
|
||||
equal(ctypes.winLastError, win32.ERROR_BROKEN_PIPE, "Read should fail with ERROR_BROKEN_PIPE");
|
||||
|
||||
|
||||
proc.stdin.close();
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_subprocess_wait() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "exit", "42"],
|
||||
});
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 42, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_pathSearch() {
|
||||
let promise = Subprocess.call({
|
||||
command: PYTHON_BIN,
|
||||
arguments: ["-u", TEST_SCRIPT, "exit", "13"],
|
||||
environment: {
|
||||
PATH: PYTHON_DIR,
|
||||
},
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_workdir() {
|
||||
let procDir = yield OS.File.getCurrentDirectory();
|
||||
let tmpDirFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
tmpDirFile.initWithPath(OS.Constants.Path.tmpDir);
|
||||
tmpDirFile.normalize();
|
||||
let tmpDir = tmpDirFile.path;
|
||||
|
||||
notEqual(procDir, tmpDir,
|
||||
"Current process directory must not be the current temp directory");
|
||||
|
||||
function* pwd(options) {
|
||||
let proc = yield Subprocess.call(Object.assign({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "pwd"],
|
||||
}, options));
|
||||
|
||||
let pwdOutput = read(proc.stdout);
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
|
||||
return pwdOutput;
|
||||
}
|
||||
|
||||
let dir = yield pwd({});
|
||||
equal(dir, procDir, "Process should normally launch in current process directory");
|
||||
|
||||
dir = yield pwd({workdir: tmpDir});
|
||||
equal(dir, tmpDir, "Process should launch in the directory specified in `workdir`");
|
||||
|
||||
dir = yield OS.File.getCurrentDirectory();
|
||||
equal(dir, procDir, "`workdir` should not change the working directory of the current process");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_term() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// Windows does not support killing processes gracefully, so they will
|
||||
// always exit with -9 there.
|
||||
let retVal = AppConstants.platform == "win" ? -9 : -15;
|
||||
|
||||
// Kill gracefully with the default timeout of 300ms.
|
||||
let {exitCode} = yield proc.kill();
|
||||
|
||||
equal(exitCode, retVal, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, retVal, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_kill() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "echo"],
|
||||
});
|
||||
|
||||
// Force kill with no gracefull termination timeout.
|
||||
let {exitCode} = yield proc.kill(0);
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_kill_timeout() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "ignore_sigterm"],
|
||||
});
|
||||
|
||||
// Wait for the process to set up its signal handler and tell us it's
|
||||
// ready.
|
||||
let msg = yield read(proc.stdout);
|
||||
equal(msg, "Ready", "Process is ready");
|
||||
|
||||
// Kill gracefully with the default timeout of 300ms.
|
||||
// Expect a force kill after 300ms, since the process traps SIGTERM.
|
||||
const TIMEOUT = 300;
|
||||
let startTime = Date.now();
|
||||
|
||||
let {exitCode} = yield proc.kill(TIMEOUT);
|
||||
|
||||
// Graceful termination is not supported on Windows, so don't bother
|
||||
// testing the timeout there.
|
||||
if (AppConstants.platform != "win") {
|
||||
let diff = Date.now() - startTime;
|
||||
ok(diff >= TIMEOUT, `Process was killed after ${diff}ms (expected ~${TIMEOUT}ms)`);
|
||||
}
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, -9, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_subprocess_arguments() {
|
||||
let args = [
|
||||
String.raw`C:\Program Files\Company\Program.exe`,
|
||||
String.raw`\\NETWORK SHARE\Foo Directory${"\\"}`,
|
||||
String.raw`foo bar baz`,
|
||||
String.raw`"foo bar baz"`,
|
||||
String.raw`foo " bar`,
|
||||
String.raw`Thing \" with "" "\" \\\" \\\\" quotes\\" \\`,
|
||||
];
|
||||
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "print_args", ...args],
|
||||
});
|
||||
|
||||
for (let [i, arg] of args.entries()) {
|
||||
let val = yield read(proc.stdout);
|
||||
equal(val, arg, `Got correct value for args[${i}]`);
|
||||
}
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
// Windows XP can't handle launching Python with a partial environment.
|
||||
if (!AppConstants.isPlatformAndVersionAtMost("win", "5.2")) {
|
||||
add_task(function* test_subprocess_environment() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environment: {
|
||||
FOO: "BAR",
|
||||
},
|
||||
});
|
||||
|
||||
let path = yield read(proc.stdout);
|
||||
let foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, "", "Got expected $PATH value");
|
||||
equal(foo, "BAR", "Got expected $FOO value");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
add_task(function* test_subprocess_environmentAppend() {
|
||||
let proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environmentAppend: true,
|
||||
environment: {
|
||||
FOO: "BAR",
|
||||
},
|
||||
});
|
||||
|
||||
let path = yield read(proc.stdout);
|
||||
let foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, env.get("PATH"), "Got expected $PATH value");
|
||||
equal(foo, "BAR", "Got expected $FOO value");
|
||||
|
||||
let {exitCode} = yield proc.wait();
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
|
||||
proc = yield Subprocess.call({
|
||||
command: PYTHON,
|
||||
arguments: ["-u", TEST_SCRIPT, "env", "PATH", "FOO"],
|
||||
environmentAppend: true,
|
||||
});
|
||||
|
||||
path = yield read(proc.stdout);
|
||||
foo = yield read(proc.stdout);
|
||||
|
||||
equal(path, env.get("PATH"), "Got expected $PATH value");
|
||||
equal(foo, "", "Got expected $FOO value");
|
||||
|
||||
({exitCode} = yield proc.wait());
|
||||
|
||||
equal(exitCode, 0, "Got expected exit code");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_bad_executable() {
|
||||
// Test with a non-executable file.
|
||||
|
||||
let textFile = do_get_file("data_text_file.txt").path;
|
||||
|
||||
let promise = Subprocess.call({
|
||||
command: textFile,
|
||||
arguments: [],
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
if (AppConstants.platform == "win") {
|
||||
return /Failed to create process/.test(error.message);
|
||||
}
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
|
||||
// Test with a nonexistent file.
|
||||
promise = Subprocess.call({
|
||||
command: textFile + ".doesNotExist",
|
||||
arguments: [],
|
||||
});
|
||||
|
||||
yield Assert.rejects(
|
||||
promise,
|
||||
function(error) {
|
||||
return error.errorCode == Subprocess.ERROR_BAD_EXECUTABLE;
|
||||
},
|
||||
"Subprocess.call should fail for a bad executable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_cleanup() {
|
||||
let {SubprocessImpl} = Cu.import("resource://gre/modules/Subprocess.jsm");
|
||||
|
||||
let worker = SubprocessImpl.Process.getWorker();
|
||||
|
||||
let openFiles = yield worker.call("getOpenFiles", []);
|
||||
let processes = yield worker.call("getProcesses", []);
|
||||
|
||||
equal(openFiles.size, 0, "No remaining open files");
|
||||
equal(processes.size, 0, "No remaining processes");
|
||||
});
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
"use strict";
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
add_task(function* test_getEnvironment() {
|
||||
env.set("FOO", "BAR");
|
||||
|
||||
let environment = Subprocess.getEnvironment();
|
||||
|
||||
equal(environment.FOO, "BAR");
|
||||
equal(environment.PATH, env.get("PATH"));
|
||||
|
||||
env.set("FOO", null);
|
||||
|
||||
environment = Subprocess.getEnvironment();
|
||||
equal(environment.FOO || "", "");
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
"use strict";
|
||||
|
||||
let envService = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
|
||||
const PYTHON = envService.get("PYTHON");
|
||||
|
||||
const PYTHON_BIN = OS.Path.basename(PYTHON);
|
||||
const PYTHON_DIR = OS.Path.dirname(PYTHON);
|
||||
|
||||
const DOES_NOT_EXIST = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||
"ThisPathDoesNotExist");
|
||||
|
||||
const PATH_SEP = AppConstants.platform == "win" ? ";" : ":";
|
||||
|
||||
|
||||
add_task(function* test_pathSearchAbsolute() {
|
||||
let env = {};
|
||||
|
||||
let path = yield Subprocess.pathSearch(PYTHON, env);
|
||||
equal(path, PYTHON, "Full path resolves even with no PATH.");
|
||||
|
||||
env.PATH = "";
|
||||
path = yield Subprocess.pathSearch(PYTHON, env);
|
||||
equal(path, PYTHON, "Full path resolves even with empty PATH.");
|
||||
|
||||
yield Assert.rejects(
|
||||
Subprocess.pathSearch(DOES_NOT_EXIST, env),
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_BAD_EXECUTABLE,
|
||||
"Got the expected error code");
|
||||
return /File at path .* does not exist, or is not (executable|a normal file)/.test(e.message);
|
||||
},
|
||||
"Absolute path should throw for a nonexistent execuable");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_pathSearchRelative() {
|
||||
let env = {};
|
||||
|
||||
yield Assert.rejects(
|
||||
Subprocess.pathSearch(PYTHON_BIN, env),
|
||||
function(e) {
|
||||
equal(e.errorCode, Subprocess.ERROR_BAD_EXECUTABLE,
|
||||
"Got the expected error code");
|
||||
return /Executable not found:/.test(e.message);
|
||||
},
|
||||
"Relative path should not be found when PATH is missing");
|
||||
|
||||
env.PATH = [DOES_NOT_EXIST, PYTHON_DIR].join(PATH_SEP);
|
||||
|
||||
let path = yield Subprocess.pathSearch(PYTHON_BIN, env);
|
||||
equal(path, PYTHON, "Correct executable should be found in the path");
|
||||
});
|
||||
|
||||
|
||||
add_task({
|
||||
skip_if: () => AppConstants.platform != "win",
|
||||
}, function* test_pathSearch_PATHEXT() {
|
||||
ok(PYTHON_BIN.endsWith(".exe"), "Python executable must end with .exe");
|
||||
|
||||
const python_bin = PYTHON_BIN.slice(0, -4);
|
||||
|
||||
let env = {
|
||||
PATH: PYTHON_DIR,
|
||||
PATHEXT: [".com", ".exe", ".foobar"].join(";"),
|
||||
};
|
||||
|
||||
let path = yield Subprocess.pathSearch(python_bin, env);
|
||||
equal(path, PYTHON, "Correct executable should be found in the path, with guessed extension");
|
||||
});
|
||||
// IMPORTANT: Do not add any tests beyond this point without removing
|
||||
// the `skip_if` condition from the previous task, or it will prevent
|
||||
// all succeeding tasks from running when it does not match.
|
||||
14
toolkit/modules/subprocess/test/xpcshell/xpcshell.ini
Normal file
14
toolkit/modules/subprocess/test/xpcshell/xpcshell.ini
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[DEFAULT]
|
||||
head = head.js
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
skip-if = os == 'android'
|
||||
subprocess = true
|
||||
support-files =
|
||||
data_text_file.txt
|
||||
data_test_script.py
|
||||
|
||||
[test_subprocess.js]
|
||||
skip-if = os == 'win' # Path issues due to venv changes on the test machines
|
||||
[test_subprocess_getEnvironment.js]
|
||||
[test_subprocess_pathSearch.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue