Bug 1209463 - [mozlog] Add a 'summary_on_shutdown' attribute to MachFormatter, r?jgraham draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 29 Nov 2017 12:02:19 -0500
changeset 707173 6e3cfe1e3c0e4063ac2d867942867b207f0dfcf7
parent 707172 4a34fffe66b435632ec89126bc7afbc66dc51a7c
child 707174 c4765e815bc628aace4ae551d932ff9b1736f5f4
push id92023
push userahalberstadt@mozilla.com
push dateMon, 04 Dec 2017 21:11:24 +0000
reviewersjgraham
bugs1209463
milestone59.0a1
Bug 1209463 - [mozlog] Add a 'summary_on_shutdown' attribute to MachFormatter, r?jgraham When 'summary_on_shutdown' is True (which is the case for |mach test| and |mach mochitest|), BaseSummaryFormatters will save the summary information until the 'shutdown' action is received at the end of the logger's lifetime. Summary information will no longer be dumped on 'suite_end'. MozReview-Commit-ID: HKtVr5PxfOy
testing/mach_commands.py
testing/mochitest/mach_commands.py
testing/mozbase/mozlog/mozlog/formatters/machformatter.py
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -111,16 +111,17 @@ class Test(MachCommandBase):
         run_suites, run_tests = resolver.resolve_metadata(what)
 
         if not run_suites and not run_tests:
             print(UNKNOWN_TEST)
             return 1
 
         # Create shared logger
         formatter = log_formatters[self._mach_context.settings['test']['format']][0]()
+        formatter.summary_on_shutdown = True
 
         level = self._mach_context.settings['test']['level']
         log = StructuredLogger('mach-test')
         log.add_handler(StreamHandler(sys.stdout, LogLevelFilter(formatter, level)))
 
         status = None
         for suite_name in run_suites:
             suite = TEST_SUITES[suite_name]
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -305,16 +305,18 @@ class MachCommands(MachCommandBase):
                     flavors = [fname]
                     break
         else:
             flavors = [f for f, v in ALL_FLAVORS.iteritems() if buildapp in v['enabled_apps']]
 
         if not kwargs.get('log'):
             # Create shared logger
             formatter = log_formatters[self._mach_context.settings['test']['format']][0]()
+            formatter.summary_on_shutdown = True
+
             level = self._mach_context.settings['test']['level']
             kwargs['log'] = StructuredLogger('mach-mochitest')
             kwargs['log'].add_handler(StreamHandler(sys.stdout, LogLevelFilter(formatter, level)))
 
         from mozbuild.controller.building import BuildDriver
         self._ensure_state_subdir_exists('.')
 
         test_paths = kwargs['test_paths']
--- a/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
@@ -30,17 +30,17 @@ class NullTerminal(object):
 
     def _id(self, value):
         return value
 
 
 class MachFormatter(base.BaseFormatter):
 
     def __init__(self, start_time=None, write_interval=False, write_times=True,
-                 terminal=None, disable_colors=False, **kwargs):
+                 terminal=None, disable_colors=False, summary_on_shutdown=False, **kwargs):
         super(MachFormatter, self).__init__(**kwargs)
 
         if disable_colors:
             terminal = None
         elif terminal is None and blessings is not None:
             terminal = blessings.Terminal()
 
         if start_time is None:
@@ -52,16 +52,17 @@ class MachFormatter(base.BaseFormatter):
         self.status_buffer = {}
         self.has_unexpected = {}
         self.last_time = None
         self.terminal = terminal
         self.verbose = False
         self._known_pids = set()
 
         self.summary = SummaryHandler()
+        self.summary_on_shutdown = summary_on_shutdown
 
     def __call__(self, data):
         self.summary(data)
 
         s = super(MachFormatter, self).__call__(data)
         if s is None:
             return
 
@@ -113,17 +114,18 @@ class MachFormatter(base.BaseFormatter):
 
         assert False, "unexpected test_id"
 
     def suite_start(self, data):
         num_tests = reduce(lambda x, y: x + len(y), data['tests'].itervalues(), 0)
         return "%i" % num_tests
 
     def suite_end(self, data):
-        return self._format_suite_summary(self.summary.current_suite, self.summary.current)
+        if not self.summary_on_shutdown:
+            return self._format_suite_summary(self.summary.current_suite, self.summary.current)
 
     def _format_expected(self, status, expected):
         term = self.terminal if self.terminal is not None else NullTerminal()
         if status == "ERROR":
             color = term.red
         else:
             color = term.yellow
 
@@ -382,16 +384,26 @@ class MachFormatter(base.BaseFormatter):
             level=data["level"],
             message=data["message"],
             rule='{} '.format(data["rule"]) if data.get("rule") else "",
             linter=data["linter"].lower() if data.get("linter") else "",
         )
 
         return message
 
+    def shutdown(self, data):
+        if not self.summary_on_shutdown:
+            return
+
+        heading = "Overall Summary"
+        rv = ["", heading, "=" * len(heading)]
+        for suite, summary in self.summary:
+            rv.append(self._format_suite_summary(suite, summary))
+        return "\n".join(rv)
+
     def _get_subtest_data(self, data):
         test = self._get_test_id(data)
         return self.status_buffer.get(test, {"count": 0, "unexpected": 0, "pass": 0})
 
     def _time(self, data):
         entry_time = data["time"]
         if self.write_interval and self.last_time is not None:
             t = entry_time - self.last_time