Bug 1119442 - hang ui tests. r=mconley
☠☠ backed out by 88dbb4b40940 ☠ ☠
authorJim Mathies <jmathies@mozilla.com>
Fri, 23 Oct 2015 14:39:23 -0500
changeset 304526 c7641c84643083baf7e43244420e846fc99207ba
parent 304525 88b02bfcc8c760175cade1ae211e49d0a21349a4
child 304527 cc0945ec65c682d140c9a6945fe623358817c935
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley
bugs1119442
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1119442 - hang ui tests. r=mconley
browser/modules/test/browser.ini
browser/modules/test/browser_ProcessHangNotifications.js
--- a/browser/modules/test/browser.ini
+++ b/browser/modules/test/browser.ini
@@ -1,13 +1,15 @@
 [DEFAULT]
 support-files =
   head.js
 
 [browser_BrowserUITelemetry_buckets.js]
+[browser_ProcessHangNotifications.js]
+skip-if = !e10s
 [browser_ContentSearch.js]
 skip-if = e10s
 support-files =
   contentSearch.js
   contentSearchBadImage.xml
   contentSearchSuggestions.sjs
   contentSearchSuggestions.xml
 [browser_NetworkPrioritizer.js]
new file mode 100644
--- /dev/null
+++ b/browser/modules/test/browser_ProcessHangNotifications.js
@@ -0,0 +1,185 @@
+
+Cu.import("resource://gre/modules/UpdateUtils.jsm");
+
+function getNotificationBox(aWindow) {
+  return aWindow.document.getElementById("high-priority-global-notificationbox");
+}
+
+function promiseNotificationShown(aWindow, aName) {
+  return new Promise((resolve) => {
+    let notification = getNotificationBox(aWindow);
+    notification.addEventListener("AlertActive", function active() {
+      notification.removeEventListener("AlertActive", active, true);
+      is(notification.allNotifications.length, 1, "Notification Displayed.");
+      resolve(notification);
+    });
+  });
+}
+
+function promiseReportCallMade(aValue) {
+  return new Promise((resolve) => {
+    let old = gTestHangReport.testCallback;
+    gTestHangReport.testCallback = function (val) {
+      gTestHangReport.testCallback = old;
+      is(aValue, val, "was the correct method call made on the hang report object?");
+      resolve();
+    };
+  });
+}
+
+function pushPrefs(...aPrefs) {
+  return new Promise((resolve) => {
+    SpecialPowers.pushPrefEnv({"set": aPrefs}, resolve);
+    resolve();
+  });
+}
+
+function popPrefs() {
+  return new Promise((resolve) => {
+    SpecialPowers.popPrefEnv(resolve);
+    resolve();
+  });
+}
+
+let gTestHangReport = {
+  SLOW_SCRIPT: 1,
+  PLUGIN_HANG: 2,
+
+  TEST_CALLBACK_CANCELED: 1,
+  TEST_CALLBACK_TERMSCRIPT: 2,
+  TEST_CALLBACK_TERMPLUGIN: 3,
+
+  _hangType: 1,
+  _tcb: function (aCallbackType) {},
+
+  get hangType() {
+    return this._hangType;
+  },
+
+  set hangType(aValue) {
+    this._hangType = aValue;
+  },
+
+  set testCallback(aValue) {
+    this._tcb = aValue;
+  },
+
+  QueryInterface: function (aIID) {
+    if (aIID.equals(Components.interfaces.nsIHangReport) ||
+        aIID.equals(Components.interfaces.nsISupports))
+      return this;
+    throw Components.results.NS_NOINTERFACE;
+  },
+
+  userCanceled: function () {
+    this._tcb(this.TEST_CALLBACK_CANCELED);
+  },
+
+  terminateScript: function () {
+    this._tcb(this.TEST_CALLBACK_TERMSCRIPT);
+  },
+
+  terminatePlugin: function () {
+    this._tcb(this.TEST_CALLBACK_TERMPLUGIN);
+  },
+
+  isReportForBrowser: function(aFrameLoader) {
+    return true;
+  }
+};
+
+// on dev edition we add a button for js debugging of hung scripts.
+let buttonCount = (UpdateUtils.UpdateChannel == "aurora" ? 3 : 2);
+
+/**
+ * Test if hang reports receive a terminate script callback when the user selects
+ * stop in response to a script hang.
+ */
+
+add_task(function* terminateScriptTest() {
+  let promise = promiseNotificationShown(window, "process-hang");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
+  let notification = yield promise;
+
+  let buttons = notification.currentNotification.getElementsByTagName("button");
+  is(buttons.length, buttonCount, "proper number of buttons");
+
+  // Click the "Stop It" button, we should get a terminate script callback
+  gTestHangReport.hangType = gTestHangReport.SLOW_SCRIPT;
+  promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMSCRIPT);
+  buttons[0].click();
+  yield promise;
+});
+
+/**
+ * Test if hang reports receive user canceled callbacks after a user selects wait
+ * and the browser frees up from a script hang on its own.
+ */
+
+add_task(function* waitForScriptTest() {
+  let promise = promiseNotificationShown(window, "process-hang");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
+  let notification = yield promise;
+
+  let buttons = notification.currentNotification.getElementsByTagName("button");
+  is(buttons.length, buttonCount, "proper number of buttons");
+
+  yield pushPrefs(["browser.hangNotification.waitPeriod", 1000],
+                  ["browser.hangNotification.expiration", 2000]);
+
+  function nocbcheck() {
+    ok(false, "received a callback?");
+  }
+  let oldcb = gTestHangReport.testCallback;
+  gTestHangReport.testCallback = nocbcheck;
+  // Click the "Wait" button this time, we shouldn't get a callback at all.
+  buttons[1].click();
+  gTestHangReport.testCallback = oldcb;
+
+  // send another hang pulse, we should not get a notification here
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
+  is(notification.currentNotification, null, "no notification should be visible");
+
+  // After selecting Wait, we should get a userCanceled callback after
+  // HANG_EXPIRATION_TIME.
+  yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
+
+  yield popPrefs();
+});
+
+/**
+ * Test if hang reports receive user canceled callbacks after the content
+ * process stops sending hang notifications.
+ */
+
+add_task(function* hangGoesAwayTest() {
+  yield pushPrefs(["browser.hangNotification.expiration", 1000]);
+
+  let promise = promiseNotificationShown(window, "process-hang");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
+  yield promise;
+
+  yield promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
+
+  yield popPrefs();
+});
+
+/**
+ * Tests if hang reports receive a terminate plugin callback when the user selects
+ * stop in response to a plugin hang.
+ */
+
+add_task(function* terminatePluginTest() {
+  let promise = promiseNotificationShown(window, "process-hang");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
+  let notification = yield promise;
+
+  let buttons = notification.currentNotification.getElementsByTagName("button");
+  is(buttons.length, buttonCount, "proper number of buttons");
+
+  // Click the "Stop It" button, we should get a terminate script callback
+  gTestHangReport.hangType = gTestHangReport.PLUGIN_HANG;
+  promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_TERMPLUGIN);
+  buttons[0].click();
+  yield promise;
+});