tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser-harness.xhtml (11825B)


      1 <?xml version="1.0"?>
      2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
      3 <!-- This Source Code Form is subject to the terms of the Mozilla Public
      4   - License, v. 2.0. If a copy of the MPL was not distributed with this
      5   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
      6 
      7 <window id="browserTestHarness"
      8        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      9        onload="TestStart();"
     10        title="Browser chrome tests"
     11        width="1024">
     12  <script src="chrome://mochikit/content/tests/SimpleTest/MozillaLogger.js"/>
     13  <script src="chrome://mochikit/content/tests/SimpleTest/LogController.js"/>
     14  <script src="chrome://mochikit/content/tests/SimpleTest/TestRunner.js"/>
     15  <script src="chrome://mochikit/content/chrome-harness.js"/>
     16  <script src="chrome://mochikit/content/manifestLibrary.js" />
     17  <script src="chrome://mochikit/content/mochitestListingsUtils.js" />
     18  <script src="chrome://mochikit/content/chunkifyTests.js"/>
     19  <style xmlns="http://www.w3.org/1999/xhtml"><![CDATA[
     20    #results {
     21      margin: 5px;
     22      background-color: window;
     23      user-select: text;
     24    }
     25 
     26    #summary {
     27      color: white;
     28      border: 2px solid black;
     29    }
     30 
     31    #summary.success {
     32      background-color: #0d0;
     33    }
     34 
     35    #summary.failure {
     36      background-color: red;
     37    }
     38 
     39    #summary.todo {
     40      background-color: orange;
     41    }
     42 
     43    .info {
     44      color: grey;
     45    }
     46 
     47    .failed {
     48      color: red;
     49      font-weight: bold;
     50    }
     51 
     52    .testHeader {
     53      margin-top: 1em;
     54    }
     55 
     56    p {
     57      margin: 0.1em;
     58    }
     59 
     60    a {
     61      color: blue;
     62      text-decoration: underline;
     63    }
     64  ]]></style>
     65  <script type="application/javascript"><![CDATA[
     66    var gConfig;
     67 
     68    var gDumper = {
     69      get fileLogger() {
     70        let logger = null;
     71        if (gConfig.logFile) {
     72          try {
     73            logger = new MozillaFileLogger(gConfig.logFile)
     74          } catch (ex) {
     75            dump("TEST-UNEXPECTED-FAIL | (browser-harness.xhtml) | " +
     76                 "Error trying to log to " + gConfig.logFile + ": " + ex + "\n");
     77          }
     78        }
     79        delete this.fileLogger;
     80        return this.fileLogger = logger;
     81      },
     82      structuredLogger: TestRunner.structuredLogger,
     83      dump(str) {
     84        this.structuredLogger.info(str);
     85 
     86        if (this.fileLogger)
     87          this.fileLogger.log(str);
     88      },
     89 
     90      done() {
     91        if (this.fileLogger)
     92          this.fileLogger.close();
     93      }
     94    }
     95 
     96    function TestStart() {
     97      gConfig = readConfig();
     98 
     99      // Update the title for --start-at and --end-at.
    100      if (gConfig.startAt || gConfig.endAt)
    101        document.getElementById("runTestsButton").label =
    102          "Run subset of tests";
    103 
    104      if (gConfig.autorun)
    105        setTimeout(runTests, 0);
    106    }
    107 
    108    var gErrorCount = 0;
    109 
    110    function browserTest(aTestFile) {
    111      this.path = aTestFile.url;
    112      this.expected = aTestFile.expected;
    113      this.https_first_disabled = aTestFile.https_first_disabled || false;
    114      this.allow_xul_xbl = aTestFile.allow_xul_xbl || false;
    115      this.dumper = gDumper;
    116      this.results = [];
    117      this.scope = null;
    118      this.duration = 0;
    119      this.unexpectedTimeouts = 0;
    120      this.lastOutputTime = 0;
    121    }
    122    browserTest.prototype = {
    123      get passCount() {
    124        return this.results.filter(t => !t.info && !t.todo && t.pass).length;
    125      },
    126      get todoCount() {
    127        return this.results.filter(t => !t.info && t.todo && t.pass).length;
    128      },
    129      get failCount() {
    130        return this.results.filter(t => !t.info && !t.pass).length;
    131      },
    132      get allowedFailureCount() {
    133        return this.results.filter(t => t.allowedFailure).length;
    134      },
    135 
    136      addResult: function addResult(result) {
    137        this.lastOutputTime = Date.now();
    138        this.results.push(result);
    139 
    140        if (result.info) {
    141          if (result.msg) {
    142            ChromeUtils.addProfilerMarker("TEST-INFO", {category: "Test"},
    143                                          result.msg);
    144            this.dumper.structuredLogger.info(result.msg);
    145          }
    146          return;
    147        }
    148 
    149        // Use task name as subtest if available
    150        let subtest = this.scope?.SimpleTest?._currentTaskName || null;
    151 
    152        // Combine assertion name with exception details if present
    153        let message = result.name;
    154        if (result.msg) {
    155          message += " - " + result.msg;
    156        }
    157 
    158        this.dumper.structuredLogger.testStatus(this.path,
    159                                                subtest,
    160                                                result.status,
    161                                                result.expected,
    162                                                message,
    163                                                result.stack || null);
    164        let markerName = "TEST-";
    165        if (result.pass) {
    166          markerName += result.todo ? "KNOWN-FAIL" : "PASS";
    167        }
    168        else {
    169          markerName += "UNEXPECTED-" + result.status;
    170        }
    171        ChromeUtils.addProfilerMarker(markerName, {category: "Test"}, message);
    172      },
    173 
    174      setDuration: function setDuration(duration) {
    175        this.duration = duration;
    176      },
    177 
    178      get htmlLog() {
    179        let txtToHTML = Cc["@mozilla.org/txttohtmlconv;1"].
    180                        getService(Ci.mozITXTToHTMLConv);
    181        function _entityEncode(str) {
    182          return txtToHTML.scanTXT(str, Ci.mozITXTToHTMLConv.kEntities);
    183        }
    184        var path = _entityEncode(this.path);
    185        var html = this.results.map(function (t) {
    186          var classname = "result ";
    187          var result = "TEST-";
    188          if (t.info) {
    189            classname = "info";
    190            result += "INFO";
    191          }
    192          else if (t.pass) {
    193            classname += "passed";
    194            if (t.todo)
    195              result += "KNOWN-FAIL";
    196            else
    197              result += "PASS";
    198          }
    199          else {
    200            classname += "failed";
    201            result += "UNEXPECTED-" + t.status;
    202          }
    203          var message = t.name + (t.msg ? " - " + t.msg : "");
    204          var text = result + " | " + path + " | " + _entityEncode(message);
    205          if (!t.info && !t.pass) {
    206            return '<p class="' + classname + '" id=\"ERROR' + (gErrorCount++) + '">' +
    207                   text + " <a href=\"javascript:scrollTo('ERROR" + gErrorCount + "')\">NEXT ERROR</a></p>";
    208          }
    209          return '<p class="' + classname + '">' + text + "</p>";
    210        }).join("\n");
    211        if (this.duration) {
    212          html += "<p class=\"info\">TEST-END | " + path + " | finished in " +
    213                  this.duration + " ms</p>";
    214        }
    215        return html;
    216      }
    217    };
    218 
    219    // Returns an array of browserTest objects for all the selected tests
    220    function runTests() {
    221      gConfig.baseurl = "chrome://mochitests/content";
    222      getTestList(gConfig, loadTestList);
    223    }
    224 
    225    function loadTestList(links) {
    226      if (!links) {
    227        createTester({});
    228        return;
    229      }
    230 
    231      var fileNames = [];
    232      var fileNameRegexp = /browser_.+\.js$/;
    233      arrayOfTestFiles(links, fileNames, fileNameRegexp);
    234 
    235      if (gConfig.startAt || gConfig.endAt) {
    236        fileNames = skipTests(fileNames, gConfig.startAt, gConfig.endAt);
    237      }
    238 
    239      createTester(fileNames.map(function (f) { return new browserTest(f); }));
    240    }
    241 
    242    function setStatus(aStatusString) {
    243      document.getElementById("status").value = aStatusString;
    244    }
    245 
    246    function createTester(links) {
    247      var winType = null;
    248      if (gConfig.testRoot == "browser") {
    249        const IS_THUNDERBIRD = Services.appinfo.ID == "{3550f703-e582-4d05-9a08-453d09bdfdc6}";
    250        winType = IS_THUNDERBIRD ? "mail:3pane" : "navigator:browser";
    251      }
    252      if (!winType) {
    253        throw new Error("Unrecognized gConfig.testRoot: " + gConfig.testRoot);
    254      }
    255      var testWin = Services.wm.getMostRecentWindow(winType);
    256 
    257      setStatus("Running...");
    258 
    259      // It's possible that the test harness window is not yet focused when this
    260      // function runs (in which case testWin is already focused, and focusing it
    261      // will be a no-op, and then the test harness window will steal focus later,
    262      // which will mess up tests). So wait for the test harness window to be
    263      // focused before trying to focus testWin.
    264      waitForFocus(() => {
    265        // Focus the test window and start tests.
    266        waitForFocus(() => {
    267          var Tester = new testWin.Tester(links, gDumper.structuredLogger, testsFinished);
    268          Tester.start();
    269        }, testWin);
    270      }, window);
    271    }
    272 
    273    function executeSoon(callback) {
    274      Services.tm.dispatchToMainThread(callback);
    275    }
    276 
    277    function waitForFocus(callback, win) {
    278      // If "win" is already focused, just call the callback.
    279      if (Services.focus.focusedWindow == win) {
    280        executeSoon(callback);
    281        return;
    282      }
    283 
    284      // Otherwise focus it, and wait for the focus event.
    285      win.addEventListener("focus", function listener() {
    286        executeSoon(callback);
    287      }, { capture: true, once: true});
    288      win.focus();
    289    }
    290 
    291    function sum(a, b) {
    292      return a + b;
    293    }
    294 
    295    function getHTMLLogFromTests(aTests) {
    296      if (!aTests.length)
    297        return "<div id=\"summary\" class=\"failure\">No tests to run." +
    298                 " Did you pass an invalid --test-path?</div>";
    299 
    300      var log = "";
    301 
    302      var passCount = aTests.map(f => f.passCount).reduce(sum);
    303      var failCount = aTests.map(f => f.failCount).reduce(sum);
    304      var todoCount = aTests.map(f => f.todoCount).reduce(sum);
    305      log += "<div id=\"summary\" class=\"";
    306      if (failCount != 0) {
    307        log += "failure";
    308      } else {
    309        log += passCount == 0 ? "todo" : "success";
    310      }
    311      log += "\">\n<p>Passed: " + passCount + "</p>\n" +
    312             "<p>Failed: " + failCount;
    313      if (failCount > 0)
    314        log += " <a href=\"javascript:scrollTo('ERROR0')\">NEXT ERROR</a>";
    315      log += "</p>\n" +
    316             "<p>Todo: " + todoCount + "</p>\n</div>\n<div id=\"log\">\n";
    317 
    318      return log + aTests.map(function (f) {
    319                                return "<p class=\"testHeader\">Running " + f.path + "...</p>\n" + f.htmlLog;
    320                              }).join("\n") + "</div>";
    321    }
    322 
    323    function testsFinished(aTests) {
    324      if (gConfig.closeWhenDone) {
    325        const {AppConstants} = ChromeUtils.importESModule(
    326          "resource://gre/modules/AppConstants.sys.mjs"
    327        );
    328        if (
    329          !AppConstants.RELEASE_OR_BETA &&
    330          !AppConstants.DEBUG &&
    331          !AppConstants.MOZ_CODE_COVERAGE &&
    332          !AppConstants.ASAN &&
    333          !AppConstants.TSAN
    334        ) {
    335          let filename =
    336            Services.profiler.IsActive() &&
    337            Services.env.get("MOZ_PROFILER_SHUTDOWN");
    338          if (!filename) {
    339            Cu.exitIfInAutomation();
    340          }
    341          Services.profiler
    342            .dumpProfileToFileAsync(filename)
    343            .then(() => Services.profiler.StopProfiler())
    344            .then(() => Cu.exitIfInAutomation());
    345        } else {
    346          Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
    347        }
    348        return;
    349      }
    350 
    351      // Focus our window, to display the results
    352      window.focus();
    353 
    354      // UI
    355      // eslint-disable-next-line no-unsanitized/property
    356      document.getElementById("results").innerHTML = getHTMLLogFromTests(aTests);
    357      setStatus("Done.");
    358    }
    359 
    360    function scrollTo(id) {
    361      var line = document.getElementById(id);
    362      if (!line)
    363        return;
    364 
    365      line.scrollIntoView();
    366    }
    367  ]]></script>
    368  <button id="runTestsButton" oncommand="runTests();" label="Run All Tests"/>
    369  <label id="status"/>
    370  <scrollbox flex="1" style="overflow: auto" align="stretch">
    371    <div id="results" xmlns="http://www.w3.org/1999/xhtml" flex="1"/>
    372  </scrollbox>
    373 </window>