Bug 1335272 - prep: factor out registering about: pages into BTU, r=jaws draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 02 Feb 2017 14:34:40 +0000
changeset 480053 0edc732e50ea3482d0cba0fd150ac4d0a07aaa82
parent 479917 6d27535f4fe912068e0a0ac5854f7f39e94964a5
child 480054 5498ab3e5d86f7025ab4e3e63e0dafd0ac964b74
push id44444
push usergijskruitbosch@gmail.com
push dateTue, 07 Feb 2017 19:46:28 +0000
reviewersjaws
bugs1335272
milestone54.0a1
Bug 1335272 - prep: factor out registering about: pages into BTU, r=jaws MozReview-Commit-ID: 2B2j5xcbSWt
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
browser/base/content/test/general/file_register_about_page.js
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js
testing/mochitest/jar.mn
testing/mochitest/tests/browser/browser.ini
testing/mochitest/tests/browser/browser_BrowserTestUtils.js
testing/mochitest/tests/browser/dummy.html
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -89,19 +89,16 @@ support-files =
   !/toolkit/mozapps/extensions/test/xpinstall/corrupt.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/incompatible.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
   !/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs
   !/toolkit/mozapps/extensions/test/xpinstall/restartless-unsigned.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/restartless.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/theme.xpi
   !/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs
-  file_about_child.html
-  file_about_parent.html
-  file_register_about_page.js
 
 [browser_aboutAccounts.js]
 skip-if = os == "linux" # Bug 958026
 support-files =
   content_aboutAccounts.js
 [browser_aboutCertError.js]
 [browser_aboutNetError.js]
 [browser_aboutSupport_newtab_security_state.js]
@@ -422,16 +419,19 @@ skip-if = true # Bug 1005420 - fails int
 skip-if = (os == "win" && !debug)
 [browser_web_channel.js]
 [browser_windowopen_reflows.js]
 [browser_zbug569342.js]
 skip-if = e10s || debug # Bug 1094240 - has findbar-related failures
 [browser_registerProtocolHandler_notification.js]
 [browser_addCertException.js]
 [browser_e10s_about_page_triggeringprincipal.js]
+support-files =
+  file_about_child.html
+  file_about_parent.html
 [browser_e10s_switchbrowser.js]
 [browser_e10s_about_process.js]
 [browser_e10s_chrome_process.js]
 [browser_e10s_javascript.js]
 [browser_blockHPKP.js]
 tags = psm
 [browser_windowactivation.js]
 [browser_contextmenu_childprocess.js]
--- a/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
+++ b/browser/base/content/test/general/browser_e10s_about_page_triggeringprincipal.js
@@ -1,26 +1,24 @@
 "use strict";
-Cu.import("resource://gre/modules/Services.jsm");
+
+const kChildPage = getRootDirectory(gTestPath) + "file_about_child.html";
+const kParentPage = getRootDirectory(gTestPath) + "file_about_parent.html";
 
-registerCleanupFunction(function() {
-  Services.ppmm.broadcastAsyncMessage("AboutPrincipalTest:Unregister");
-  BrowserTestUtils.waitForMessage(Services.ppmm, "AboutPrincipalTest:Unregistered").then(
-    Services.ppmm.removeDelayedProcessScript(
-      "chrome://mochitests/content/browser/browser/base/content/test/general/file_register_about_page.js"
-    )
-  );
-});
+const kAboutPagesRegistered = Promise.all([
+  BrowserTestUtils.registerAboutPage(
+    registerCleanupFunction, "test-about-principal-child", kChildPage,
+    Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD | Ci.nsIAboutModule.ALLOW_SCRIPT),
+  BrowserTestUtils.registerAboutPage(
+    registerCleanupFunction, "test-about-principal-parent", kParentPage,
+    Ci.nsIAboutModule.ALLOW_SCRIPT)
+]);
 
 add_task(function* test_principal_click() {
-  Services.ppmm.loadProcessScript(
-    "chrome://mochitests/content/browser/browser/base/content/test/general/file_register_about_page.js",
-    true
-  );
-
+  yield kAboutPagesRegistered;
   yield BrowserTestUtils.withNewTab("about:test-about-principal-parent", function*(browser) {
     let loadPromise = BrowserTestUtils.browserLoaded(browser, false, "about:test-about-principal-child");
     let myLink = browser.contentDocument.getElementById("aboutchildprincipal");
     myLink.click();
     yield loadPromise;
 
     yield ContentTask.spawn(gBrowser.selectedBrowser, {}, function*() {
       let channel = content.document.docShell.currentDocumentChannel;
@@ -39,16 +37,17 @@ add_task(function* test_principal_click(
       let loadingPrincipal = channel.loadInfo.loadingPrincipal;
       is(loadingPrincipal, null,
          "sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal");
     });
   });
 });
 
 add_task(function* test_principal_ctrl_click() {
+  yield kAboutPagesRegistered;
   yield SpecialPowers.pushPrefEnv({
     "set": [["security.sandbox.content.level", 1]],
   });
 
   yield BrowserTestUtils.withNewTab("about:test-about-principal-parent", function*(browser) {
     let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:test-about-principal-child");
     // simulate ctrl+click
     BrowserTestUtils.synthesizeMouseAtCenter("#aboutchildprincipal",
@@ -75,16 +74,17 @@ add_task(function* test_principal_ctrl_c
       is(loadingPrincipal, null,
          "sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal");
     });
     yield BrowserTestUtils.removeTab(tab);
   });
 });
 
 add_task(function* test_principal_right_click_open_link_in_new_tab() {
+  yield kAboutPagesRegistered;
   yield SpecialPowers.pushPrefEnv({
     "set": [["security.sandbox.content.level", 1]],
   });
 
   yield BrowserTestUtils.withNewTab("about:test-about-principal-parent", function*(browser) {
     let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:test-about-principal-child");
 
     // simulate right-click open link in tab
deleted file mode 100644
--- a/browser/base/content/test/general/file_register_about_page.js
+++ /dev/null
@@ -1,81 +0,0 @@
-const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) {
-  this.chromeURL = chromeURL;
-  this.aboutHost = aboutHost;
-  this.classID = Components.ID(classID);
-  this.description = description;
-  this.uriFlags = uriFlags;
-}
-
-AboutPage.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
-  getURIFlags(aURI) { // eslint-disable-line no-unused-vars
-    return this.uriFlags;
-  },
-
-  newChannel(aURI, aLoadInfo) {
-    let newURI = Services.io.newURI(this.chromeURL);
-    let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
-                                                            aLoadInfo);
-    channel.originalURI = aURI;
-
-    if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
-      channel.owner = null;
-    }
-    return channel;
-  },
-
-  createInstance(outer, iid) {
-    if (outer !== null) {
-      throw Cr.NS_ERROR_NO_AGGREGATION;
-    }
-    return this.QueryInterface(iid);
-  },
-
-  register() {
-    Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
-      this.classID, this.description,
-      "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
-  },
-
-  unregister() {
-    Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
-      this.classID, this);
-  }
-};
-
-/* exported AboutPrincipalTest */
-var AboutPrincipalTest = {};
-
-XPCOMUtils.defineLazyGetter(AboutPrincipalTest, "aboutChild", () =>
-  new AboutPage("chrome://mochitests/content/browser/browser/base/content/test/general/file_about_child.html",
-                "test-about-principal-child",
-                "{df6cbd19-c95b-4011-874b-315347c0832c}",
-                "About Principal Child Test",
-                Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
-                Ci.nsIAboutModule.ALLOW_SCRIPT)
-
-);
-
-XPCOMUtils.defineLazyGetter(AboutPrincipalTest, "aboutParent", () =>
-  new AboutPage("chrome://mochitests/content/browser/browser/base/content/test/general/file_about_parent.html",
-                "test-about-principal-parent",
-                "{15e1a03d-9f94-4352-bfb8-94216140d3ab}",
-                "About Principal Parent Test",
-                Ci.nsIAboutModule.ALLOW_SCRIPT)
-);
-
-AboutPrincipalTest.aboutParent.register();
-AboutPrincipalTest.aboutChild.register();
-
-function onUnregisterMessage() {
-  removeMessageListener("AboutPrincipalTest:Unregister", onUnregisterMessage);
-  AboutPrincipalTest.aboutParent.unregister();
-  AboutPrincipalTest.aboutChild.unregister();
-  sendAsyncMessage("AboutPrincipalTest:Unregistered");
-}
-
-addMessageListener("AboutPrincipalTest:Unregister", onUnregisterMessage);
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -37,16 +37,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 // some cases.
 Cu.permitCPOWsInScope(this);
 
 var gSendCharCount = 0;
 var gSynthesizeKeyCount = 0;
 var gSynthesizeCompositionCount = 0;
 var gSynthesizeCompositionChangeCount = 0;
 
+const kAboutPageRegistrationContentScript =
+  "chrome://mochikit/content/tests/BrowserTestUtils/content-about-page-utils.js";
+
 this.BrowserTestUtils = {
   /**
    * Loads a page in a new tab, executes a Task and closes the tab.
    *
    * @param options
    *        An object  or string.
    *        If this is a string it is the url to open and will be opened in the
    *        currently active browser window.
@@ -1263,9 +1266,67 @@ this.BrowserTestUtils = {
       return new Promise((resolve) => {
         addEventListener("MozAfterPaint", function onPaint() {
           removeEventListener("MozAfterPaint", onPaint);
           resolve();
         })
       });
     });
   },
+
+  _knownAboutPages: new Set(),
+  _loadedAboutContentScript: false,
+  /**
+   * Registers an about: page with particular flags in both the parent
+   * and any content processes. Returns a promise that resolves when
+   * registration is complete.
+   *
+   * @param registerCleanupFunction (Function)
+   *        The test framework doesn't keep its cleanup stuff anywhere accessible,
+   *        so the first argument is a reference to your cleanup registration
+   *        function, allowing us to clean up after you if necessary.
+   * @param aboutModule (String)
+   *        The name of the about page.
+   * @param pageURI (String)
+   *        The URI the about: page should point to.
+   * @param flags (Number)
+   *        The nsIAboutModule flags to use for registration.
+   * @returns Promise that resolves when registration has finished.
+   */
+  registerAboutPage(registerCleanupFunction, aboutModule, pageURI, flags) {
+    // Return a promise that resolves when registration finished.
+    const kRegistrationMsgId = "browser-test-utils:about-registration:registered";
+    let rv = this.waitForMessage(Services.ppmm, kRegistrationMsgId, msg => {
+      return msg.data == aboutModule;
+    });
+    // Load a script that registers our page, then send it a message to execute the registration.
+    if (!this._loadedAboutContentScript) {
+      Services.ppmm.loadProcessScript(kAboutPageRegistrationContentScript, true);
+      this._loadedAboutContentScript = true;
+      registerCleanupFunction(this._removeAboutPageRegistrations.bind(this));
+    }
+    Services.ppmm.broadcastAsyncMessage("browser-test-utils:about-registration:register",
+                                        {aboutModule, pageURI, flags});
+    return rv.then(() => {
+      this._knownAboutPages.add(aboutModule);
+    });
+  },
+
+  unregisterAboutPage(aboutModule) {
+    if (!this._knownAboutPages.has(aboutModule)) {
+      return Promise.reject(new Error("We don't think this about page exists!"));
+    }
+    const kUnregistrationMsgId = "browser-test-utils:about-registration:unregistered";
+    let rv = this.waitForMessage(Services.ppmm, kUnregistrationMsgId, msg => {
+      return msg.data == aboutModule;
+    });
+    Services.ppmm.broadcastAsyncMessage("browser-test-utils:about-registration:unregister",
+                                        aboutModule);
+    return rv.then(() => this._knownAboutPages.delete(aboutModule));
+  },
+
+  *_removeAboutPageRegistrations() {
+    for (let aboutModule of this._knownAboutPages) {
+      yield this.unregisterAboutPage(aboutModule);
+    }
+    Services.ppmm.removeDelayedProcessScript(kAboutPageRegistrationContentScript);
+  },
 };
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js
@@ -0,0 +1,76 @@
+"use strict";
+
+var {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+
+function AboutPage(aboutHost, chromeURL, uriFlags) {
+  this.chromeURL = chromeURL;
+  this.aboutHost = aboutHost;
+  this.classID = Components.ID(generateUUID().number);
+  this.description = "BrowserTestUtils: " + aboutHost;
+  this.uriFlags = uriFlags;
+}
+
+AboutPage.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+  getURIFlags(aURI) { // eslint-disable-line no-unused-vars
+    return this.uriFlags;
+  },
+
+  newChannel(aURI, aLoadInfo) {
+    let newURI = Services.io.newURI(this.chromeURL);
+    let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
+                                                            aLoadInfo);
+    channel.originalURI = aURI;
+
+    if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
+      channel.owner = null;
+    }
+    return channel;
+  },
+
+  createInstance(outer, iid) {
+    if (outer !== null) {
+      throw Cr.NS_ERROR_NO_AGGREGATION;
+    }
+    return this.QueryInterface(iid);
+  },
+
+  register() {
+    Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
+      this.classID, this.description,
+      "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
+  },
+
+  unregister() {
+    Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
+      this.classID, this);
+  }
+};
+
+const gRegisteredPages = new Map();
+
+addMessageListener("browser-test-utils:about-registration:register", msg => {
+  let {aboutModule, pageURI, flags} = msg.data;
+  if (gRegisteredPages.has(aboutModule)) {
+    gRegisteredPages.get(aboutModule).unregister();
+  }
+  let moduleObj = new AboutPage(aboutModule, pageURI, flags);
+  moduleObj.register();
+  gRegisteredPages.set(aboutModule, moduleObj);
+  sendAsyncMessage("browser-test-utils:about-registration:registered", aboutModule);
+});
+
+addMessageListener("browser-test-utils:about-registration:unregister", msg => {
+  let aboutModule = msg.data;
+  let moduleObj = gRegisteredPages.get(aboutModule);
+  if (moduleObj) {
+    moduleObj.unregister();
+    gRegisteredPages.delete(aboutModule);
+  }
+  sendAsyncMessage("browser-test-utils:about-registration:unregistered", aboutModule);
+});
--- a/testing/mochitest/jar.mn
+++ b/testing/mochitest/jar.mn
@@ -37,10 +37,11 @@ mochikit.jar:
   content/tests/SimpleTest/TestRunner.js (tests/SimpleTest/TestRunner.js)
   content/tests/SimpleTest/iframe-between-tests.html (tests/SimpleTest/iframe-between-tests.html)
   content/tests/SimpleTest/WindowSnapshot.js (tests/SimpleTest/WindowSnapshot.js)
   content/tests/SimpleTest/MockObjects.js (tests/SimpleTest/MockObjects.js)
   content/tests/SimpleTest/NativeKeyCodes.js (tests/SimpleTest/NativeKeyCodes.js)
   content/tests/SimpleTest/paint_listener.js (tests/SimpleTest/paint_listener.js)
   content/tests/SimpleTest/docshell_helpers.js (../../docshell/test/chrome/docshell_helpers.js)
   content/tests/BrowserTestUtils/content-task.js (BrowserTestUtils/content/content-task.js)
+  content/tests/BrowserTestUtils/content-about-page-utils.js (BrowserTestUtils/content/content-about-page-utils.js)
   content/tests/BrowserTestUtils/content-utils.js (BrowserTestUtils/content/content-utils.js)
 
--- a/testing/mochitest/tests/browser/browser.ini
+++ b/testing/mochitest/tests/browser/browser.ini
@@ -1,16 +1,18 @@
 [DEFAULT]
 support-files =
   head.js
 
 [browser_browserLoaded_content_loaded.js]
 [browser_add_task.js]
 [browser_async.js]
 [browser_BrowserTestUtils.js]
+support-files =
+  dummy.html
 [browser_head.js]
 [browser_pass.js]
 [browser_parameters.js]
 [browser_popupNode.js]
 [browser_popupNode_check.js]
 [browser_privileges.js]
 [browser_sanityException.js]
 [browser_sanityException2.js]
--- a/testing/mochitest/tests/browser/browser_BrowserTestUtils.js
+++ b/testing/mochitest/tests/browser/browser_BrowserTestUtils.js
@@ -42,8 +42,29 @@ add_task(function* () {
 
   cancelled = yield BrowserTestUtils.synthesizeMouseAtCenter("body > div", { type: "mouseup" }, browser);
   details = yield getLastEventDetails(browser);
   is(details, "div,40,84", "synthesizeMouseAtCenter mouseup with complex selector");
   ok(!cancelled, "synthesizeMouseAtCenter mouseup with complex selector cancelled");
 
   gBrowser.removeTab(tab);
 });
+
+add_task(function* () {
+  yield BrowserTestUtils.registerAboutPage(
+    registerCleanupFunction, "about-pages-are-cool",
+    getRootDirectory(gTestPath) + "dummy.html", 0);
+  let tab = yield BrowserTestUtils.openNewForegroundTab(
+    gBrowser, "about:about-pages-are-cool", true);
+  ok(tab, "Successfully created an about: page and loaded it.");
+  yield BrowserTestUtils.removeTab(tab);
+  try {
+    yield BrowserTestUtils.unregisterAboutPage("about-pages-are-cool");
+    ok(true, "Successfully unregistered the about page.");
+  } catch (ex) {
+    ok(false, "Should not throw unregistering a known about: page");
+  }
+  yield BrowserTestUtils.unregisterAboutPage("random-other-about-page").then(() => {
+    ok(false, "Should not have succeeded unregistering an unknown about: page.");
+  }, () => {
+    ok(true, "Should have returned a rejected promise trying to unregister an unknown about page");
+  });
+});
new file mode 100644
--- /dev/null
+++ b/testing/mochitest/tests/browser/dummy.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+  <title>This is a dummy page</title>
+  <meta charset="utf-8">
+  <body>This is a dummy page</body>
+</html>