Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / dom / ipc / tests / browser_crash_oopiframe.js
blobedb91468b04260599ff265b27fe74c59fb75d9f4
1 "use strict";
3 /**
4  * Opens a number of tabs containing an out-of-process iframe.
5  *
6  * @param numTabs the number of tabs to open.
7  * @returns the browsing context of the iframe in the last tab opened.
8  */
9 async function openTestTabs(numTabs) {
10   let iframeBC = null;
12   for (let count = 0; count < numTabs; count++) {
13     let tab = await BrowserTestUtils.openNewForegroundTab({
14       gBrowser,
15       url: "about:blank",
16     });
18     // If we load example.com in an injected subframe, we assume that this
19     // will load in its own subprocess, which we can then crash.
20     iframeBC = await SpecialPowers.spawn(tab.linkedBrowser, [], async () => {
21       let iframe = content.document.createElement("iframe");
22       iframe.setAttribute("src", "http://example.com");
24       content.document.body.appendChild(iframe);
25       await ContentTaskUtils.waitForEvent(iframe, "load");
26       return iframe.frameLoader.browsingContext;
27     });
28   }
30   return iframeBC;
33 /**
34  * Helper function for testing frame crashing. Some tabs are opened
35  * containing frames from example.com and then the process for
36  * example.com is crashed. Notifications should apply to each tab
37  * and all should close when one of the notifications is closed.
38  *
39  * @param numTabs the number of tabs to open.
40  */
41 async function testFrameCrash(numTabs) {
42   let iframeBC = await openTestTabs(numTabs);
43   let browser = gBrowser.selectedBrowser;
44   let rootBC = browser.browsingContext;
46   is(iframeBC.parent, rootBC, "oop frame has root as parent");
48   let eventFiredPromise = BrowserTestUtils.waitForEvent(
49     browser,
50     "oop-browser-crashed"
51   );
53   BrowserTestUtils.crashFrame(
54     browser,
55     true /* shouldShowTabCrashPage */,
56     true /* shouldClearMinidumps */,
57     iframeBC
58   );
60   let notificationPromise = BrowserTestUtils.waitForNotificationBar(
61     gBrowser,
62     browser,
63     "subframe-crashed"
64   );
66   info("Waiting for oop-browser-crashed event.");
67   await eventFiredPromise.then(event => {
68     ok(!event.isTopFrame, "should not be reporting top-level frame crash");
69     ok(event.childID != 0, "childID is non-zero");
71     isnot(
72       event.browsingContextId,
73       rootBC,
74       "top frame browsing context id not expected."
75     );
77     is(
78       event.browsingContextId,
79       iframeBC.id,
80       "oop frame browsing context id expected."
81     );
82   });
84   if (numTabs == 1) {
85     // The BrowsingContext is re-used, but the window global might still be
86     // getting set up at this point, so wait until it's been initialized.
87     let { subject: windowGlobal } = await BrowserUtils.promiseObserved(
88       "window-global-created",
89       wgp => wgp.documentURI.spec.startsWith("about:framecrashed")
90     );
92     is(
93       windowGlobal,
94       iframeBC.currentWindowGlobal,
95       "Resolved on expected window global"
96     );
98     let newIframeURI = await SpecialPowers.spawn(iframeBC, [], async () => {
99       return content.document.documentURI;
100     });
102     ok(
103       newIframeURI.startsWith("about:framecrashed"),
104       "The iframe is now pointing at about:framecrashed"
105     );
107     let title = await SpecialPowers.spawn(iframeBC, [], async () => {
108       await content.document.l10n.ready;
109       return content.document.documentElement.getAttribute("title");
110     });
111     ok(title, "The iframe has a non-empty tooltip.");
112   }
114   // Next, check that the crash notification bar has appeared.
115   await notificationPromise;
117   for (let count = 1; count <= numTabs; count++) {
118     let notificationBox = gBrowser.getNotificationBox(gBrowser.browsers[count]);
119     let notification = notificationBox.currentNotification;
120     ok(notification, "Notification " + count + " should be visible");
121     is(
122       notification.getAttribute("value"),
123       "subframe-crashed",
124       "Should be showing the right notification" + count
125     );
127     let buttons = notification.buttonContainer.querySelectorAll(
128       ".notification-button"
129     );
130     is(
131       buttons.length,
132       1,
133       "Notification " + count + " should have only one button."
134     );
135     let links = notification.supportLinkEls;
136     is(
137       links.length,
138       1,
139       "Notification " + count + " should have only one link."
140     );
141     ok(
142       notification.messageText.textContent.length,
143       "Notification " + count + " should have a crash msg."
144     );
145   }
147   // Press the ignore button on the visible notification.
148   let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
149   let notification = notificationBox.currentNotification;
151   // Make sure all of the notifications were closed when one of them was closed.
152   let closedPromises = [];
153   for (let count = 1; count <= numTabs; count++) {
154     let nb = gBrowser.getNotificationBox(gBrowser.browsers[count]);
155     closedPromises.push(
156       BrowserTestUtils.waitForMutationCondition(
157         nb.stack,
158         { childList: true },
159         () => !nb.currentNotification
160       )
161     );
162   }
164   notification.dismiss();
165   await Promise.all(closedPromises);
167   for (let count = 1; count <= numTabs; count++) {
168     BrowserTestUtils.removeTab(gBrowser.selectedTab);
169   }
173  * In this test, we crash an out-of-process iframe and
174  * verify that :
175  *  1. the "oop-browser-crashed" event is dispatched with
176  *     the browsing context of the crashed oop subframe.
177  *  2. the crashed subframe is now pointing at "about:framecrashed"
178  *     page.
179  */
180 add_task(async function test_crashframe() {
181   // Open a new window with fission enabled.
182   ok(
183     SpecialPowers.useRemoteSubframes,
184     "This test only makes sense of we can use OOP iframes."
185   );
187   // Create the crash reporting directory if it doesn't yet exist, otherwise, a failure
188   // sometimes occurs. See bug 1687855 for fixing this.
189   const uAppDataPath = Services.dirsvc.get("UAppData", Ci.nsIFile).path;
190   let path = PathUtils.join(uAppDataPath, "Crash Reports", "pending");
191   await IOUtils.makeDirectory(path, { ignoreExisting: true });
193   // Test both one tab and when four tabs are opened.
194   await testFrameCrash(1);
195   await testFrameCrash(4);
198 // This test checks that no notification shows when there is no minidump available. It
199 // simulates the steps that occur during a crash, once with a dumpID and once without.
200 add_task(async function test_nominidump() {
201   for (let dumpID of [null, "8888"]) {
202     let iframeBC = await openTestTabs(1);
204     let childID = iframeBC.currentWindowGlobal.domProcess.childID;
206     let notificationPromise;
207     if (dumpID) {
208       notificationPromise = BrowserTestUtils.waitForNotificationBar(
209         gBrowser,
210         gBrowser.selectedBrowser,
211         "subframe-crashed"
212       );
213     }
215     gBrowser.selectedBrowser.dispatchEvent(
216       new FrameCrashedEvent("oop-browser-crashed", {
217         browsingContextID: iframeBC,
218         childID,
219         isTopFrame: false,
220         bubbles: true,
221       })
222     );
224     let bag = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
225       Ci.nsIWritablePropertyBag
226     );
227     bag.setProperty("abnormal", "true");
228     bag.setProperty("childID", iframeBC.currentWindowGlobal.domProcess.childID);
229     if (dumpID) {
230       bag.setProperty("dumpID", dumpID);
231     }
233     Services.obs.notifyObservers(bag, "ipc:content-shutdown");
235     await notificationPromise;
236     let notificationBox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
237     let notification = notificationBox.currentNotification;
238     ok(
239       dumpID ? notification : !notification,
240       "notification shown for browser with no minidump"
241     );
243     BrowserTestUtils.removeTab(gBrowser.selectedTab);
244   }