зеркало из https://github.com/mozilla/gecko-dev.git
237 строки
7.2 KiB
JavaScript
237 строки
7.2 KiB
JavaScript
"use strict";
|
|
|
|
/**
|
|
* Opens a number of tabs containing an out-of-process iframe.
|
|
*
|
|
* @param numTabs the number of tabs to open.
|
|
* @returns the browsing context of the iframe in the last tab opened.
|
|
*/
|
|
async function openTestTabs(numTabs) {
|
|
let iframeBC = null;
|
|
|
|
for (let count = 0; count < numTabs; count++) {
|
|
let tab = await BrowserTestUtils.openNewForegroundTab({
|
|
gBrowser,
|
|
url: "about:blank",
|
|
});
|
|
|
|
// If we load example.com in an injected subframe, we assume that this
|
|
// will load in its own subprocess, which we can then crash.
|
|
iframeBC = await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
|
|
let iframe = content.document.createElement("iframe");
|
|
iframe.setAttribute("src", "http://example.com");
|
|
|
|
content.document.body.appendChild(iframe);
|
|
await ContentTaskUtils.waitForEvent(iframe, "load");
|
|
return iframe.frameLoader.browsingContext;
|
|
});
|
|
}
|
|
|
|
return iframeBC;
|
|
}
|
|
|
|
/**
|
|
* Helper function for testing frame crashing. Some tabs are opened
|
|
* containing frames from example.com and then the process for
|
|
* example.com is crashed. Notifications should apply to each tab
|
|
* and all should close when one of the notifications is closed.
|
|
*
|
|
* @param numTabs the number of tabs to open.
|
|
*/
|
|
async function testFrameCrash(numTabs) {
|
|
let iframeBC = await openTestTabs(numTabs);
|
|
let browser = gBrowser.selectedBrowser;
|
|
let rootBC = browser.browsingContext;
|
|
|
|
is(iframeBC.parent, rootBC, "oop frame has root as parent");
|
|
|
|
let eventFiredPromise = BrowserTestUtils.waitForEvent(
|
|
browser,
|
|
"oop-browser-crashed"
|
|
);
|
|
|
|
BrowserTestUtils.crashFrame(
|
|
browser,
|
|
true /* shouldShowTabCrashPage */,
|
|
true /* shouldClearMinidumps */,
|
|
iframeBC
|
|
);
|
|
|
|
let notificationPromise = BrowserTestUtils.waitForNotificationBar(
|
|
gBrowser,
|
|
browser,
|
|
"subframe-crashed"
|
|
);
|
|
|
|
info("Waiting for oop-browser-crashed event.");
|
|
await eventFiredPromise.then(event => {
|
|
ok(!event.isTopFrame, "should not be reporting top-level frame crash");
|
|
ok(event.childID != 0, "childID is non-zero");
|
|
|
|
isnot(
|
|
event.browsingContextId,
|
|
rootBC,
|
|
"top frame browsing context id not expected."
|
|
);
|
|
|
|
is(
|
|
event.browsingContextId,
|
|
iframeBC.id,
|
|
"oop frame browsing context id expected."
|
|
);
|
|
});
|
|
|
|
if (numTabs == 1) {
|
|
// The BrowsingContext is re-used, but the window global might still be
|
|
// getting set up at this point, so wait until it's been initialized.
|
|
let {
|
|
subject: windowGlobal,
|
|
} = await BrowserUtils.promiseObserved("window-global-created", wgp =>
|
|
wgp.documentURI.spec.startsWith("about:framecrashed")
|
|
);
|
|
|
|
is(
|
|
windowGlobal,
|
|
iframeBC.currentWindowGlobal,
|
|
"Resolved on expected window global"
|
|
);
|
|
|
|
let newIframeURI = await SpecialPowers.spawn(iframeBC, [], async () => {
|
|
return content.document.documentURI;
|
|
});
|
|
|
|
ok(
|
|
newIframeURI.startsWith("about:framecrashed"),
|
|
"The iframe is now pointing at about:framecrashed"
|
|
);
|
|
|
|
let title = await SpecialPowers.spawn(iframeBC, [], async () => {
|
|
await content.document.l10n.ready;
|
|
return content.document.documentElement.getAttribute("title");
|
|
});
|
|
ok(title, "The iframe has a non-empty tooltip.");
|
|
}
|
|
|
|
// Next, check that the crash notification bar has appeared.
|
|
await notificationPromise;
|
|
|
|
for (let count = 1; count <= numTabs; count++) {
|
|
let notificationBox = gBrowser.getNotificationBox(gBrowser.browsers[count]);
|
|
let notification = notificationBox.currentNotification;
|
|
ok(notification, "Notification " + count + " should be visible");
|
|
is(
|
|
notification.getAttribute("value"),
|
|
"subframe-crashed",
|
|
"Should be showing the right notification" + count
|
|
);
|
|
|
|
let buttons = notification.buttonContainer.querySelectorAll(
|
|
".notification-button"
|
|
);
|
|
is(
|
|
buttons.length,
|
|
1,
|
|
"Notification " + count + " should have only one button."
|
|
);
|
|
let links = notification.messageText.querySelectorAll(".text-link");
|
|
is(
|
|
links.length,
|
|
1,
|
|
"Notification " + count + " should have only one link."
|
|
);
|
|
let msgs = notification.messageText.querySelectorAll(
|
|
"span[data-l10n-id='crashed-subframe-message']"
|
|
);
|
|
is(msgs.length, 1, "Notification " + count + " should have one crash msg.");
|
|
}
|
|
|
|
// Press the ignore button on the visible notification.
|
|
let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
|
|
let notification = notificationBox.currentNotification;
|
|
|
|
// Make sure all of the notifications were closed when one of them was closed.
|
|
let closedPromises = [];
|
|
for (let count = 1; count <= numTabs; count++) {
|
|
let nb = gBrowser.getNotificationBox(gBrowser.browsers[count]);
|
|
closedPromises.push(
|
|
BrowserTestUtils.waitForMutationCondition(
|
|
nb.stack,
|
|
{ childList: true },
|
|
() => !nb.currentNotification
|
|
)
|
|
);
|
|
}
|
|
|
|
notification.dismiss();
|
|
await Promise.all(closedPromises);
|
|
|
|
for (let count = 1; count <= numTabs; count++) {
|
|
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* In this test, we crash an out-of-process iframe and
|
|
* verify that :
|
|
* 1. the "oop-browser-crashed" event is dispatched with
|
|
* the browsing context of the crashed oop subframe.
|
|
* 2. the crashed subframe is now pointing at "about:framecrashed"
|
|
* page.
|
|
*/
|
|
add_task(async function test_crashframe() {
|
|
// Open a new window with fission enabled.
|
|
ok(
|
|
SpecialPowers.useRemoteSubframes,
|
|
"This test only makes sense of we can use OOP iframes."
|
|
);
|
|
|
|
// Create the crash reporting directory if it doesn't yet exist, otherwise, a failure
|
|
// sometimes occurs. See bug 1687855 for fixing this.
|
|
const uAppDataPath = Services.dirsvc.get("UAppData", Ci.nsIFile).path;
|
|
let path = PathUtils.join(uAppDataPath, "Crash Reports", "pending");
|
|
await IOUtils.makeDirectory(path, { ignoreExisting: true });
|
|
|
|
// Test both one tab and when four tabs are opened.
|
|
await testFrameCrash(1);
|
|
await testFrameCrash(4);
|
|
});
|
|
|
|
// This test checks that no notification shows when there is no minidump available. It
|
|
// simulates the steps that occur during a crash, once with a dumpID and once without.
|
|
add_task(async function test_nominidump() {
|
|
for (let dumpID of [null, "8888"]) {
|
|
let iframeBC = await openTestTabs(1);
|
|
|
|
let childID = iframeBC.currentWindowGlobal.domProcess.childID;
|
|
|
|
gBrowser.selectedBrowser.dispatchEvent(
|
|
new FrameCrashedEvent("oop-browser-crashed", {
|
|
browsingContextID: iframeBC,
|
|
childID,
|
|
isTopFrame: false,
|
|
bubbles: true,
|
|
})
|
|
);
|
|
|
|
let bag = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
|
|
Ci.nsIWritablePropertyBag
|
|
);
|
|
bag.setProperty("abnormal", "true");
|
|
bag.setProperty("childID", iframeBC.currentWindowGlobal.domProcess.childID);
|
|
if (dumpID) {
|
|
bag.setProperty("dumpID", dumpID);
|
|
}
|
|
|
|
Services.obs.notifyObservers(bag, "ipc:content-shutdown");
|
|
|
|
let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
|
|
let notification = notificationBox.currentNotification;
|
|
ok(
|
|
dumpID ? notification : !notification,
|
|
"notification shown for browser with no minidump"
|
|
);
|
|
|
|
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
|
}
|
|
});
|