mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1110511 - Move tab-crashing test helper function to BrowserTestUtils.jsm r=felipe
This commit is contained in:
parent
4859e86f4f
commit
1a329623c1
@ -69,7 +69,7 @@ add_task(function* test_crash() {
|
||||
// the content process. The "crash" message makes it first so that we don't
|
||||
// get a chance to process the flush. The TabStateFlusher however should be
|
||||
// notified so that the flush still completes.
|
||||
let promise1 = crashBrowser(browser);
|
||||
let promise1 = BrowserTestUtils.crashBrowser(browser);
|
||||
let promise2 = TabStateFlusher.flush(browser);
|
||||
yield Promise.all([promise1, promise2]);
|
||||
|
||||
|
@ -117,7 +117,7 @@ add_task(function test_crash_page_not_in_history() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
// Check the tab state and make sure the tab crashed page isn't
|
||||
// mentioned.
|
||||
@ -146,7 +146,7 @@ add_task(function test_revived_history_from_remote() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
// Browse to a new site that will cause the browser to
|
||||
// become remote again.
|
||||
@ -185,7 +185,7 @@ add_task(function test_revived_history_from_non_remote() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
// Browse to a new site that will not cause the browser to
|
||||
// become remote again.
|
||||
@ -235,7 +235,7 @@ add_task(function test_revive_tab_from_session_store() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
is(newTab2.getAttribute("crashed"), "true", "Second tab should be crashed too.");
|
||||
|
||||
// Use SessionStore to revive the tab
|
||||
@ -286,7 +286,7 @@ add_task(function test_revive_all_tabs_from_session_store() {
|
||||
yield TabStateFlusher.flush(browser2);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
is(newTab2.getAttribute("crashed"), "true", "Second tab should be crashed too.");
|
||||
|
||||
// Use SessionStore to revive all the tabs
|
||||
@ -331,7 +331,7 @@ add_task(function test_close_tab_after_crash() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
let promise = promiseEvent(gBrowser.tabContainer, "TabClose");
|
||||
|
||||
@ -359,7 +359,7 @@ add_task(function* test_hide_restore_all_button() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
let doc = browser.contentDocument;
|
||||
let restoreAllButton = doc.getElementById("restoreAll");
|
||||
@ -375,7 +375,7 @@ add_task(function* test_hide_restore_all_button() {
|
||||
yield promiseBrowserLoaded(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
doc = browser.contentDocument;
|
||||
restoreAllButton = doc.getElementById("restoreAll");
|
||||
@ -405,7 +405,7 @@ add_task(function* test_aboutcrashedtabzoom() {
|
||||
yield TabStateFlusher.flush(browser);
|
||||
|
||||
// Crash the tab
|
||||
yield crashBrowser(browser);
|
||||
yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
ok(ZoomManager.getZoomForBrowser(browser) === 1, "zoom should have reset on crash");
|
||||
|
||||
|
@ -538,112 +538,6 @@ function promiseRemoveTab(tab) {
|
||||
return BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves once a remote <xul:browser> has experienced
|
||||
* a crash. Also does the job of cleaning up the minidump of the crash.
|
||||
*
|
||||
* @param browser
|
||||
* The <xul:browser> that will crash
|
||||
* @return Promise
|
||||
*/
|
||||
function crashBrowser(browser) {
|
||||
/**
|
||||
* Returns the directory where crash dumps are stored.
|
||||
*
|
||||
* @return nsIFile
|
||||
*/
|
||||
function getMinidumpDirectory() {
|
||||
let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
|
||||
dir.append("minidumps");
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file from a directory. This is a no-op if the file does not
|
||||
* exist.
|
||||
*
|
||||
* @param directory
|
||||
* The nsIFile representing the directory to remove from.
|
||||
* @param filename
|
||||
* A string for the file to remove from the directory.
|
||||
*/
|
||||
function removeFile(directory, filename) {
|
||||
let file = directory.clone();
|
||||
file.append(filename);
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
// This frame script is injected into the remote browser, and used to
|
||||
// intentionally crash the tab. We crash by using js-ctypes and dereferencing
|
||||
// a bad pointer. The crash should happen immediately upon loading this
|
||||
// frame script.
|
||||
let frame_script = () => {
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
||||
let dies = function() {
|
||||
privateNoteIntentionalCrash();
|
||||
let zero = new ctypes.intptr_t(8);
|
||||
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
|
||||
badptr.contents
|
||||
};
|
||||
|
||||
dump("Et tu, Brute?");
|
||||
dies();
|
||||
}
|
||||
|
||||
let crashCleanupPromise = new Promise((resolve, reject) => {
|
||||
let observer = (subject, topic, data) => {
|
||||
is(topic, 'ipc:content-shutdown', 'Received correct observer topic.');
|
||||
ok(subject instanceof Ci.nsIPropertyBag2,
|
||||
'Subject implements nsIPropertyBag2.');
|
||||
// we might see this called as the process terminates due to previous tests.
|
||||
// We are only looking for "abnormal" exits...
|
||||
if (!subject.hasKey("abnormal")) {
|
||||
info("This is a normal termination and isn't the one we are looking for...");
|
||||
return;
|
||||
}
|
||||
|
||||
let dumpID;
|
||||
if ('nsICrashReporter' in Ci) {
|
||||
dumpID = subject.getPropertyAsAString('dumpID');
|
||||
ok(dumpID, "dumpID is present and not an empty string");
|
||||
}
|
||||
|
||||
if (dumpID) {
|
||||
let minidumpDirectory = getMinidumpDirectory();
|
||||
removeFile(minidumpDirectory, dumpID + '.dmp');
|
||||
removeFile(minidumpDirectory, dumpID + '.extra');
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(observer, 'ipc:content-shutdown');
|
||||
info("Crash cleaned up");
|
||||
resolve();
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, 'ipc:content-shutdown');
|
||||
});
|
||||
|
||||
let aboutTabCrashedLoadPromise = new Promise((resolve, reject) => {
|
||||
browser.addEventListener("AboutTabCrashedLoad", function onCrash() {
|
||||
browser.removeEventListener("AboutTabCrashedLoad", onCrash, false);
|
||||
info("about:tabcrashed loaded");
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
|
||||
// This frame script will crash the remote browser as soon as it is
|
||||
// evaluated.
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
|
||||
return Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]).then(() => {
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
is(tab.getAttribute("crashed"), "true", "Tab should be marked as crashed");
|
||||
});
|
||||
}
|
||||
|
||||
// Write DOMSessionStorage data to the given browser.
|
||||
function modifySessionStorage(browser, data, options = {}) {
|
||||
return ContentTask.spawn(browser, [data, options], function* ([data, options]) {
|
||||
|
@ -17,6 +17,7 @@ this.EXPORTED_SYMBOLS = [
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/AppConstants.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
@ -458,5 +459,147 @@ this.BrowserTestUtils = {
|
||||
tab.ownerDocument.defaultView.gBrowser.removeTab(tab);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Crashes a remote browser tab and cleans up the generated minidumps.
|
||||
* Resolves with the data from the .extra file (the crash annotations).
|
||||
*
|
||||
* @param (Browser) browser
|
||||
* A remote <xul:browser> element. Must not be null.
|
||||
*
|
||||
* @returns (Promise)
|
||||
* @resolves An Object with key-value pairs representing the data from the
|
||||
* crash report's extra file (if applicable).
|
||||
*/
|
||||
crashBrowser: Task.async(function*(browser) {
|
||||
let extra = {};
|
||||
let KeyValueParser = {};
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
Cu.import("resource://gre/modules/KeyValueParser.jsm", KeyValueParser);
|
||||
}
|
||||
|
||||
if (!browser.isRemoteBrowser) {
|
||||
throw new Error("<xul:browser> needs to be remote in order to crash");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory where crash dumps are stored.
|
||||
*
|
||||
* @return nsIFile
|
||||
*/
|
||||
function getMinidumpDirectory() {
|
||||
let dir = Services.dirsvc.get('ProfD', Ci.nsIFile);
|
||||
dir.append("minidumps");
|
||||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file from a directory. This is a no-op if the file does not
|
||||
* exist.
|
||||
*
|
||||
* @param directory
|
||||
* The nsIFile representing the directory to remove from.
|
||||
* @param filename
|
||||
* A string for the file to remove from the directory.
|
||||
*/
|
||||
function removeFile(directory, filename) {
|
||||
let file = directory.clone();
|
||||
file.append(filename);
|
||||
if (file.exists()) {
|
||||
file.remove(false);
|
||||
}
|
||||
}
|
||||
|
||||
// This frame script is injected into the remote browser, and used to
|
||||
// intentionally crash the tab. We crash by using js-ctypes and dereferencing
|
||||
// a bad pointer. The crash should happen immediately upon loading this
|
||||
// frame script.
|
||||
let frame_script = () => {
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
||||
let dies = function() {
|
||||
privateNoteIntentionalCrash();
|
||||
let zero = new ctypes.intptr_t(8);
|
||||
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
|
||||
badptr.contents
|
||||
};
|
||||
|
||||
dump("\nEt tu, Brute?\n");
|
||||
dies();
|
||||
}
|
||||
|
||||
let crashCleanupPromise = new Promise((resolve, reject) => {
|
||||
let observer = (subject, topic, data) => {
|
||||
if (topic != "ipc:content-shutdown") {
|
||||
return reject("Received incorrect observer topic: " + topic);
|
||||
}
|
||||
if (!(subject instanceof Ci.nsIPropertyBag2)) {
|
||||
return reject("Subject did not implement nsIPropertyBag2");
|
||||
}
|
||||
// we might see this called as the process terminates due to previous tests.
|
||||
// We are only looking for "abnormal" exits...
|
||||
if (!subject.hasKey("abnormal")) {
|
||||
dump("\nThis is a normal termination and isn't the one we are looking for...\n");
|
||||
return;
|
||||
}
|
||||
|
||||
let dumpID;
|
||||
if ('nsICrashReporter' in Ci) {
|
||||
dumpID = subject.getPropertyAsAString('dumpID');
|
||||
if (!dumpID) {
|
||||
return reject("dumpID was not present despite crash reporting " +
|
||||
"being enabled");
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpID) {
|
||||
let minidumpDirectory = getMinidumpDirectory();
|
||||
let extrafile = minidumpDirectory.clone();
|
||||
extrafile.append(dumpID + '.extra');
|
||||
if (extrafile.exists()) {
|
||||
dump(`\nNo .extra file for dumpID: ${dumpID}\n`);
|
||||
if (AppConstants.MOZ_CRASHREPORTER) {
|
||||
extra = KeyValueParser.parseKeyValuePairsFromFile(extrafile);
|
||||
} else {
|
||||
dump('\nCrashReporter not enabled - will not return any extra data\n');
|
||||
}
|
||||
}
|
||||
|
||||
removeFile(minidumpDirectory, dumpID + '.dmp');
|
||||
removeFile(minidumpDirectory, dumpID + '.extra');
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(observer, 'ipc:content-shutdown');
|
||||
dump("\nCrash cleaned up\n");
|
||||
resolve();
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, 'ipc:content-shutdown', false);
|
||||
});
|
||||
|
||||
let aboutTabCrashedLoadPromise = new Promise((resolve, reject) => {
|
||||
browser.addEventListener("AboutTabCrashedLoad", function onCrash() {
|
||||
browser.removeEventListener("AboutTabCrashedLoad", onCrash, false);
|
||||
dump("\nabout:tabcrashed loaded\n");
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
|
||||
// This frame script will crash the remote browser as soon as it is
|
||||
// evaluated.
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
|
||||
|
||||
yield Promise.all([crashCleanupPromise, aboutTabCrashedLoadPromise]);
|
||||
|
||||
let gBrowser = browser.ownerDocument.defaultView.gBrowser;
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
if (tab.getAttribute("crashed") != "true") {
|
||||
throw new Error("Tab should be marked as crashed");
|
||||
}
|
||||
|
||||
return extra;
|
||||
}),
|
||||
};
|
||||
|
@ -9,72 +9,6 @@
|
||||
// Running this test in ASAN is slow.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves once a remote <xul:browser> has experienced
|
||||
* a crash. Resolves with the data from the .extra file (the crash annotations).
|
||||
*
|
||||
* @param browser
|
||||
* The <xul:browser> that will crash
|
||||
* @return Promise
|
||||
*/
|
||||
function crashBrowser(browser) {
|
||||
let kv = {};
|
||||
Cu.import("resource://gre/modules/KeyValueParser.jsm", kv);
|
||||
// This frame script is injected into the remote browser, and used to
|
||||
// intentionally crash the tab. We crash by using js-ctypes and dereferencing
|
||||
// a bad pointer. The crash should happen immediately upon loading this
|
||||
// frame script.
|
||||
let frame_script = () => {
|
||||
const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/ctypes.jsm");
|
||||
|
||||
let dies = function() {
|
||||
privateNoteIntentionalCrash();
|
||||
let zero = new ctypes.intptr_t(8);
|
||||
let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
|
||||
let crash = badptr.contents;
|
||||
};
|
||||
|
||||
dump("Et tu, Brute?");
|
||||
dies();
|
||||
};
|
||||
|
||||
function checkSubject(subject, data) {
|
||||
return subject instanceof Ci.nsIPropertyBag2 &&
|
||||
subject.hasKey("abnormal");
|
||||
};
|
||||
let crashPromise = TestUtils.topicObserved('ipc:content-shutdown',
|
||||
checkSubject);
|
||||
let crashDataPromise = crashPromise.then(([subject, data]) => {
|
||||
ok(subject instanceof Ci.nsIPropertyBag2);
|
||||
|
||||
let dumpID;
|
||||
if ('nsICrashReporter' in Ci) {
|
||||
dumpID = subject.getPropertyAsAString('dumpID');
|
||||
ok(dumpID, "dumpID is present and not an empty string");
|
||||
}
|
||||
|
||||
let extra = null;
|
||||
if (dumpID) {
|
||||
let minidumpDirectory = getMinidumpDirectory();
|
||||
let extrafile = minidumpDirectory.clone();
|
||||
extrafile.append(dumpID + '.extra');
|
||||
ok(extrafile.exists(), 'found .extra file');
|
||||
extra = kv.parseKeyValuePairsFromFile(extrafile);
|
||||
removeFile(minidumpDirectory, dumpID + '.dmp');
|
||||
removeFile(minidumpDirectory, dumpID + '.extra');
|
||||
}
|
||||
|
||||
return extra;
|
||||
});
|
||||
|
||||
// This frame script will crash the remote browser as soon as it is
|
||||
// evaluated.
|
||||
let mm = browser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + frame_script.toString() + ")();", false);
|
||||
return crashDataPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file from a directory. This is a no-op if the file does not
|
||||
* exist.
|
||||
@ -130,7 +64,7 @@ add_task(function* test_content_url_annotation() {
|
||||
yield promise;
|
||||
|
||||
// Crash the tab
|
||||
let annotations = yield crashBrowser(browser);
|
||||
let annotations = yield BrowserTestUtils.crashBrowser(browser);
|
||||
|
||||
ok("URL" in annotations, "annotated a URL");
|
||||
is(annotations.URL, redirect_url,
|
||||
|
Loading…
Reference in New Issue
Block a user