Bug 1041706 - Mochitests prints raw JSON logs when running with a debugger. r=ahal
authorAhmed Kachkach <ahmed.kachkach@gmail.com>
Wed, 23 Jul 2014 15:31:00 +0200
changeset 217455 f0b4070ebc822aad0d5bb30472acd615104d1205
parent 217454 55b20adc6177bf8d6c8c8a4efa319ec0e51c74a8
child 217456 7ec48291f26a726f0a585be9c13e4992ea68628c
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersahal
bugs1041706
milestone34.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 1041706 - Mochitests prints raw JSON logs when running with a debugger. r=ahal
testing/mochitest/runtests.py
testing/mochitest/tests/SimpleTest/TestRunner.js
testing/mochitest/tests/SimpleTest/setup.js
testing/specialpowers/content/MozillaLogger.js
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -509,16 +509,18 @@ class MochitestUtilsMixin(object):
       if options.debugOnFailure:
         self.urlOpts.append("debugOnFailure=true")
       if options.dumpOutputDirectory:
         self.urlOpts.append("dumpOutputDirectory=%s" % encodeURIComponent(options.dumpOutputDirectory))
       if options.dumpAboutMemoryAfterTest:
         self.urlOpts.append("dumpAboutMemoryAfterTest=true")
       if options.dumpDMDAfterTest:
         self.urlOpts.append("dumpDMDAfterTest=true")
+      if options.debugger:
+        self.urlOpts.append("interactiveDebugger=true")
 
   def getTestFlavor(self, options):
     if options.browserChrome:
       return "browser-chrome"
     elif options.chrome:
       return "chrome"
     elif options.a11y:
       return "a11y"
--- a/testing/mochitest/tests/SimpleTest/TestRunner.js
+++ b/testing/mochitest/tests/SimpleTest/TestRunner.js
@@ -60,27 +60,81 @@ function flattenArguments(lst/* ...*/) {
             }
         } else {
             res.push(o);
         }
     }
     return res;
 }
 
+/**
+ * StructuredFormatter: Formatter class turning structured messages
+ * into human-readable messages.
+ */
+this.StructuredFormatter = function() {
+    this.testStartTimes = {};
+};
+
+StructuredFormatter.prototype.log = function(message) {
+  return message.message;
+};
+
+StructuredFormatter.prototype.suite_start = function(message) {
+    this.suiteStartTime = message.time;
+    return "SUITE-START | Running " +  message.tests.length + " tests";
+};
+
+StructuredFormatter.prototype.test_start = function(message) {
+    this.testStartTimes[message.test] = new Date().getTime();
+    return "TEST-START | " + message.test;
+};
+
+StructuredFormatter.prototype.test_status = function(message) {
+    var statusInfo = message.test + " | " + message.subtest +
+                    (message.message ? " | " + message.message : "");
+    if (message.expected) {
+        return "TEST-UNEXPECTED-" + message.status + " | " + statusInfo +
+               " - expected: " + message.expected;
+    } else {
+        return "TEST-" + message.status + " | " + statusInfo;
+    }
+};
+
+StructuredFormatter.prototype.test_end = function(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 = " | took " + message.time - startTime + "ms";
+};
+
+StructuredFormatter.prototype.suite_end = function(message) {
+    return "SUITE-END | took " + message.time - this.suiteStartTime + "ms";
+};
 
 /**
  * StructuredLogger: Structured logger class following the mozlog.structured protocol
  *
  *
 **/
 var VALID_ACTIONS = ['suite_start', 'suite_end', 'test_start', 'test_end', 'test_status', 'process_output', 'log'];
+// This delimiter is used to avoid interleaving Mochitest/Gecko logs.
+var LOG_DELIMITER = String.fromCharCode(0xe175) + String.fromCharCode(0xee31) + String.fromCharCode(0x2c32) + String.fromCharCode(0xacbf);
 
 function StructuredLogger(name) {
     this.name = name;
     this.testsStarted = [];
+    this.interactiveDebugger = false;
+    this.structuredFormatter = new StructuredFormatter();
 
     /* test logs */
 
     this.testStart = function(test) {
         var data = {test: test};
         this._logData("test_start", data);
     };
 
@@ -196,17 +250,22 @@ function StructuredLogger(name) {
         for (var attrname in data) {
             allData[attrname] = data[attrname];
         }
 
         this._dumpMessage(allData);
     };
 
     this._dumpMessage = function(message) {
-        var str = JSON.stringify(message);
+        var str;
+        if (this.interactiveDebugger) {
+            str = this.structuredFormatter[message.action](message);
+        } else {
+            str = LOG_DELIMITER + JSON.stringify(message) + LOG_DELIMITER;
+        }
         // BUGFIX: browser-chrome tests doesn't use LogController
         if (Object.keys(LogController.listeners).length !== 0) {
             LogController.log(str);
         } else {
             dump('\n' + str + '\n');
         }
     };
 
--- a/testing/mochitest/tests/SimpleTest/setup.js
+++ b/testing/mochitest/tests/SimpleTest/setup.js
@@ -130,20 +130,23 @@ if (params.dumpOutputDirectory) {
 if (params.dumpAboutMemoryAfterTest) {
   TestRunner.dumpAboutMemoryAfterTest = true;
 }
 
 if (params.dumpDMDAfterTest) {
   TestRunner.dumpDMDAfterTest = true;
 }
 
+if (params.interactiveDebugger) {
+  TestRunner.structuredLogger.interactiveDebugger = true;
+}
+
 // Log things to the console if appropriate.
 TestRunner.logger.addListener("dumpListener", consoleLevel + "", function(msg) {
-  var data = formatLogMessage(msg);
-  dump(data);
+  dump(msg.info.join(' ') + "\n");
 });
 
 var gTestList = [];
 var RunSet = {};
 RunSet.runall = function(e) {
   // Filter tests to include|exclude tests based on data in params.filter.
   // This allows for including or excluding tests from the gTestList
   if (params.testManifest) {
--- a/testing/specialpowers/content/MozillaLogger.js
+++ b/testing/specialpowers/content/MozillaLogger.js
@@ -1,20 +1,19 @@
 /**
  * MozillaLogger, a base class logger that just logs to stdout.
  */
 
 "use strict";
 
 function MozillaLogger(aPath) {
 }
-// This delimiter is used to avoid interleaving Mochitest/Gecko logs.
-var LOG_DELIMITER = String.fromCharCode(0xe175) + String.fromCharCode(0xee31) + String.fromCharCode(0x2c32) + String.fromCharCode(0xacbf);
+
 function formatLogMessage(msg) {
-    return LOG_DELIMITER + msg.info.join(' ') + LOG_DELIMITER + "\n";
+    return msg.info.join(' ') + "\n";
 }
 
 MozillaLogger.prototype = {
   init : function(path) {},
 
   getLogCallback : function() {
     return function (msg) {
       var data = formatLogMessage(msg);