Bug 1498343 - Fix and re-enable userScript test disabled in Bug 1498343. r=zombie
authorLuca Greco <lgreco@mozilla.com>
Thu, 18 Oct 2018 12:19:51 +0000
changeset 490506 c68fc2d0347185ab54ef90462b9b294f82cc50be
parent 490505 b466e005ccbb79b108abb8d0083ef5a2ca928057
child 490507 a0aa0b0aa078f7135e7d7032687e4a38e6c378f8
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerszombie
bugs1498343
milestone64.0a1
Bug 1498343 - Fix and re-enable userScript test disabled in Bug 1498343. r=zombie Differential Revision: https://phabricator.services.mozilla.com/D8537
toolkit/components/extensions/extension-process-script.js
toolkit/components/extensions/test/xpcshell/test_ext_userScripts.js
--- a/toolkit/components/extensions/extension-process-script.js
+++ b/toolkit/components/extensions/extension-process-script.js
@@ -158,24 +158,25 @@ ExtensionManager = {
 
       // Register any existent dynamically registered content script for the extension
       // when a content process is started for the first time (which also cover
       // a content process that crashed and it has been recreated).
       const registeredContentScripts = this.registeredContentScripts.get(policy);
 
       for (let [scriptId, options] of getData(extension, "contentScripts") || []) {
         const script = new WebExtensionContentScript(policy, options);
-        policy.registerContentScript(script);
-        registeredContentScripts.set(scriptId, script);
 
         // If the script is a userScript, add the additional userScriptOptions
         // property to the WebExtensionContentScript instance.
         if ("userScriptOptions" in options) {
           script.userScriptOptions = options.userScriptOptions;
         }
+
+        policy.registerContentScript(script);
+        registeredContentScripts.set(scriptId, script);
       }
 
       policy.active = true;
       policy.instanceId = extension.instanceId;
       policy.optionalPermissions = extension.optionalPermissions;
     }
     return policy;
   },
--- a/toolkit/components/extensions/test/xpcshell/test_ext_userScripts.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_userScripts.js
@@ -1,24 +1,32 @@
 "use strict";
 
+const PROCESS_COUNT_PREF = "dom.ipc.processCount";
+
 const {
   createAppInfo,
 } = AddonTestUtils;
 
 AddonTestUtils.init(this);
 
 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
 
 const server = createHttpServer();
 server.registerDirectory("/data/", do_get_file("data"));
 
 const BASE_URL = `http://localhost:${server.identity.primaryPort}/data`;
 
 add_task(async function setup_test_environment() {
+  if (ExtensionTestUtils.remoteContentScripts) {
+    // Start with one content process so that we can increase the number
+    // later and test the behavior of a fresh content process.
+    Services.prefs.setIntPref(PROCESS_COUNT_PREF, 1);
+  }
+
   // Grant the optional permissions requested.
   function permissionObserver(subject, topic, data) {
     if (topic == "webextension-optional-permission-prompt") {
       let {resolve} = subject.wrappedJSObject;
       resolve(true);
     }
   }
   Services.obs.addObserver(permissionObserver, "webextension-optional-permission-prompt");
@@ -152,70 +160,74 @@ add_task(async function test_userScripts
   // Test that all the matches are now subsumed by the extension permissions.
   extension.sendMessage("test-allowed-matches");
   await extension.awaitMessage("test-allowed-matches:done");
 
   await extension.unload();
 });
 
 // Test that userScripts sandboxes:
-// - can be registered/unregistered from an extension page
+// - can be registered/unregistered from an extension page (and they are registered on both new and
+//   existing processes).
 // - have no WebExtensions APIs available
 // - are able to access the target window and document
-
-// Temporarily disabled due to bug 1498364
-/* eslint-disable indent */
-if (false) {
 add_task(async function test_userScripts_no_webext_apis() {
   async function background() {
-    const matches = ["http://localhost/*/file_sample.html"];
+    const matches = ["http://localhost/*/file_sample.html*"];
 
     const sharedCode = {code: "console.log(\"js code shared by multiple userScripts\");"};
 
-    let script = await browser.userScripts.register({
+    const userScriptOptions = {
       js: [sharedCode, {
         code: `
           window.addEventListener("load", () => {
             const webextAPINamespaces = this.browser ? Object.keys(this.browser) : undefined;
             document.body.innerHTML = "userScript loaded - " + JSON.stringify(webextAPINamespaces);
           }, {once: true});
         `,
       }],
       runAt: "document_start",
       matches,
       scriptMetadata: {
         name: "test-user-script",
         arrayProperty: ["el1"],
         objectProperty: {nestedProp: "nestedValue"},
         nullProperty: null,
       },
-    });
+    };
+
+    let script = await browser.userScripts.register(userScriptOptions);
 
     // Unregister and then register the same js code again, to verify that the last registered
     // userScript doesn't get assigned a revoked blob url (otherwise Extensioncontent.jsm
     // ScriptCache raises an error because it fails to compile the revoked blob url and the user
     // script will never be loaded).
     script.unregister();
-    script = await browser.userScripts.register({
-      js: [sharedCode, {
-        code: `
+    script = await browser.userScripts.register(userScriptOptions);
+
+    browser.test.onMessage.addListener(async msg => {
+      if (msg !== "register-new-script") {
+        return;
+      }
+
+      await script.unregister();
+      await browser.userScripts.register({
+        ...userScriptOptions,
+        scriptMetadata: {name: "test-new-script"},
+        js: [sharedCode, {
+          code: `
           window.addEventListener("load", () => {
             const webextAPINamespaces = this.browser ? Object.keys(this.browser) : undefined;
-            document.body.innerHTML = "userScript loaded - " + JSON.stringify(webextAPINamespaces);
+            document.body.innerHTML = "new userScript loaded - " + JSON.stringify(webextAPINamespaces);
           }, {once: true});
         `,
-      }],
-      runAt: "document_start",
-      matches,
-      scriptMetadata: {
-        name: "test-user-script",
-        arrayProperty: ["el1"],
-        objectProperty: {nestedProp: "nestedValue"},
-        nullProperty: null,
-      },
+        }],
+      });
+
+      browser.test.sendMessage("script-registered");
     });
 
     const scriptToRemove = await browser.userScripts.register({
       js: [sharedCode, {
         code: `
           window.addEventListener("load", () => {
             document.body.innerHTML = "unexpected unregistered userScript loaded";
           }, {once: true});
@@ -248,61 +260,66 @@ add_task(async function test_userScripts
   };
 
   let extension = ExtensionTestUtils.loadExtension(extensionData);
 
   await extension.startup();
 
   await extension.awaitMessage("background-ready");
 
-  // Test in an existing process (where the registered userScripts has been received from the
-  // Extension:RegisterContentScript message sent to all the processes).
-  info("Test content script loaded in a process created before any registered userScript");
-  let url = `${BASE_URL}/file_sample.html#remote-false`;
-  let contentPage = await ExtensionTestUtils.loadContentPage(url, {remote: false});
+  let url = `${BASE_URL}/file_sample.html?testpage=1`;
+  let contentPage = await ExtensionTestUtils.loadContentPage(
+    url, ExtensionTestUtils.remoteContentScripts ? {remote: true} : undefined);
   let result = await contentPage.spawn(undefined, async () => {
     return {
       textContent: this.content.document.body.textContent,
       url: this.content.location.href,
       readyState: this.content.document.readyState,
     };
   });
   Assert.deepEqual(result, {
     textContent: "userScript loaded - undefined",
     url,
     readyState: "complete",
   }, "The userScript executed on the expected url and no access to the WebExtensions APIs");
-  await contentPage.close();
+
+  // If the tests is running with "remote content process" mode, test that the userScript
+  // are being correctly registered in newly created processes (received as part of the sharedData).
+  if (ExtensionTestUtils.remoteContentScripts) {
+    info("Test content script are correctly created on a newly created process");
 
-  // Test in a new process (where the registered userScripts has to be retrieved from the extension
-  // representation from the shared memory data).
-  // NOTE: this part is currently skipped on Android, where e10s content is not yet supported and
-  // the xpcshell test crash when we create contentPage2 with `remote = true`.
-  if (ExtensionTestUtils.remoteContentScripts) {
-    info("Test content script loaded in a process created after the userScript has been registered");
-    let url2 = `${BASE_URL}/file_sample.html#remote-true`;
+    await extension.sendMessage("register-new-script");
+    await extension.awaitMessage("script-registered");
+
+    // Update the process count preference, so that we can test that the newly registered user script
+    // is propagated as expected into the newly created process.
+    Services.prefs.setIntPref(PROCESS_COUNT_PREF, 2);
+
+    const url2 = `${BASE_URL}/file_sample.html?testpage=2`;
     let contentPage2 = await ExtensionTestUtils.loadContentPage(url2, {remote: true});
     let result2 = await contentPage2.spawn(undefined, async () => {
       return {
         textContent: this.content.document.body.textContent,
         url: this.content.location.href,
         readyState: this.content.document.readyState,
       };
     });
     Assert.deepEqual(result2, {
-      textContent: "userScript loaded - undefined",
+      textContent: "new userScript loaded - undefined",
       url: url2,
       readyState: "complete",
     }, "The userScript executed on the expected url and no access to the WebExtensions APIs");
+
     await contentPage2.close();
   }
 
+  await contentPage.close();
+
   await extension.unload();
 });
-}
 
 add_task(async function test_userScripts_exported_APIs() {
   async function background() {
     const matches = ["http://localhost/*/file_sample.html"];
 
     await browser.runtime.onMessage.addListener(async (msg, sender) => {
       return {bgPageReply: true};
     });