forked from mirrors/gecko-dev
		
	 5fc9f15115
			
		
	
	
		5fc9f15115
		
	
	
	
	
		
			
			Reftest-family test suites can be "run-by-manifest" (reftest-plain, on desktop), or not (all reftest-family suites on Android, crashtest and jsreftest on desktop). When not run-by-manifest, code in reftest.jsm is used to format the suite_start data; when run-by-manifest, code in runreftest.py is used. Currently, the reftest.jsm implementation submits a simple array of test IDs -- no associated manifests -- possibly consistent with the concept that tests are not being run/grouped by manifest. This patch updates the reftest.jsm implementation to generate the same format of suite_start data as the python implementation: An array of dictionaries mapping manifest IDs to arrays of associated test IDs. Differential Revision: https://phabricator.services.mozilla.com/D63875 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			299 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| var EXPORTED_SYMBOLS = ["StructuredLogger", "StructuredFormatter"];
 | |
| 
 | |
| /**
 | |
|  * TestLogger: Logger class generating messages compliant with the
 | |
|  * structured logging protocol for tests exposed by mozlog
 | |
|  *
 | |
|  * @param name
 | |
|  *        The name of the logger to instantiate.
 | |
|  * @param dumpFun
 | |
|  *        An underlying function to be used to log raw messages. This function
 | |
|  *        will receive the complete serialized json string to log.
 | |
|  * @param mutators
 | |
|  *        An array of functions used to add global context to log messages.
 | |
|  *        These will each be called with the complete object to log as an
 | |
|  *        argument.
 | |
|  */
 | |
| var StructuredLogger = function(name, dumpFun = dump, mutators = []) {
 | |
|   this.name = name;
 | |
|   this._dumpFun = dumpFun;
 | |
|   this._mutatorFuns = mutators;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Log functions producing messages in the format specified by mozlog
 | |
|  */
 | |
| StructuredLogger.prototype = {
 | |
|   testStart(test) {
 | |
|     var data = { test: this._testId(test) };
 | |
|     this._logData("test_start", data);
 | |
|   },
 | |
| 
 | |
|   testStatus(
 | |
|     test,
 | |
|     subtest,
 | |
|     status,
 | |
|     expected = "PASS",
 | |
|     message = null,
 | |
|     stack = null,
 | |
|     extra = null
 | |
|   ) {
 | |
|     if (subtest === null || subtest === undefined) {
 | |
|       // Fix for assertions that don't pass in a name
 | |
|       subtest = "undefined assertion name";
 | |
|     }
 | |
| 
 | |
|     var data = {
 | |
|       test: this._testId(test),
 | |
|       subtest,
 | |
|       status,
 | |
|     };
 | |
| 
 | |
|     if (expected != status && status != "SKIP") {
 | |
|       data.expected = expected;
 | |
|     }
 | |
|     if (message !== null) {
 | |
|       data.message = String(message);
 | |
|     }
 | |
|     if (stack !== null) {
 | |
|       data.stack = stack;
 | |
|     }
 | |
|     if (extra !== null) {
 | |
|       data.extra = extra;
 | |
|     }
 | |
| 
 | |
|     this._logData("test_status", data);
 | |
|   },
 | |
| 
 | |
|   testEnd(
 | |
|     test,
 | |
|     status,
 | |
|     expected = "OK",
 | |
|     message = null,
 | |
|     stack = null,
 | |
|     extra = null
 | |
|   ) {
 | |
|     var data = { test: this._testId(test), status };
 | |
| 
 | |
|     if (expected != status && status != "SKIP") {
 | |
|       data.expected = expected;
 | |
|     }
 | |
|     if (message !== null) {
 | |
|       data.message = String(message);
 | |
|     }
 | |
|     if (stack !== null) {
 | |
|       data.stack = stack;
 | |
|     }
 | |
|     if (extra !== null) {
 | |
|       data.extra = extra;
 | |
|     }
 | |
| 
 | |
|     this._logData("test_end", data);
 | |
|   },
 | |
| 
 | |
|   assertionCount(test, count, minExpected = 0, maxExpected = 0) {
 | |
|     var data = {
 | |
|       test: this._testId(test),
 | |
|       min_expected: minExpected,
 | |
|       max_expected: maxExpected,
 | |
|       count,
 | |
|     };
 | |
| 
 | |
|     this._logData("assertion_count", data);
 | |
|   },
 | |
| 
 | |
|   suiteStart(
 | |
|     ids,
 | |
|     name = null,
 | |
|     runinfo = null,
 | |
|     versioninfo = null,
 | |
|     deviceinfo = null,
 | |
|     extra = null
 | |
|   ) {
 | |
|     Object.keys(ids).map(function(manifest) {
 | |
|       ids[manifest] = ids[manifest].map(x => this._testId(x));
 | |
|     }, this);
 | |
|     var data = { tests: ids };
 | |
| 
 | |
|     if (name !== null) {
 | |
|       data.name = name;
 | |
|     }
 | |
| 
 | |
|     if (runinfo !== null) {
 | |
|       data.runinfo = runinfo;
 | |
|     }
 | |
| 
 | |
|     if (versioninfo !== null) {
 | |
|       data.versioninfo = versioninfo;
 | |
|     }
 | |
| 
 | |
|     if (deviceinfo !== null) {
 | |
|       data.deviceinfo = deviceinfo;
 | |
|     }
 | |
| 
 | |
|     if (extra !== null) {
 | |
|       data.extra = extra;
 | |
|     }
 | |
| 
 | |
|     this._logData("suite_start", data);
 | |
|   },
 | |
| 
 | |
|   suiteEnd(extra = null) {
 | |
|     var data = {};
 | |
| 
 | |
|     if (extra !== null) {
 | |
|       data.extra = extra;
 | |
|     }
 | |
| 
 | |
|     this._logData("suite_end", data);
 | |
|   },
 | |
| 
 | |
|   /**
 | |
|    * Unstructured logging functions. The "extra" parameter can always by used to
 | |
|    * log suite specific data. If a "stack" field is provided it is logged at the
 | |
|    * top level of the data object for the benefit of mozlog's formatters.
 | |
|    */
 | |
|   log(level, message, extra = null) {
 | |
|     var data = {
 | |
|       level,
 | |
|       message: String(message),
 | |
|     };
 | |
| 
 | |
|     if (extra !== null) {
 | |
|       data.extra = extra;
 | |
|       if ("stack" in extra) {
 | |
|         data.stack = extra.stack;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     this._logData("log", data);
 | |
|   },
 | |
| 
 | |
|   debug(message, extra = null) {
 | |
|     this.log("DEBUG", message, extra);
 | |
|   },
 | |
| 
 | |
|   info(message, extra = null) {
 | |
|     this.log("INFO", message, extra);
 | |
|   },
 | |
| 
 | |
|   warning(message, extra = null) {
 | |
|     this.log("WARNING", message, extra);
 | |
|   },
 | |
| 
 | |
|   error(message, extra = null) {
 | |
|     this.log("ERROR", message, extra);
 | |
|   },
 | |
| 
 | |
|   critical(message, extra = null) {
 | |
|     this.log("CRITICAL", message, extra);
 | |
|   },
 | |
| 
 | |
|   processOutput(thread, message) {
 | |
|     this._logData("process_output", {
 | |
|       message,
 | |
|       thread,
 | |
|     });
 | |
|   },
 | |
| 
 | |
|   _logData(action, data = {}) {
 | |
|     var allData = {
 | |
|       action,
 | |
|       time: Date.now(),
 | |
|       thread: null,
 | |
|       pid: null,
 | |
|       source: this.name,
 | |
|     };
 | |
| 
 | |
|     for (var field in data) {
 | |
|       allData[field] = data[field];
 | |
|     }
 | |
| 
 | |
|     for (var fun of this._mutatorFuns) {
 | |
|       fun(allData);
 | |
|     }
 | |
| 
 | |
|     this._dumpFun(allData);
 | |
|   },
 | |
| 
 | |
|   _testId(test) {
 | |
|     if (Array.isArray(test)) {
 | |
|       return test.join(" ");
 | |
|     }
 | |
|     return test;
 | |
|   },
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * StructuredFormatter: Formatter class turning structured messages
 | |
|  * into human-readable messages.
 | |
|  */
 | |
| var StructuredFormatter = function() {
 | |
|   this.testStartTimes = {};
 | |
| };
 | |
| 
 | |
| StructuredFormatter.prototype = {
 | |
|   log(message) {
 | |
|     return message.message;
 | |
|   },
 | |
| 
 | |
|   suite_start(message) {
 | |
|     this.suiteStartTime = message.time;
 | |
|     return "SUITE-START | Running " + message.tests.length + " tests";
 | |
|   },
 | |
| 
 | |
|   test_start(message) {
 | |
|     this.testStartTimes[message.test] = new Date().getTime();
 | |
|     return "TEST-START | " + message.test;
 | |
|   },
 | |
| 
 | |
|   test_status(message) {
 | |
|     var statusInfo =
 | |
|       message.test +
 | |
|       " | " +
 | |
|       message.subtest +
 | |
|       (message.message ? " | " + message.message : "");
 | |
|     if (message.expected) {
 | |
|       return (
 | |
|         "TEST-UNEXPECTED-" +
 | |
|         message.status +
 | |
|         " | " +
 | |
|         statusInfo +
 | |
|         " - expected: " +
 | |
|         message.expected
 | |
|       );
 | |
|     }
 | |
|     return "TEST-" + message.status + " | " + statusInfo;
 | |
|   },
 | |
| 
 | |
|   test_end(message) {
 | |
|     var startTime = this.testStartTimes[message.test];
 | |
|     delete this.testStartTimes[message.test];
 | |
|     var statusInfo =
 | |
|       message.test + (message.message ? " | " + String(message.message) : "");
 | |
|     var result;
 | |
|     if (message.expected) {
 | |
|       result =
 | |
|         "TEST-UNEXPECTED-" +
 | |
|         message.status +
 | |
|         " | " +
 | |
|         statusInfo +
 | |
|         " - expected: " +
 | |
|         message.expected;
 | |
|     } else {
 | |
|       return "TEST-" + message.status + " | " + statusInfo;
 | |
|     }
 | |
|     result = result + " | took " + message.time - startTime + "ms";
 | |
|     return result;
 | |
|   },
 | |
| 
 | |
|   suite_end(message) {
 | |
|     return "SUITE-END | took " + message.time - this.suiteStartTime + "ms";
 | |
|   },
 | |
| };
 |