forked from mirrors/gecko-dev
Despite having passed through test-verify cleanly, the crash test is still sometimes failing due to a dump not being generated. Increase it to one full second, to give the file dialog time to open. If this doesn't suffice we'll have to either add another flavor of promise in the test-only code, or disable the test entirely. Differential Revision: https://phabricator.services.mozilla.com/D192101
170 lines
5.4 KiB
JavaScript
170 lines
5.4 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
SimpleTest.requestCompleteLog();
|
|
|
|
// Wait until the child process with the given PID has indeed been terminated.
|
|
//
|
|
// Note that `checkUtilityExists`, and other functions deriving from the output
|
|
// of `ChromeUtils.requestProcInfo()`, do not suffice for this purpose! It is an
|
|
// attested failure mode that the file-dialog utility process has been removed
|
|
// from the proc-info list, but is still live with the file-picker dialog still
|
|
// displayed.
|
|
function untilChildProcessDead(pid) {
|
|
return utilityProcessTest().untilChildProcessDead(pid);
|
|
}
|
|
|
|
async function fileDialogProcessExists() {
|
|
return !!(await tryGetUtilityPid("windowsFileDialog"));
|
|
}
|
|
|
|
// Poll for the creation of a file dialog process.
|
|
function untilFileDialogProcessExists(options = { maxTime: 2000 }) {
|
|
// milliseconds
|
|
const maxTime = options.maxTime ?? 2000,
|
|
pollTime = options.pollTime ?? 100;
|
|
const count = maxTime / pollTime;
|
|
|
|
return TestUtils.waitForCondition(
|
|
() => tryGetUtilityPid("windowsFileDialog", { quiet: true }),
|
|
"waiting for file dialog process",
|
|
pollTime, // interval
|
|
count // maxTries
|
|
);
|
|
}
|
|
|
|
function openFileDialog() {
|
|
const process = (async () => {
|
|
await untilFileDialogProcessExists();
|
|
let pid = await tryGetUtilityPid("windowsFileDialog");
|
|
ok(pid, `pid should be acquired in openFileDialog::process (got ${pid})`);
|
|
// HACK: Wait briefly for the file dialog to open.
|
|
//
|
|
// If this is not done, we may attempt to crash the process while it's in
|
|
// the middle of creating and showing the file dialog window. There _should_
|
|
// be no problem with this, but `::MiniDumpWriteDump()` occasionally fails
|
|
// with mysterious errors (`ERROR_BAD_LENGTH`) if we crashed the process
|
|
// while that was happening, yielding no minidump and therefore a failing
|
|
// test.
|
|
//
|
|
// Use of an arbitrary timeout could presumably be avoided by setting a
|
|
// window hook for the file dialog being shown and `await`ing on that.
|
|
//
|
|
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
|
|
await new Promise(res => setTimeout(res, 1000));
|
|
return pid;
|
|
})();
|
|
|
|
const file = new Promise((resolve, reject) => {
|
|
info("Opening Windows file dialog");
|
|
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
|
fp.init(window, "Test: browser_utility_filepicker_crashed.js", fp.modeOpen);
|
|
fp.open(result => {
|
|
ok(
|
|
result == fp.returnCancel,
|
|
"filepicker should resolve to cancellation"
|
|
);
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
return { process, file };
|
|
}
|
|
|
|
add_setup(async function () {
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
// remote, no fallback
|
|
["widget.windows.utility_process_file_picker", 2],
|
|
],
|
|
});
|
|
});
|
|
|
|
function makeTask(description, Describe, action) {
|
|
let task = async function () {
|
|
if (await fileDialogProcessExists()) {
|
|
// If this test proceeds, it will probably cause whatever other test has a
|
|
// file dialog open to fail.
|
|
//
|
|
// (We shouldn't be running two such tests in parallel on the same Fx
|
|
// instance, but that's not obvious at this level.)
|
|
ok(false, "another test has a file dialog open; aborting");
|
|
return;
|
|
}
|
|
|
|
const { process, file } = openFileDialog();
|
|
const pid = await process;
|
|
const untilDead = untilChildProcessDead(pid);
|
|
|
|
info(Describe + " the file-dialog utility process");
|
|
await action();
|
|
|
|
// the file-picker's callback should have been promptly cancelled
|
|
const _before = Date.now();
|
|
await file;
|
|
const _after = Date.now();
|
|
const delta = _after - _before;
|
|
info(`file callback resolved after ${description} after ${delta}ms`);
|
|
|
|
// depending on the test configuration, this may take some time while
|
|
// cleanup occurs
|
|
await untilDead;
|
|
};
|
|
|
|
// give this task a legible name
|
|
Object.defineProperty(task, "name", {
|
|
value: "testFileDialogProcess-" + Describe.replace(" ", ""),
|
|
});
|
|
|
|
return task;
|
|
}
|
|
|
|
for (let [description, Describe, action] of [
|
|
["crash", "Crash", () => crashSomeUtilityActor("windowsFileDialog")],
|
|
[
|
|
"being killed",
|
|
"Kill",
|
|
() => cleanUtilityProcessShutdown("windowsFileDialog", true),
|
|
],
|
|
// Unfortunately, a controlled shutdown doesn't actually terminate the utility
|
|
// process; the file dialog remains open. (This is expected to be resolved with
|
|
// bug 1837008.)
|
|
/* [
|
|
"shutdown",
|
|
"Shut down",
|
|
() => cleanUtilityProcessShutdown("windowsFileDialog"),
|
|
] */
|
|
]) {
|
|
add_task(makeTask(description, Describe, action));
|
|
add_task(testCleanup);
|
|
}
|
|
|
|
async function testCleanup() {
|
|
const killFileDialogProcess = async () => {
|
|
if (await tryGetUtilityPid("windowsFileDialog", { quiet: true })) {
|
|
await cleanUtilityProcessShutdown("windowsFileDialog", true);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
// If a test failure occurred, the file dialog process may or may not already
|
|
// exist...
|
|
if (await killFileDialogProcess()) {
|
|
console.warn("File dialog process found and killed");
|
|
return;
|
|
}
|
|
|
|
// ... and if not, may or may not be pending creation.
|
|
info("Active file dialog process not found; waiting...");
|
|
try {
|
|
await untilFileDialogProcessExists({ maxTime: 1000 });
|
|
} catch (e) {
|
|
info("File dialog process not found during cleanup (as expected)");
|
|
return;
|
|
}
|
|
await killFileDialogProcess();
|
|
console.warn("Delayed file dialog process found and killed");
|
|
}
|