forked from mirrors/gecko-dev
This patch also checks for I/O errors when deleting leftover crashdump files in the test harness and reports them if the files couldn't be deleted. This won't prevent tests from leaking crash dumps if they're not written correctly, but it will make their presence visible and won't cause the harness to hang if it cannot delete them. MozReview-Commit-ID: FLvBJxEKkH5 --HG-- extra : rebase_source : 6a0242b670ceabc2307c5345b0ea7108857a10d2 extra : source : 95b1010395826d06cdc77cbf43faf7d8681504eb
249 lines
8.8 KiB
JavaScript
249 lines
8.8 KiB
JavaScript
/* global gBrowser */
|
|
Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
|
|
|
|
const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
|
|
|
|
var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
|
|
var gTestBrowser = null;
|
|
var config = {};
|
|
|
|
add_task(async function() {
|
|
// The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
|
|
// crash reports. This test needs them enabled. The test also needs a mock
|
|
// report server, and fortunately one is already set up by toolkit/
|
|
// crashreporter/test/Makefile.in. Assign its URL to MOZ_CRASHREPORTER_URL,
|
|
// which CrashSubmit.jsm uses as a server override.
|
|
let env = Components.classes["@mozilla.org/process/environment;1"]
|
|
.getService(Components.interfaces.nsIEnvironment);
|
|
let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT");
|
|
let serverUrl = env.get("MOZ_CRASHREPORTER_URL");
|
|
env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
|
|
env.set("MOZ_CRASHREPORTER_URL", SERVER_URL);
|
|
|
|
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
|
|
gTestBrowser = gBrowser.selectedBrowser;
|
|
|
|
// Crash immediately
|
|
Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 0);
|
|
|
|
registerCleanupFunction(async function() {
|
|
Services.prefs.clearUserPref("dom.ipc.plugins.timeoutSecs");
|
|
env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
|
|
env.set("MOZ_CRASHREPORTER_URL", serverUrl);
|
|
env = null;
|
|
config = null;
|
|
gTestBrowser = null;
|
|
gBrowser.removeCurrentTab();
|
|
window.focus();
|
|
});
|
|
});
|
|
|
|
add_task(async function() {
|
|
config = {
|
|
shouldSubmissionUIBeVisible: true,
|
|
comment: "",
|
|
urlOptIn: false
|
|
};
|
|
|
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
|
|
|
let pluginCrashed = promisePluginCrashed();
|
|
|
|
await promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
|
|
|
|
// Work around for delayed PluginBindingAttached
|
|
await promiseUpdatePluginBindings(gTestBrowser);
|
|
|
|
// Wait for the plugin to crash
|
|
await pluginCrashed;
|
|
|
|
let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
|
|
|
|
// Test that the crash submission UI is actually visible and submit the crash report.
|
|
await ContentTask.spawn(gTestBrowser, config, async function(aConfig) {
|
|
let doc = content.document;
|
|
let plugin = doc.getElementById("plugin");
|
|
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
|
let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
|
|
// Test that we don't send the URL when urlOptIn is false.
|
|
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
|
|
submitButton.click();
|
|
Assert.equal(content.getComputedStyle(pleaseSubmit).display == "block",
|
|
aConfig.shouldSubmissionUIBeVisible, "The crash UI should be visible");
|
|
});
|
|
|
|
await crashReportStatus;
|
|
});
|
|
|
|
add_task(async function() {
|
|
config = {
|
|
shouldSubmissionUIBeVisible: true,
|
|
comment: "a test comment",
|
|
urlOptIn: true
|
|
};
|
|
|
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
|
|
|
let pluginCrashed = promisePluginCrashed();
|
|
|
|
await promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html");
|
|
|
|
// Work around for delayed PluginBindingAttached
|
|
await promiseUpdatePluginBindings(gTestBrowser);
|
|
|
|
// Wait for the plugin to crash
|
|
await pluginCrashed;
|
|
|
|
let crashReportStatus = TestUtils.topicObserved("crash-report-status", onSubmitStatus);
|
|
|
|
// Test that the crash submission UI is actually visible and submit the crash report.
|
|
await ContentTask.spawn(gTestBrowser, config, async function(aConfig) {
|
|
let doc = content.document;
|
|
let plugin = doc.getElementById("plugin");
|
|
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
|
let submitButton = doc.getAnonymousElementByAttribute(plugin, "anonid", "submitButton");
|
|
// Test that we send the URL when urlOptIn is true.
|
|
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitURLOptIn").checked = aConfig.urlOptIn;
|
|
doc.getAnonymousElementByAttribute(plugin, "anonid", "submitComment").value = aConfig.comment;
|
|
submitButton.click();
|
|
Assert.equal(content.getComputedStyle(pleaseSubmit).display == "block",
|
|
aConfig.shouldSubmissionUIBeVisible, "The crash UI should be visible");
|
|
});
|
|
|
|
await crashReportStatus;
|
|
});
|
|
|
|
add_task(async function() {
|
|
config = {
|
|
shouldSubmissionUIBeVisible: false,
|
|
comment: "",
|
|
urlOptIn: true
|
|
};
|
|
|
|
// Deferred promise object used by the test to wait for the crash handler
|
|
let crashDeferred = PromiseUtils.defer();
|
|
|
|
// Clear out any minidumps we create from plugin crashes, this is needed
|
|
// because we do not submit the crash otherwise the submission process would
|
|
// have deleted the crash dump files for us.
|
|
let crashObserver = (subject, topic, data) => {
|
|
if (topic != "plugin-crashed") {
|
|
return;
|
|
}
|
|
|
|
let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
|
|
let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
|
|
|
|
Services.crashmanager.ensureCrashIsPresent(minidumpID).then(() => {
|
|
let dirSvc = Cc["@mozilla.org/file/directory_service;1"]
|
|
.getService(Ci.nsIProperties);
|
|
let minidumpDir = dirSvc.get("UAppData", Ci.nsIFile);
|
|
minidumpDir.append("Crash Reports");
|
|
minidumpDir.append("pending");
|
|
|
|
let pluginDumpFile = minidumpDir.clone();
|
|
pluginDumpFile.append(minidumpID + ".dmp");
|
|
|
|
let extraFile = minidumpDir.clone();
|
|
extraFile.append(minidumpID + ".extra");
|
|
|
|
pluginDumpFile.remove(false);
|
|
extraFile.remove(false);
|
|
crashDeferred.resolve();
|
|
});
|
|
};
|
|
|
|
Services.obs.addObserver(crashObserver, "plugin-crashed");
|
|
|
|
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
|
|
|
|
let pluginCrashed = promisePluginCrashed();
|
|
|
|
// Make sure that the plugin container is too small to display the crash submission UI
|
|
await promiseTabLoadEvent(gBrowser.selectedTab, gTestRoot + "plugin_crashCommentAndURL.html?" +
|
|
encodeURIComponent(JSON.stringify({width: 300, height: 300})));
|
|
|
|
// Work around for delayed PluginBindingAttached
|
|
await promiseUpdatePluginBindings(gTestBrowser);
|
|
|
|
// Wait for the plugin to crash
|
|
await pluginCrashed;
|
|
|
|
// Test that the crash submission UI is not visible and do not submit a crash report.
|
|
await ContentTask.spawn(gTestBrowser, config, async function(aConfig) {
|
|
let doc = content.document;
|
|
let plugin = doc.getElementById("plugin");
|
|
let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
|
|
Assert.equal(!!pleaseSubmit && content.getComputedStyle(pleaseSubmit).display == "block",
|
|
aConfig.shouldSubmissionUIBeVisible, "Plugin crash UI should not be visible");
|
|
});
|
|
|
|
await crashDeferred.promise;
|
|
Services.obs.removeObserver(crashObserver, "plugin-crashed");
|
|
});
|
|
|
|
function promisePluginCrashed() {
|
|
return new ContentTask.spawn(gTestBrowser, {}, async function() {
|
|
await new Promise((resolve) => {
|
|
addEventListener("PluginCrashReporterDisplayed", function onPluginCrashed() {
|
|
removeEventListener("PluginCrashReporterDisplayed", onPluginCrashed);
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function onSubmitStatus(aSubject, aData) {
|
|
if (aData === "submitting") {
|
|
return false;
|
|
}
|
|
|
|
is(aData, "success", "The crash report should be submitted successfully");
|
|
|
|
let propBag = aSubject.QueryInterface(Ci.nsIPropertyBag);
|
|
if (aData == "success") {
|
|
let remoteID = getPropertyBagValue(propBag, "serverCrashID");
|
|
ok(!!remoteID, "serverCrashID should be set");
|
|
|
|
// Remove the submitted report file.
|
|
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
|
file.initWithPath(Services.crashmanager._submittedDumpsDir);
|
|
file.append(remoteID + ".txt");
|
|
ok(file.exists(), "Submitted report file should exist");
|
|
file.remove(false);
|
|
}
|
|
|
|
let extra = getPropertyBagValue(propBag, "extra");
|
|
ok(extra instanceof Ci.nsIPropertyBag, "Extra data should be property bag");
|
|
|
|
let val = getPropertyBagValue(extra, "PluginUserComment");
|
|
if (config.comment) {
|
|
is(val, config.comment,
|
|
"Comment in extra data should match comment in textbox");
|
|
} else {
|
|
ok(val === undefined,
|
|
"Comment should be absent from extra data when textbox is empty");
|
|
}
|
|
|
|
val = getPropertyBagValue(extra, "PluginContentURL");
|
|
if (config.urlOptIn) {
|
|
is(val, gBrowser.currentURI.spec,
|
|
"URL in extra data should match browser URL when opt-in checked");
|
|
} else {
|
|
ok(val === undefined,
|
|
"URL should be absent from extra data when opt-in not checked");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
function getPropertyBagValue(bag, key) {
|
|
try {
|
|
var val = bag.getProperty(key);
|
|
} catch (e) {
|
|
if (e.result != Cr.NS_ERROR_FAILURE) {
|
|
throw e;
|
|
}
|
|
}
|
|
return val;
|
|
}
|