# HG changeset patch # User Kartikaya Gupta # Date 1520742387 18000 # Node ID 81cbeed3386036397f7d001234e89a378a3725c9 # Parent 5cc75edd971c31c05988d44322ce6e3a303de9b4 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 diff --git a/gfx/layers/apz/test/mochitest/apz_test_utils.js b/gfx/layers/apz/test/mochitest/apz_test_utils.js --- 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 + "]"); + } + } + } +}; diff --git a/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html b/gfx/layers/apz/test/mochitest/helper_touch_action_regions.html --- 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.