gecko-dev/toolkit/xre/test/test_launch_without_hang.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

261 строка
7.3 KiB
JavaScript
Исходник Обычный вид История

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// bug 1360493
// Launch the browser a number of times, testing startup hangs.
"use strict";
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
Bug 1514594: Part 3 - Change ChromeUtils.import API. *** Bug 1514594: Part 3a - Change ChromeUtils.import to return an exports object; not pollute global. r=mccr8 This changes the behavior of ChromeUtils.import() to return an exports object, rather than a module global, in all cases except when `null` is passed as a second argument, and changes the default behavior not to pollute the global scope with the module's exports. Thus, the following code written for the old model: ChromeUtils.import("resource://gre/modules/Services.jsm"); is approximately the same as the following, in the new model: var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); Since the two behaviors are mutually incompatible, this patch will land with a scripted rewrite to update all existing callers to use the new model rather than the old. *** Bug 1514594: Part 3b - Mass rewrite all JS code to use the new ChromeUtils.import API. rs=Gijs This was done using the followng script: https://bitbucket.org/kmaglione/m-c-rewrites/src/tip/processors/cu-import-exports.jsm *** Bug 1514594: Part 3c - Update ESLint plugin for ChromeUtils.import API changes. r=Standard8 Differential Revision: https://phabricator.services.mozilla.com/D16747 *** Bug 1514594: Part 3d - Remove/fix hundreds of duplicate imports from sync tests. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D16748 *** Bug 1514594: Part 3e - Remove no-op ChromeUtils.import() calls. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D16749 *** Bug 1514594: Part 3f.1 - Cleanup various test corner cases after mass rewrite. r=Gijs *** Bug 1514594: Part 3f.2 - Cleanup various non-test corner cases after mass rewrite. r=Gijs Differential Revision: https://phabricator.services.mozilla.com/D16750 --HG-- extra : rebase_source : 359574ee3064c90f33bf36c2ebe3159a24cc8895 extra : histedit_source : b93c8f42808b1599f9122d7842d2c0b3e656a594%2C64a3a4e3359dc889e2ab2b49461bab9e27fc10a7
2019-01-17 21:18:31 +03:00
const { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
const APP_TIMER_TIMEOUT_MS = 1000 * 15;
const TRY_COUNT = 50;
// Sets a group of environment variables, returning the old values.
// newVals AND return value is an array of { key: "", value: "" }
function setEnvironmentVariables(newVals) {
let oldVals = [];
let env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment
);
for (let i = 0; i < newVals.length; ++i) {
let key = newVals[i].key;
let value = newVals[i].value;
let oldObj = { key };
if (env.exists(key)) {
oldObj.value = env.get(key);
} else {
oldObj.value = null;
}
env.set(key, value);
oldVals.push(oldObj);
}
return oldVals;
}
function getFirefoxExecutableFilename() {
if (AppConstants.platform === "win") {
return AppConstants.MOZ_APP_NAME + ".exe";
}
return AppConstants.MOZ_APP_NAME;
}
// Returns a nsIFile to the firefox.exe executable file
function getFirefoxExecutableFile() {
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file = Services.dirsvc.get("GreBinD", Ci.nsIFile);
file.append(getFirefoxExecutableFilename());
return file;
}
// Takes an executable and arguments, and wraps it in a call to the system shell.
// Technique adapted from \toolkit\mozapps\update\tests\unit_service_updater\xpcshellUtilsAUS.js
// to avoid child process console output polluting the xpcshell log.
// returns { file: (nsIFile), args: [] }
function wrapLaunchInShell(file, args) {
let ret = {};
if (AppConstants.platform === "win") {
ret.file = Services.dirsvc.get("WinD", Ci.nsIFile);
ret.file.append("System32");
ret.file.append("cmd.exe");
ret.args = ["/D", "/Q", "/C", file.path].concat(args).concat([">nul"]);
} else {
ret.file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
ret.file.initWithPath("/usr/bin/env");
ret.args = [file.path].concat(args).concat(["> /dev/null"]);
}
Assert.ok(
ret.file.exists(),
"Executable file should exist: " + ret.file.path
);
return ret;
}
// Needed because process.kill() kills the console, not its child process, firefox.
function terminateFirefox(completion) {
let executableName = getFirefoxExecutableFilename();
let file;
let args;
if (AppConstants.platform === "win") {
file = Services.dirsvc.get("WinD", Ci.nsIFile);
file.append("System32");
file.append("taskkill.exe");
args = ["/F", "/IM", executableName];
} else {
file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath("/usr/bin/killall");
args = [executableName];
}
info("launching application: " + file.path);
info(" with args: " + args.join(" "));
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(file);
let processObserver = {
observe: function PO_observe(aSubject, aTopic, aData) {
info("topic: " + aTopic + ", process exitValue: " + process.exitValue);
Assert.equal(
process.exitValue,
0,
"Terminate firefox process exit value should be 0"
);
Assert.equal(
aTopic,
"process-finished",
"Terminate firefox observer topic should be process-finished"
);
if (completion) {
completion();
}
},
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
};
process.runAsync(args, args.length, processObserver);
info(" with pid: " + process.pid);
}
// Launches file with args asynchronously, failing if the process did not
// exit within timeoutMS milliseconds. If a timeout occurs, handler()
// is called.
function launchProcess(file, args, env, timeoutMS, handler, attemptCount) {
let state = {};
state.attempt = attemptCount;
state.processObserver = {
observe: function PO_observe(aSubject, aTopic, aData) {
if (!state.appTimer) {
// the app timer has been canceled; this process has timed out already so don't process further.
handler(false);
return;
}
info(
"topic: " + aTopic + ", process exitValue: " + state.process.exitValue
);
info("Restoring environment variables");
setEnvironmentVariables(state.oldEnv);
state.appTimer.cancel();
state.appTimer = null;
Assert.equal(
state.process.exitValue,
0,
"the application process exit value should be 0"
);
Assert.equal(
aTopic,
"process-finished",
"the application process observer topic should be process-finished"
);
handler(true);
},
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
};
// The timer callback to kill the process if it takes too long.
state.appTimerCallback = {
notify: function TC_notify(aTimer) {
state.appTimer = null;
info("Restoring environment variables");
setEnvironmentVariables(state.oldEnv);
if (state.process.isRunning) {
info("attempting to kill process");
// This will cause the shell process to exit as well, triggering our process observer.
terminateFirefox(function terminateFirefoxCompletion() {
Assert.ok(false, "Launch application timer expired");
});
}
},
QueryInterface: ChromeUtils.generateQI(["nsITimerCallback"]),
};
info("launching application: " + file.path);
info(" with args: " + args.join(" "));
info(" with environment: ");
for (let i = 0; i < env.length; ++i) {
info(" " + env[i].key + "=" + env[i].value);
}
state.process = Cc["@mozilla.org/process/util;1"].createInstance(
Ci.nsIProcess
);
state.process.init(file);
state.appTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
state.appTimer.initWithCallback(
state.appTimerCallback,
timeoutMS,
Ci.nsITimer.TYPE_ONE_SHOT
);
state.oldEnv = setEnvironmentVariables(env);
state.process.runAsync(args, args.length, state.processObserver);
info(" with pid: " + state.process.pid);
}
function run_test() {
do_test_pending();
let env = [
{ key: "MOZ_CRASHREPORTER_DISABLE", value: null },
{ key: "MOZ_CRASHREPORTER", value: "1" },
{ key: "MOZ_CRASHREPORTER_NO_REPORT", value: "1" },
{ key: "MOZ_CRASHREPORTER_SHUTDOWN", value: "1" },
{ key: "XPCOM_DEBUG_BREAK", value: "stack-and-abort" },
];
let triesStarted = 1;
let handler = function launchFirefoxHandler(okToContinue) {
triesStarted++;
if (triesStarted <= TRY_COUNT && okToContinue) {
testTry();
} else {
do_test_finished();
}
};
let testTry = function testTry() {
let shell = wrapLaunchInShell(getFirefoxExecutableFile(), [
"-no-remote",
"-test-launch-without-hang",
]);
info("Try attempt #" + triesStarted);
launchProcess(
shell.file,
shell.args,
env,
APP_TIMER_TIMEOUT_MS,
handler,
triesStarted
);
};
testTry();
}