Bug 1333126: plugin crash tests now wait properly for crash handling; r?gsvelto draft
authorCarl Corcoran <carlco@gmail.com>
Fri, 18 Aug 2017 11:25:05 +0200
changeset 648863 8fde6f7b5d061a036ef0bbaefb30291e8729a0cf
parent 648855 a61eca4a65740e88d3ef642f758ec93711e104bf
child 726971 ef538a5d719fc20e0189716b368406d05b1054dd
push id74915
push userbmo:ccorcoran@mozilla.com
push dateFri, 18 Aug 2017 12:49:18 +0000
reviewersgsvelto
bugs1333126
milestone57.0a1
Bug 1333126: plugin crash tests now wait properly for crash handling; r?gsvelto MozReview-Commit-ID: 70AvBYhCKnE
browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js
browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js
--- a/browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js
+++ b/browser/base/content/test/plugins/browser_pluginCrashCommentAndURL.js
@@ -1,16 +1,19 @@
 Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
+Cu.import("resource://gre/modules/PromiseUtils.jsm");
 
 const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
 
 var gTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
 var gTestBrowser = null;
 var config = {};
 
+let gRegisteredCrashObserver = null;
+
 add_task(async function() {
   // The test harness sets MOZ_CRASHREPORTER_NO_REPORT, which disables plugin
   // crash reports.  This test needs them enabled.  The test also needs a mock
   // report server, and fortunately one is already set up by toolkit/
   // crashreporter/test/Makefile.in.  Assign its URL to MOZ_CRASHREPORTER_URL,
   // which CrashSubmit.jsm uses as a server override.
   let env = Components.classes["@mozilla.org/process/environment;1"]
                       .getService(Components.interfaces.nsIEnvironment);
@@ -22,16 +25,19 @@ add_task(async function() {
   gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
   gTestBrowser = gBrowser.selectedBrowser;
 
   // Crash immediately
   Services.prefs.setIntPref("dom.ipc.plugins.timeoutSecs", 0);
 
   registerCleanupFunction(async function() {
     Services.prefs.clearUserPref("dom.ipc.plugins.timeoutSecs");
+    if (gRegisteredCrashObserver !== null) {
+      Services.obs.removeObserver(gRegisteredCrashObserver, "plugin-crashed");
+    }
     env.set("MOZ_CRASHREPORTER_NO_REPORT", noReport);
     env.set("MOZ_CRASHREPORTER_URL", serverUrl);
     env = null;
     config = null;
     gTestBrowser = null;
     gBrowser.removeCurrentTab();
     window.focus();
   });
@@ -108,16 +114,35 @@ add_task(async function() {
     Assert.equal(content.getComputedStyle(pleaseSubmit).display == "block",
       aConfig.shouldSubmissionUIBeVisible, "The crash UI should be visible");
   });
 
   await crashReportStatus;
 });
 
 add_task(async function() {
+  // Since this test doesn't actually submit a crash report, we can't await
+  // on crashReportStatus. This ensures the crash handling mechanism is
+  // completely finished before exiting the test.
+  let crashObserverDeferred = PromiseUtils.defer();
+
+  gRegisteredCrashObserver = (subject, topic, data) => {
+    if (topic != "plugin-crashed") {
+      return;
+    }
+    let propBag = subject.QueryInterface(Ci.nsIPropertyBag2);
+    let minidumpID = propBag.getPropertyAsAString("pluginDumpID");
+
+    Services.crashmanager.ensureCrashIsPresent(minidumpID).then(() => {
+      crashObserverDeferred.resolve();
+    });
+  };
+
+  Services.obs.addObserver(gRegisteredCrashObserver, "plugin-crashed");
+
   config = {
     shouldSubmissionUIBeVisible: false,
     comment: "",
     urlOptIn: true
   };
 
   setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
 
@@ -136,16 +161,18 @@ add_task(async function() {
   // Test that the crash submission UI is not visible and do not submit a crash report.
   await ContentTask.spawn(gTestBrowser, config, async function(aConfig) {
     let doc = content.document;
     let plugin = doc.getElementById("plugin");
     let pleaseSubmit = doc.getAnonymousElementByAttribute(plugin, "anonid", "pleaseSubmit");
     Assert.equal(!!pleaseSubmit && content.getComputedStyle(pleaseSubmit).display == "block",
       aConfig.shouldSubmissionUIBeVisible, "Plugin crash UI should not be visible");
   });
+
+  await crashObserverDeferred.promise;
 });
 
 function promisePluginCrashed() {
   return new ContentTask.spawn(gTestBrowser, {}, async function() {
     await new Promise((resolve) => {
       addEventListener("PluginCrashReporterDisplayed", function onPluginCrashed() {
         removeEventListener("PluginCrashReporterDisplayed", onPluginCrashed);
         resolve();
--- a/browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js
+++ b/browser/base/content/test/plugins/browser_pluginCrashReportNonDeterminism.js
@@ -1,11 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
+Cu.import("resource://gre/modules/PromiseUtils.jsm");
+
 /**
  * With e10s, plugins must run in their own process. This means we have
  * three processes at a minimum when we're running a plugin:
  *
  * 1) The main browser, or "chrome" process
  * 2) The content process hosting the plugin instance
  * 3) The plugin process
  *
@@ -74,16 +76,19 @@ function preparePlugin(browser, pluginFa
     });
     return plugin.runID;
   }).then((runID) => {
     browser.messageManager.sendAsyncMessage("BrowserPlugins:Test:ClearCrashData");
     return runID;
   });
 }
 
+// Allows tests to ensure crash handling is completely finished before exiting.
+let crashObserverDeferred = PromiseUtils.defer();
+
 add_task(async function setup() {
   // Bypass click-to-play
   setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
 
   // Clear out any minidumps we create from plugins - we really don't care
   // about them.
   let crashObserver = (subject, topic, data) => {
     if (topic != "plugin-crashed") {
@@ -103,16 +108,20 @@ add_task(async function setup() {
       let extraFile = minidumpDir.clone();
       extraFile.append(minidumpID + ".extra");
 
       ok(pluginDumpFile.exists(), "Found minidump");
       ok(extraFile.exists(), "Found extra file");
 
       pluginDumpFile.remove(false);
       extraFile.remove(false);
+
+      // Resolve and replace the deferred object so the next test can wait on it
+      crashObserverDeferred.resolve();
+      crashObserverDeferred = PromiseUtils.defer();
     });
   };
 
   Services.obs.addObserver(crashObserver, "plugin-crashed");
   // plugins.testmode will make BrowserPlugins:Test:ClearCrashData work.
   Services.prefs.setBoolPref("plugins.testmode", true);
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("plugins.testmode");
@@ -178,16 +187,17 @@ add_task(async function testChromeHearsP
       cancelable: true,
     });
 
     plugin.dispatchEvent(event);
     Assert.equal(statusDiv.getAttribute("status"), "please",
       "Should have been showing crash report UI");
   });
   await BrowserTestUtils.closeWindow(win);
+  await crashObserverDeferred.promise;
 });
 
 /**
  * In this case, the content process hears about the crash first.
  */
 add_task(async function testContentHearsCrashFirst() {
   // Open a remote window so that we can run this test even if e10s is not
   // enabled by default.
@@ -248,9 +258,10 @@ add_task(async function testContentHears
                           .getAnonymousElementByAttribute(plugin, "anonid",
                                                           "submitStatus");
 
     Assert.equal(statusDiv.getAttribute("status"), "please",
       "Should have been showing crash report UI");
   });
 
   await BrowserTestUtils.closeWindow(win);
+  await crashObserverDeferred.promise;
 });