Bug 1481918 Allow webextension test wrappers for externally installed extensions r=kmag
authorAndrew Swan <aswan@mozilla.com>
Sat, 18 Aug 2018 15:09:40 -0700
changeset 491792 169b47aeda91a0122dcb491a501db4d4543b5e48
parent 491778 10c2d7ed3aaff4334d186739c2978dcb8f46226d
child 491793 a8c76f3a18f9f6b57331aea619df59bc16552d24
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1481918
milestone63.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 1481918 Allow webextension test wrappers for externally installed extensions r=kmag Differential Revision: https://phabricator.services.mozilla.com/D3716
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -425,26 +425,21 @@ class ExtensionWrapper {
 
   onMessage(msg, callback) {
     this.checkDuplicateListeners(msg);
     this.messageHandler.set(msg, callback);
   }
 }
 
 class AOMExtensionWrapper extends ExtensionWrapper {
-  constructor(testScope, xpiFile, installType) {
+  constructor(testScope) {
     super(testScope);
 
     this.onEvent = this.onEvent.bind(this);
 
-    this.file = xpiFile;
-    this.installType = installType;
-
-    this.cleanupFiles = [xpiFile];
-
     Management.on("ready", this.onEvent);
     Management.on("shutdown", this.onEvent);
     Management.on("startup", this.onEvent);
 
     AddonTestUtils.on("addon-manager-shutdown", this.onEvent);
     AddonTestUtils.on("addon-manager-started", this.onEvent);
 
     AddonManager.addAddonListener(this);
@@ -457,33 +452,16 @@ class AOMExtensionWrapper extends Extens
     Management.off("ready", this.onEvent);
     Management.off("shutdown", this.onEvent);
     Management.off("startup", this.onEvent);
 
     AddonTestUtils.off("addon-manager-shutdown", this.onEvent);
     AddonTestUtils.off("addon-manager-started", this.onEvent);
 
     AddonManager.removeAddonListener(this);
-
-    for (let file of this.cleanupFiles.splice(0)) {
-      try {
-        Services.obs.notifyObservers(file, "flush-cache-entry");
-        file.remove(false);
-      } catch (e) {
-        Cu.reportError(e);
-      }
-    }
-  }
-
-  maybeSetID(uri, id) {
-    if (!this.id && uri instanceof Ci.nsIJARURI &&
-        uri.JARFile.QueryInterface(Ci.nsIFileURL)
-           .file.equals(this.file)) {
-      this.id = id;
-    }
   }
 
   setRestarting() {
     if (this.state !== "restarting") {
       this.startupPromise = new Promise(resolve => {
         this.resolveStartup = resolve;
       }).then(async result => {
         await this.addonPromise;
@@ -556,16 +534,79 @@ class AOMExtensionWrapper extends Extens
           this.state = "running";
           this.resolveStartup(extension);
         }
         break;
       }
     }
   }
 
+  async _flushCache() {
+    if (this.extension && this.extension.rootURI instanceof Ci.nsIJARURI) {
+      let file = this.extension.rootURI.JARFile.QueryInterface(Ci.nsIFileURL).file;
+      await Services.ppmm.broadcastAsyncMessage("Extension:FlushJarCache", {path: file.path});
+    }
+  }
+
+  get version() {
+    return this.addon && this.addon.version;
+  }
+
+  async unload() {
+    await this._flushCache();
+    return super.unload();
+  }
+
+  async upgrade(data) {
+    this.startupPromise = new Promise(resolve => {
+      this.resolveStartup = resolve;
+    });
+    this.state = "restarting";
+
+    await this._flushCache();
+
+    let xpiFile = Extension.generateXPI(data);
+
+    this.cleanupFiles.push(xpiFile);
+
+    return this._install(xpiFile);
+  }
+}
+
+class InstallableWrapper extends AOMExtensionWrapper {
+  constructor(testScope, xpiFile, installType) {
+    super(testScope);
+
+    this.file = xpiFile;
+    this.installType = installType;
+
+    this.cleanupFiles = [xpiFile];
+  }
+
+  destroy() {
+    super.destroy();
+
+    for (let file of this.cleanupFiles.splice(0)) {
+      try {
+        Services.obs.notifyObservers(file, "flush-cache-entry");
+        file.remove(false);
+      } catch (e) {
+        Cu.reportError(e);
+      }
+    }
+  }
+
+  maybeSetID(uri, id) {
+    if (!this.id && uri instanceof Ci.nsIJARURI &&
+        uri.JARFile.QueryInterface(Ci.nsIFileURL)
+           .file.equals(this.file)) {
+      this.id = id;
+    }
+  }
+
   _install(xpiFile) {
     if (this.installType === "temporary") {
       return AddonManager.installTemporaryAddon(xpiFile).then(addon => {
         this.id = addon.id;
         this.addon = addon;
 
         return this.startupPromise;
       }).catch(e => {
@@ -588,59 +629,43 @@ class AOMExtensionWrapper extends Extens
         install.addListener(listener);
         install.install();
 
         return this.startupPromise;
       });
     }
   }
 
-  async _flushCache() {
-    if (this.extension && this.extension.rootURI instanceof Ci.nsIJARURI) {
-      let file = this.extension.rootURI.JARFile.QueryInterface(Ci.nsIFileURL).file;
-      await Services.ppmm.broadcastAsyncMessage("Extension:FlushJarCache", {path: file.path});
-    }
-  }
-
-  get version() {
-    return this.addon && this.addon.version;
-  }
-
   startup() {
     if (this.state != "uninitialized") {
       throw new Error("Extension already started");
     }
 
     this.state = "pending";
     this.startupPromise = new Promise(resolve => {
       this.resolveStartup = resolve;
     });
 
     return this._install(this.file);
   }
+}
 
-  async unload() {
-    await this._flushCache();
-    return super.unload();
-  }
+class ExternallyInstalledWrapper extends AOMExtensionWrapper {
+  constructor(testScope, id) {
+    super(testScope);
 
-  async upgrade(data) {
+    this.id = id;
     this.startupPromise = new Promise(resolve => {
       this.resolveStartup = resolve;
     });
-    this.state = "restarting";
-
-    await this._flushCache();
 
-    let xpiFile = Extension.generateXPI(data);
+    this.state = "restarting";
+  }
 
-    this.cleanupFiles.push(xpiFile);
-
-    return this._install(xpiFile);
-  }
+  maybeSetID(uri, id) { }
 }
 
 var ExtensionTestUtils = {
   BASE_MANIFEST,
 
   async normalizeManifest(manifest, manifestType = "manifest.WebExtensionManifest",
                           baseManifest = BASE_MANIFEST) {
     await Management.lazyInit();
@@ -749,17 +774,23 @@ var ExtensionTestUtils = {
     }
 
     let extension = Extension.generate(data);
 
     return new ExtensionWrapper(this.currentScope, extension);
   },
 
   loadExtensionXPI(xpiFile, useAddonManager = "temporary") {
-    return new AOMExtensionWrapper(this.currentScope, xpiFile, useAddonManager);
+    return new InstallableWrapper(this.currentScope, xpiFile, useAddonManager);
+  },
+
+  // Create a wrapper for a webextension that will be installed
+  // by some external process (e.g., Normandy)
+  expectExtension(id) {
+    return new ExternallyInstalledWrapper(this.currentScope, id);
   },
 
   get remoteContentScripts() {
     return REMOTE_CONTENT_SCRIPTS;
   },
 
   set remoteContentScripts(val) {
     REMOTE_CONTENT_SCRIPTS = !!val;