summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser/browser_crash_previous_frameloader.js')
-rw-r--r--toolkit/content/tests/browser/browser_crash_previous_frameloader.js131
1 files changed, 131 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/browser_crash_previous_frameloader.js b/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
new file mode 100644
index 0000000000..0fa2f17912
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
@@ -0,0 +1,131 @@
+"use strict";
+
+/**
+ * Returns the id of the crash minidump.
+ *
+ * @param subject (nsISupports)
+ * The subject passed through the ipc:content-shutdown
+ * observer notification when a content process crash has
+ * occurred.
+ * @returns {String} The crash dump id.
+ */
+function getCrashDumpId(subject) {
+ Assert.ok(
+ subject instanceof Ci.nsIPropertyBag2,
+ "Subject needs to be a nsIPropertyBag2 to clean up properly"
+ );
+
+ return subject.getPropertyAsAString("dumpID");
+}
+
+/**
+ * Cleans up the .dmp and .extra file from a crash.
+ *
+ * @param id {String} The crash dump id.
+ */
+function cleanUpMinidump(id) {
+ let dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ dir.append("minidumps");
+
+ let file = dir.clone();
+ file.append(id + ".dmp");
+ file.remove(true);
+
+ file = dir.clone();
+ file.append(id + ".extra");
+ file.remove(true);
+}
+
+/**
+ * This test ensures that if a remote frameloader crashes after
+ * the frameloader owner swaps it out for a new frameloader,
+ * that a oop-browser-crashed event is not sent to the new
+ * frameloader's browser element.
+ */
+add_task(async function test_crash_in_previous_frameloader() {
+ // On debug builds, crashing tabs results in much thinking, which
+ // slows down the test and results in intermittent test timeouts,
+ // so we'll pump up the expected timeout for this test.
+ requestLongerTimeout(2);
+
+ if (!gMultiProcessBrowser) {
+ Assert.ok(false, "This test should only be run in multi-process mode.");
+ return;
+ }
+
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "http://example.com",
+ },
+ async function (browser) {
+ // First, sanity check...
+ Assert.ok(
+ browser.isRemoteBrowser,
+ "This browser needs to be remote if this test is going to " +
+ "work properly."
+ );
+
+ // We will wait for the oop-browser-crashed event to have
+ // a chance to appear. That event is fired when RemoteTabs
+ // are destroyed, and that occurs _before_ ContentParents
+ // are destroyed, so we'll wait on the ipc:content-shutdown
+ // observer notification, which is fired when a ContentParent
+ // goes away. After we see this notification, oop-browser-crashed
+ // events should have fired.
+ let contentProcessGone = TestUtils.topicObserved("ipc:content-shutdown");
+ let sawTabCrashed = false;
+ let onTabCrashed = () => {
+ sawTabCrashed = true;
+ };
+
+ browser.addEventListener("oop-browser-crashed", onTabCrashed);
+
+ // The name of the game is to cause a crash in a remote browser,
+ // and then immediately swap out the browser for a non-remote one.
+ await SpecialPowers.spawn(browser, [], function () {
+ const { ctypes } = ChromeUtils.importESModule(
+ "resource://gre/modules/ctypes.sys.mjs"
+ );
+
+ let dies = function () {
+ ChromeUtils.privateNoteIntentionalCrash();
+ let zero = new ctypes.intptr_t(8);
+ let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+ badptr.contents;
+ };
+
+ // When the parent flips the remoteness of the browser, the
+ // page should receive the pagehide event, which we'll then
+ // use to crash the frameloader.
+ docShell.chromeEventHandler.addEventListener("pagehide", function () {
+ dump("\nEt tu, Brute?\n");
+ dies();
+ });
+ });
+
+ gBrowser.updateBrowserRemoteness(browser, {
+ remoteType: E10SUtils.NOT_REMOTE,
+ });
+ info("Waiting for content process to go away.");
+ let [subject /* , data */] = await contentProcessGone;
+
+ // If we don't clean up the minidump, the harness will
+ // complain.
+ let dumpID = getCrashDumpId(subject);
+
+ Assert.ok(dumpID, "There should be a dumpID");
+ if (dumpID) {
+ await Services.crashmanager.ensureCrashIsPresent(dumpID);
+ cleanUpMinidump(dumpID);
+ }
+
+ info("Content process is gone!");
+ Assert.ok(
+ !sawTabCrashed,
+ "Should not have seen the oop-browser-crashed event."
+ );
+ browser.removeEventListener("oop-browser-crashed", onTabCrashed);
+ }
+ );
+});