Bug 1388082 - Use async/await in reftest module. r?automatedtester draft
authorAndreas Tolfsen <ato@sny.no>
Mon, 07 Aug 2017 18:57:37 +0100
changeset 645936 2c0bd5ce921dea52723b77d315648b6f7c761548
parent 645935 7ea257026743495e61dd35cab75dce59f0579f6c
child 645937 e2a8f9318c99904a4fedf9717d9b1a895eaf4acd
push id73947
push userbmo:ato@sny.no
push dateMon, 14 Aug 2017 16:03:22 +0000
reviewersautomatedtester
bugs1388082
milestone57.0a1
Bug 1388082 - Use async/await in reftest module. r?automatedtester MozReview-Commit-ID: 9sUL77lPCK1
testing/marionette/reftest.js
--- a/testing/marionette/reftest.js
+++ b/testing/marionette/reftest.js
@@ -3,17 +3,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
 
 Cu.import("chrome://marionette/content/assert.js");
 Cu.import("chrome://marionette/content/capture.js");
 const {InvalidArgumentError} =
     Cu.import("chrome://marionette/content/error.js", {});
 
 this.EXPORTED_SYMBOLS = ["reftest"];
 
@@ -64,52 +63,52 @@ reftest.Runner = class {
    *
    * @param {Object.<Number>} urlCount
    *     Object holding a map of URL: number of times the URL
    *     will be opened during the reftest run, where that's
    *     greater than 1.
    * @param {string} screenshotMode
    *     String enum representing when screenshots should be taken
    */
-  *setup(urlCount, screenshotMode) {
+  async setup(urlCount, screenshotMode) {
     this.parentWindow =  assert.window(this.driver.getCurrentWindow());
 
     this.screenshotMode = SCREENSHOT_MODE[screenshotMode] ||
         SCREENSHOT_MODE.unexpected;
 
     this.urlCount = Object.keys(urlCount || {})
         .reduce((map, key) => map.set(key, urlCount[key]), new Map());
 
-    yield this.ensureWindow();
+    await this.ensureWindow();
   }
 
-  *ensureWindow() {
+  async ensureWindow() {
     if (this.reftestWin && !this.reftestWin.closed) {
       return this.reftestWin;
     }
 
-    let reftestWin = yield this.openWindow();
+    let reftestWin = await this.openWindow();
 
     let found = this.driver.findWindow([reftestWin], () => true);
-    yield this.driver.setWindowHandle(found, true);
+    await this.driver.setWindowHandle(found, true);
 
     this.windowUtils = reftestWin.QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIDOMWindowUtils);
     this.reftestWin = reftestWin;
     return reftestWin;
   }
 
-  *openWindow() {
+  async openWindow() {
     let reftestWin;
-    yield new Promise(resolve => {
+    await new Promise(resolve => {
       reftestWin = this.parentWindow.openDialog(
           "chrome://marionette/content/reftest.xul",
           "reftest",
           "chrome,dialog,height=600,width=600,all",
-          () => resolve());
+          resolve);
     });
 
     let browser = reftestWin.document.createElementNS(XUL_NS, "xul:browser");
     browser.permanentKey = {};
     browser.setAttribute("id", "browser");
     browser.setAttribute("anonid", "initialBrowser");
     browser.setAttribute("type", "content");
     browser.setAttribute("primary", "true");
@@ -147,71 +146,78 @@ min-width: 600px; min-height: 600px; max
    * The assumed semantics are those of web-platform-tests where
    * references form a tree and each test must meet all the conditions
    * to reach one leaf node of the tree in order for the overall test
    * to pass.
    *
    * @param {string} testUrl
    *     URL of the test itself.
    * @param {Array.<Array>} references
-   *     Array representing a tree of references to try. Each item in
-   *     the array represents a single reference node and has the form
-   *     [referenceUrl, references, relation], where referenceUrl is a
-   *     string to the url, relation is either "==" or "!=" depending on
-   *     the type of reftest, and references is another array containing
+   *     Array representing a tree of references to try.
+   *
+   *     Each item in the array represents a single reference node and
+   *     has the form <code>[referenceUrl, references, relation]</code>,
+   *     where <var>referenceUrl</var> is a string to the URL, relation
+   *     is either <code>==</code> or <code>!=</code> depending on the
+   *     type of reftest, and references is another array containing
    *     items of the same form, representing further comparisons treated
    *     as AND with the current item. Sibling entries are treated as OR.
+   *
    *     For example with testUrl of T:
+   *
+   *     <pre><code>
    *       references = [[A, [[B, [], ==]], ==]]
    *       Must have T == A AND A == B to pass
    *
    *       references = [[A, [], ==], [B, [], !=]
    *       Must have T == A OR T != B
    *
    *       references = [[A, [[B, [], ==], [C, [], ==]], ==], [D, [], ]]
    *       Must have (T == A AND A == B) OR (T == A AND A == C) OR (T == D)
+   *     </code></pre>
+   *
    * @param {string} expected
-   *     Expected test outcome (e.g. PASS, FAIL).
+   *     Expected test outcome (e.g. <tt>PASS</tt>, <tt>FAIL</tt>).
    * @param {number} timeout
-   *     Test timeout in ms
+   *     Test timeout in milliseconds.
    *
    * @return {Object}
    *     Result object with fields status, message and extra.
    */
-  *run(testUrl, references, expected, timeout) {
+  async run(testUrl, references, expected, timeout) {
 
     let timeoutHandle;
 
     let timeoutPromise = new Promise(resolve => {
       timeoutHandle = this.parentWindow.setTimeout(() => {
         resolve({status: STATUS.TIMEOUT, message: null, extra: {}});
       }, timeout);
     });
 
-    let testRunner = Task.spawn(function*() {
+    let testRunner = (async () => {
       let result;
       try {
-        result = yield this.runTest(testUrl, references, expected, timeout);
+        result = await this.runTest(testUrl, references, expected, timeout);
       } catch (e) {
         result = {status: STATUS.ERROR, message: e.stack, extra: {}};
       }
       return result;
-    }.bind(this));
+    })();
 
-    let result = yield Promise.race([testRunner, timeoutPromise]);
+    let result = await Promise.race([testRunner, timeoutPromise]);
     this.parentWindow.clearTimeout(timeoutHandle);
     if (result.status === STATUS.TIMEOUT) {
       this.abort();
     }
 
     return result;
   }
 
-  *runTest(testUrl, references, expected, timeout) {
-    let win = yield this.ensureWindow();
+  async runTest(testUrl, references, expected, timeout) {
+    let win = await this.ensureWindow();
 
     function toBase64(screenshot) {
       let dataURL = screenshot.canvas.toDataURL();
       return dataURL.split(",")[1];
     }
 
     win.innerWidth = 600;
     win.innerHeight = 600;
@@ -227,17 +233,17 @@ min-width: 600px; min-height: 600px; max
     }
 
     let status = STATUS.FAIL;
 
     while (stack.length) {
       let [lhsUrl, rhsUrl, references, relation] = stack.pop();
       message += `Testing ${lhsUrl} ${relation} ${rhsUrl}\n`;
 
-      let comparison = yield this.compareUrls(
+      let comparison = await this.compareUrls(
           win, lhsUrl, rhsUrl, relation, timeout);
 
       function recordScreenshot() {
         let encodedLHS = toBase64(comparison.lhs);
         let encodedRHS = toBase64(comparison.rhs);
         screenshotData.push([{url: lhsUrl, screenshot: encodedLHS},
           relation,
           {url: rhsUrl, screenshot: encodedRHS}]);
@@ -288,23 +294,23 @@ min-width: 600px; min-height: 600px; max
       // return the last one we took.
       let lastScreenshot = screenshotData[screenshotData.length - 1];
       result.extra.reftest_screenshots = lastScreenshot;
     }
 
     return result;
   }
 
-  *compareUrls(win, lhsUrl, rhsUrl, relation, timeout) {
+  async compareUrls(win, lhsUrl, rhsUrl, relation, timeout) {
     logger.info(`Testing ${lhsUrl} ${relation} ${rhsUrl}`);
 
     // Take the reference screenshot first so that if we pause
     // we see the test rendering
-    let rhs = yield this.screenshot(win, rhsUrl, timeout);
-    let lhs = yield this.screenshot(win, lhsUrl, timeout);
+    let rhs = await this.screenshot(win, rhsUrl, timeout);
+    let lhs = await this.screenshot(win, lhsUrl, timeout);
 
     let maxDifferences = {};
 
     let differences = this.windowUtils.compareCanvases(
         lhs.canvas, rhs.canvas, maxDifferences);
 
     let passed;
     switch (relation) {
@@ -322,17 +328,17 @@ min-width: 600px; min-height: 600px; max
 
       default:
         throw new InvalidArgumentError("Reftest operator should be '==' or '!='");
     }
 
     return {lhs, rhs, passed};
   }
 
-  *screenshot(win, url, timeout) {
+  async screenshot(win, url, timeout) {
     let canvas = null;
     let remainingCount = this.urlCount.get(url) || 1;
     let cache = remainingCount > 1;
     logger.debug(`screenshot ${url} remainingCount: ` +
         `${remainingCount} cache: ${cache}`);
     let reuseCanvas = false;
     if (this.canvasCache.has(url)) {
       logger.debug(`screenshot ${url} taken from cache`);
@@ -356,26 +362,26 @@ min-width: 600px; min-height: 600px; max
 
       logger.debug(`Starting load of ${url}`);
       let navigateOpts = {
         commandId: this.driver.listener.activeMessageId,
         pageTimeout: timeout,
       };
       if (this.lastURL === url) {
         logger.debug(`Refreshing page`);
-        yield this.driver.listener.refresh(navigateOpts);
+        await this.driver.listener.refresh(navigateOpts);
       } else {
         navigateOpts.url = url;
         navigateOpts.loadEventExpected = false;
-        yield this.driver.listener.get(navigateOpts);
+        await this.driver.listener.get(navigateOpts);
         this.lastURL = url;
       }
 
       this.driver.curBrowser.contentBrowser.focus();
-      yield this.driver.listener.reftestWait(url, this.remote);
+      await this.driver.listener.reftestWait(url, this.remote);
 
       canvas = capture.canvas(
           win,
           0,  // left
           0,  // top
           win.innerWidth,
           win.innerHeight,
           {canvas, flags});