Bug 1437295 - Ensure cleanup functions registered in a subtest are invoked when unloading the subtest. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Sat, 10 Mar 2018 23:26:27 -0500
changeset 462546 81cbeed3386036397f7d001234e89a378a3725c9
parent 462545 e2d541a790ea4419dc366ac9dc5d76a7ece662fc
child 462547 49393cd5db235a279576b857d83232ee2e44c7ed
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1437295
milestone60.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 1437295 - Ensure cleanup functions registered in a subtest are invoked when unloading the subtest. r=botond If we are registering a cleanup function inside a subtest (as we will do in the next patch) then we need to make sure it gets cleaned up before the subtest is unloaded. Otherwise the cleanup will be attempted when the top-level test page is unloaded, at which point the subtest is long gone, and that results in an error. MozReview-Commit-ID: 828XddkOUlP
gfx/layers/apz/test/mochitest/apz_test_utils.js
gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
--- a/gfx/layers/apz/test/mochitest/apz_test_utils.js
+++ b/gfx/layers/apz/test/mochitest/apz_test_utils.js
@@ -192,16 +192,20 @@ function waitForApzFlushedRepaints(aCall
 function runSubtestsSeriallyInFreshWindows(aSubtests) {
   return new Promise(function(resolve, reject) {
     var testIndex = -1;
     var w = null;
 
     function advanceSubtestExecution() {
       var test = aSubtests[testIndex];
       if (w) {
+        // Run any cleanup functions registered in the subtest
+        if (w.ApzCleanup) { // guard against the subtest not loading apz_test_utils.js
+          w.ApzCleanup.execute();
+        }
         if (typeof test.dp_suppression != 'undefined') {
           // We modified the suppression when starting the test, so now undo that.
           SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(!test.dp_suppression);
         }
         if (test.prefs) {
           // We pushed some prefs for this test, pop them, and re-invoke
           // advanceSubtestExecution() after that's been processed
           SpecialPowers.popPrefEnv(function() {
@@ -229,16 +233,17 @@ function runSubtestsSeriallyInFreshWindo
         // to avoid that we can force the displayport to be unsuppressed for the
         // entire test which is more deterministic.
         SpecialPowers.getDOMWindowUtils(window).respectDisplayPortSuppression(test.dp_suppression);
       }
 
       function spawnTest(aFile) {
         w = window.open('', "_blank");
         w.subtestDone = advanceSubtestExecution;
+        w.isApzSubtest = true;
         w.SimpleTest = SimpleTest;
         w.is = function(a, b, msg) { return is(a, b, aFile + " | " + msg); };
         w.ok = function(cond, name, diag) { return ok(cond, aFile + " | " + name, diag); };
         if (test.onload) {
           w.addEventListener('load', function(e) { test.onload(w); }, { once: true });
         }
         var subtestUrl = location.href.substring(0, location.href.lastIndexOf('/') + 1) + aFile;
         function urlResolves(url) {
@@ -364,17 +369,17 @@ function getSnapshot(rect) {
       ctx.drawWindow(topWin, rect.x, rect.y, rect.w, rect.h, 'rgb(255,255,255)', ctx.DRAWWINDOW_DRAW_VIEW | ctx.DRAWWINDOW_USE_WIDGET_LAYERS | ctx.DRAWWINDOW_DRAW_CARET);
       return canvas.toDataURL();
     });
   }
 
   if (typeof getSnapshot.chromeHelper == 'undefined') {
     // This is the first time getSnapshot is being called; do initialization
     getSnapshot.chromeHelper = SpecialPowers.loadChromeScript(parentProcessSnapshot);
-    SimpleTest.registerCleanupFunction(function() { getSnapshot.chromeHelper.destroy() });
+    ApzCleanup.register(function() { getSnapshot.chromeHelper.destroy() });
   }
 
   return getSnapshot.chromeHelper.sendSyncMessage('snapshot', JSON.stringify(rect)).toString();
 }
 
 // Takes the document's query string and parses it, assuming the query string
 // is composed of key-value pairs where the value is in JSON format. The object
 // returned contains the various values indexed by their respective keys. In
@@ -551,8 +556,32 @@ function hitTestScrollbar(params) {
     };
     var {hitInfo, scrollId} = hitTest(horizontalScrollbarPoint);
     is(hitInfo, expectedHitInfo,
        scrollframeMsg + " - horizontal scrollbar hit info");
     is(scrollId, params.expectedScrollId,
        scrollframeMsg + " - horizontal scrollbar scrollid");
   }
 }
+
+var ApzCleanup = {
+  _cleanups: [],
+
+  register: function(func) {
+    if (this._cleanups.length == 0) {
+      if (!window.isApzSubtest) {
+        SimpleTest.registerCleanupFunction(this.execute.bind(this));
+      } // else ApzCleanup.execute is called from runSubtestsSeriallyInFreshWindows
+    }
+    this._cleanups.push(func);
+  },
+
+  execute: function() {
+    while (this._cleanups.length > 0) {
+      var func = this._cleanups.pop();
+      try {
+        func();
+      } catch (ex) {
+        SimpleTest.ok(false, "Subtest cleanup function [" + func.toString() + "] threw exception [" + ex + "] on page [" + location.href + "]");
+      }
+    }
+  }
+};
--- a/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
+++ b/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html
@@ -71,17 +71,17 @@ function chromeTouchEventCounter(operati
       delete topWin.eventCounts;
       return true;
     });
   }
 
   if (typeof chromeTouchEventCounter.chromeHelper == 'undefined') {
     // This is the first time chromeTouchEventCounter is being called; do initialization
     chromeTouchEventCounter.chromeHelper = SpecialPowers.loadChromeScript(chromeProcessCounter);
-    SimpleTest.registerCleanupFunction(function() { chromeTouchEventCounter.chromeHelper.destroy() });
+    ApzCleanup.register(function() { chromeTouchEventCounter.chromeHelper.destroy() });
   }
 
   return chromeTouchEventCounter.chromeHelper.sendSyncMessage(operation, "");
 }
 
 // Simple wrapper that waits until the chrome process has seen |count| instances
 // of the |eventType| event. Returns true on success, and false if 10 seconds
 // go by without the condition being satisfied.