Bug 1465806 - Wait for addon manager and session restore full initialization before starting DAMP tests. r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Tue, 29 May 2018 11:07:08 -0700
changeset 476053 f2ae0027dfa4c4a5b5b8d1d92ce02accff6e6e4f
parent 476052 e207930f9e8a27b78e76a1866139c310e3a52dfb
child 476054 0673137d307f3878d4cf48160cfa16efb66c25b6
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1465806
milestone62.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 1465806 - Wait for addon manager and session restore full initialization before starting DAMP tests. r=jdescottes MozReview-Commit-ID: 1xszgL781BU
testing/talos/talos/tests/devtools/addon/content/damp.js
testing/talos/talos/tests/devtools/addon/content/tests/head.js
--- a/testing/talos/talos/tests/devtools/addon/content/damp.js
+++ b/testing/talos/talos/tests/devtools/addon/content/damp.js
@@ -1,10 +1,11 @@
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
 const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", {});
+const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
 const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
 
 XPCOMUtils.defineLazyGetter(this, "require", function() {
   let { require } =
     ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
   return require;
 });
 XPCOMUtils.defineLazyGetter(this, "gDevTools", function() {
@@ -158,16 +159,31 @@ Damp.prototype = {
 
   async addTab(url) {
     let tab = this._win.gBrowser.selectedTab = this._win.gBrowser.addTab(url);
     let browser = tab.linkedBrowser;
     await awaitBrowserLoaded(browser);
     return tab;
   },
 
+  async waitForPendingPaints(window) {
+    let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                      .getInterface(Ci.nsIDOMWindowUtils);
+    window.performance.mark("pending paints.start");
+    while (utils.isMozAfterPaintPending) {
+      await new Promise(done => {
+        window.addEventListener("MozAfterPaint", function listener() {
+          window.performance.mark("pending paint");
+          done();
+        }, { once: true });
+      });
+    }
+    window.performance.measure("pending paints", "pending paints.start");
+  },
+
   closeCurrentTab() {
     this._win.BrowserCloseTabOrWindow();
     return this._win.gBrowser.selectedTab;
   },
 
   reloadPage(onReload) {
     return new Promise(resolve => {
       let browser = gBrowser.selectedBrowser;
@@ -195,19 +211,16 @@ Damp.prototype = {
     await this.garbageCollect();
 
     let duration = Math.round(performance.now() - this._startTime);
     dump(`${this._currentTest} took ${duration}ms.\n`);
 
     this._runNextTest();
   },
 
-  // Everything below here are common pieces needed for the test runner to function,
-  // just copy and pasted from Tart with /s/TART/DAMP
-
   _win: undefined,
   _dampTab: undefined,
   _results: [],
   _config: {subtests: [], repeat: 1, rest: 100},
   _nextTestIndex: 0,
   _tests: [],
   _onSequenceComplete: 0,
 
@@ -345,16 +358,50 @@ Damp.prototype = {
     this._doneInternal();
   },
 
   exception(e) {
     this.error(e);
     dump(e.stack + "\n");
   },
 
+  // Waits for any pending operations that may execute on Firefox startup and that
+  // can still be pending when we start running DAMP tests.
+  async waitBeforeRunningTests() {
+    // Addons may still be being loaded, so wait for them to be fully set up.
+    if (!AddonManager.isReady) {
+      let onAddonManagerReady = new Promise(resolve => {
+        let listener = {
+          onStartup() {
+            AddonManager.removeManagerListener(listener);
+            resolve();
+          },
+          onShutdown() {},
+        };
+        AddonManager.addManagerListener(listener);
+      });
+      await onAddonManagerReady;
+    }
+
+    // SessionRestore triggers some saving sequence on idle,
+    // so wait for that to be processed before starting tests.
+    // https://searchfox.org/mozilla-central/rev/83a923ef7a3b95a516f240a6810c20664b1e0ac9/browser/components/sessionstore/content/content-sessionStore.js#828-830
+    // https://searchfox.org/mozilla-central/rev/83a923ef7a3b95a516f240a6810c20664b1e0ac9/browser/components/sessionstore/content/content-sessionStore.js#858
+    await new Promise(resolve => {
+      setTimeout(resolve, 1500);
+    });
+    await new Promise(resolve => {
+      requestIdleCallback(resolve, { timeout: 15000 });
+    });
+
+    // Free memory before running the first test, otherwise we may have a GC
+    // related to Firefox startup or DAMP setup during the first test.
+    await this.garbageCollect();
+  },
+
   startTest(doneCallback, config) {
     try {
       dump("Initialize the head file with a reference to this DAMP instance\n");
       let head = require("chrome://damp/content/tests/head.js");
       head.initialize(this);
 
       this._onTestComplete = function(results) {
         TalosParentProfiler.pause("DAMP - end");
@@ -389,19 +436,17 @@ Damp.prototype = {
       // Construct the sequence array while filtering tests
       let sequenceArray = [];
       for (let test of tests) {
         for (let r = 0; r < config.repeat; r++) {
           sequenceArray.push(test.path);
         }
       }
 
-      // Free memory before running the first test, otherwise we may have a GC
-      // related to Firefox startup or DAMP setup during the first test.
-      this.garbageCollect().then(() => {
+     this.waitBeforeRunningTests().then(() => {
         this._doSequence(sequenceArray, this._doneInternal);
       }).catch(e => {
         this.exception(e);
       });
     } catch (e) {
       this.exception(e);
     }
   }
--- a/testing/talos/talos/tests/devtools/addon/content/tests/head.js
+++ b/testing/talos/talos/tests/devtools/addon/content/tests/head.js
@@ -3,18 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 /**
  * This helper contains the public API that can be used by DAMP tests.
  */
 
-// eslint-disable-next-line mozilla/no-define-cc-etc
-const { Ci } = require("chrome");
 const Services = require("Services");
 const { gDevTools } = require("devtools/client/framework/devtools");
 const { TargetFactory } = require("devtools/client/framework/target");
 
 const webserver = Services.prefs.getCharPref("addon.test.damp.webserver");
 
 const PAGES_BASE_URL = webserver + "/tests/devtools/addon/content/pages/";
 
@@ -72,29 +70,17 @@ exports.getToolbox = function() {
  * Wait for any pending paint.
  * The tool may have touched the DOM elements at the very end of the current test.
  * We should ensure waiting for the reflow related to these changes.
  */
 async function waitForPendingPaints(toolbox) {
   let panel = toolbox.getCurrentPanel();
   // All panels have its own way of exposing their window object...
   let window = panel.panelWin || panel._frameWindow || panel.panelWindow;
-
-  let utils = window.QueryInterface(Ci.nsIInterfaceRequestor)
-                    .getInterface(Ci.nsIDOMWindowUtils);
-  window.performance.mark("pending paints.start");
-  while (utils.isMozAfterPaintPending) {
-    await new Promise(done => {
-      window.addEventListener("MozAfterPaint", function listener() {
-        window.performance.mark("pending paint");
-        done();
-      }, { once: true });
-    });
-  }
-  window.performance.measure("pending paints", "pending paints.start");
+  return damp.waitForPendingPaints(window);
 }
 
 const openToolbox = async function(tool = "webconsole", onLoad) {
   let tab = getActiveTab();
   let target = TargetFactory.forTab(tab);
   let onToolboxCreated = gDevTools.once("toolbox-created");
   let showPromise = gDevTools.showToolbox(target, tool);
   let toolbox = await onToolboxCreated;