Bug 1253148: [webext] Cleanup running extensions on test failure. r=billm
authorKris Maglione <maglione.k@gmail.com>
Wed, 02 Mar 2016 20:58:28 -0800
changeset 324869 cd697b51aed416ac3be564b7b2dff6b44178481b
parent 324868 579da5ef8ccf4417fb472947e4cd5665f7f90a46
child 324870 a6b03f5e2c7366ca44426d935a5b84e546fc00ec
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1253148
milestone47.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 1253148: [webext] Cleanup running extensions on test failure. r=billm MozReview-Commit-ID: HTFZk6y6ZEp
testing/mochitest/browser-test.js
testing/mochitest/tests/SimpleTest/ExtensionTestUtils.js
testing/specialpowers/content/specialpowersAPI.js
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -140,17 +140,21 @@ function Tester(aTests, structuredLogger
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js", simpleTestScope);
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js", simpleTestScope);
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromePowers.js", simpleTestScope);
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SimpleTest.js", simpleTestScope);
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/MemoryStats.js", simpleTestScope);
   this._scriptLoader.loadSubScript("chrome://mochikit/content/chrome-harness.js", simpleTestScope);
   this.SimpleTest = simpleTestScope.SimpleTest;
 
-  var extensionUtilsScope = {};
+  var extensionUtilsScope = {
+    registerCleanupFunction: (fn) => {
+      this.currentTest.scope.registerCleanupFunction(fn);
+    },
+  };
   extensionUtilsScope.SimpleTest = this.SimpleTest;
   this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js", extensionUtilsScope);
   this.ExtensionTestUtils = extensionUtilsScope.ExtensionTestUtils;
 
   this.SimpleTest.harnessParameters = gConfig;
 
   this.MemoryStats = simpleTestScope.MemoryStats;
   this.Task = Task;
--- a/testing/mochitest/tests/SimpleTest/ExtensionTestUtils.js
+++ b/testing/mochitest/tests/SimpleTest/ExtensionTestUtils.js
@@ -1,21 +1,30 @@
 var ExtensionTestUtils = {};
 
 ExtensionTestUtils.loadExtension = function(ext, id = null)
 {
+  // Cleanup functions need to be registered differently depending on
+  // whether we're in browser chrome or plain mochitests.
+  var registerCleanup;
+  if (typeof registerCleanupFunction != "undefined") {
+    registerCleanup = registerCleanupFunction;
+  } else {
+    registerCleanup = SimpleTest.registerCleanupFunction.bind(SimpleTest);
+  }
+
   var testResolve;
   var testDone = new Promise(resolve => { testResolve = resolve; });
 
   var messageHandler = new Map();
   var messageAwaiter = new Map();
 
   var messageQueue = new Set();
 
-  SimpleTest.registerCleanupFunction(() => {
+  registerCleanup(() => {
     if (messageQueue.size) {
       SimpleTest.is(messageQueue.size, 0, "message queue is empty");
     }
     if (messageAwaiter.size) {
       SimpleTest.is(messageAwaiter.size, 0, "no tasks awaiting on messages");
     }
   });
 
@@ -69,16 +78,25 @@ ExtensionTestUtils.loadExtension = funct
         checkMessages();
       }
 
     },
   };
 
   var extension = SpecialPowers.loadExtension(id, ext, handler);
 
+  registerCleanup(() => {
+    if (extension.state == "pending" || extension.state == "running") {
+      SimpleTest.ok(false, "Extension left running at test shutdown")
+      return extension.unload();
+    } else if (extension.state == "unloading") {
+      SimpleTest.ok(false, "Extension not fully unloaded at test shutdown")
+    }
+  });
+
   extension.awaitMessage = (msg) => {
     return new Promise(resolve => {
       checkDuplicateListeners(msg);
 
       messageAwaiter.set(msg, {resolve});
       checkMessages();
     });
   };
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1876,44 +1876,52 @@ SpecialPowersAPI.prototype = {
     startupPromise.catch(() => {
       this._removeMessageListener("SPExtensionMessage", listener);
     });
 
     handler = Cu.waiveXrays(handler);
     ext = Cu.waiveXrays(ext);
 
     let sp = this;
+    let state = "uninitialized";
     let extension = {
       id,
 
+      get state() { return state; },
+
       startup() {
+        state = "pending";
         sp._sendAsyncMessage("SPStartupExtension", {id});
         return startupPromise;
       },
 
       unload() {
+        state = "unloading";
         sp._sendAsyncMessage("SPUnloadExtension", {id});
         return unloadPromise;
       },
 
       sendMessage(...args) {
         sp._sendAsyncMessage("SPExtensionMessage", {id, args});
       },
     };
 
     this._sendAsyncMessage("SPLoadExtension", {ext, id});
 
     let listener = (msg) => {
       if (msg.data.id == id) {
         if (msg.data.type == "extensionStarted") {
+          state = "running";
           resolveStartup();
         } else if (msg.data.type == "extensionFailed") {
+          state = "failed";
           rejectStartup("startup failed");
         } else if (msg.data.type == "extensionUnloaded") {
           this._removeMessageListener("SPExtensionMessage", listener);
+          state = "unloaded";
           resolveUnload();
         } else if (msg.data.type in handler) {
           handler[msg.data.type](...msg.data.args);
         } else {
           dump(`Unexpected: ${msg.data.type}\n`);
         }
       }
     };