Bug 1298219 - Regression test. r?billm draft
authorMike Conley <mconley@mozilla.com>
Thu, 01 Sep 2016 13:10:37 -0400
changeset 410839 719e4ee0526db1a5bec871a2fbed1fca96178b1e
parent 410276 c4e6481055f2038232fa7b1cb50368c44a59f293
child 530611 3131ee19bb5803de083b9ebff54bc20bba184075
push id28770
push usermconley@mozilla.com
push dateWed, 07 Sep 2016 00:23:48 +0000
reviewersbillm
bugs1298219
milestone51.0a1
Bug 1298219 - Regression test. r?billm MozReview-Commit-ID: 5sDWL9NuTso
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_crash_previous_frameloader.js
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -15,16 +15,18 @@ support-files =
   file_multipleAudio.html
 [browser_bug295977_autoscroll_overflow.js]
 [browser_bug451286.js]
 skip-if = !e10s
 [browser_bug594509.js]
 [browser_bug982298.js]
 [browser_bug1198465.js]
 [browser_contentTitle.js]
+[browser_crash_previous_frameloader.js]
+run-if = e10s && crashreporter
 [browser_default_image_filename.js]
 [browser_f7_caret_browsing.js]
 [browser_findbar.js]
 [browser_label_textlink.js]
 [browser_isSynthetic.js]
 support-files =
   empty.png
 [browser_keyevents_during_autoscrolling.js]
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_crash_previous_frameloader.js
@@ -0,0 +1,114 @@
+"use strict";
+
+/**
+ * Cleans up the .dmp and .extra file from a crash.
+ *
+ * @param subject (nsISupports)
+ *        The subject passed through the ipc:content-shutdown
+ *        observer notification when a content process crash has
+ *        occurred.
+ */
+function cleanUpMinidump(subject) {
+  Assert.ok(subject instanceof Ci.nsIPropertyBag2,
+            "Subject needs to be a nsIPropertyBag2 to clean up properly");
+  let dumpID = subject.getPropertyAsAString("dumpID");
+
+  Assert.ok(dumpID, "There should be a dumpID");
+  if (dumpID) {
+    let dir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+    dir.append("minidumps");
+
+    let file = dir.clone();
+    file.append(dumpID + ".dmp");
+    file.remove(true);
+
+    file = dir.clone();
+    file.append(dumpID + ".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(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;
+  }
+
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com",
+  }, 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 TabParents
+    // 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.
+    yield ContentTask.spawn(browser, null, function() {
+      const Cu = Components.utils;
+      Cu.import("resource://gre/modules/ctypes.jsm");
+      Cu.import("resource://gre/modules/Timer.jsm");
+
+      let dies = function() {
+        privateNoteIntentionalCrash();
+        let zero = new ctypes.intptr_t(8);
+        let badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
+        badptr.contents
+      };
+
+      // Use a timeout to give the parent a little extra time
+      // to flip the remoteness of the browser. This has the
+      // potential to be a bit race-y, since in theory, the
+      // setTimeout could complete before the parent finishes
+      // the remoteness flip, which would mean we'd get the
+      // oop-browser-crashed event, and we'll fail here.
+      // Unfortunately, I can't find a way around that right
+      // now, since you cannot send a frameloader a message
+      // once its been replaced.
+      setTimeout(() => {
+        dump("\nEt tu, Brute?\n");
+        dies();
+      }, 0);
+    });
+
+    gBrowser.updateBrowserRemoteness(browser, false);
+    info("Waiting for content process to go away.");
+    let [subject, data] = yield contentProcessGone;
+
+    // If we don't clean up the minidump, the harness will
+    // complain.
+    cleanUpMinidump(subject);
+
+    info("Content process is gone!");
+    Assert.ok(!sawTabCrashed,
+              "Should not have seen the oop-browser-crashed event.");
+    browser.removeEventListener("oop-browser-crashed", onTabCrashed);
+  });
+});