1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Redistribution and use in source and binary forms, with or without
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# modification, are permitted provided that the following conditions are
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# met:
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Redistributions of source code must retain the above copyright
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       notice, this list of conditions and the following disclaimer.
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Redistributions in binary form must reproduce the above
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       copyright notice, this list of conditions and the following
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       disclaimer in the documentation and/or other materials provided
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       with the distribution.
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#     * Neither the name of Google Inc. nor the names of its
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       contributors may be used to endorse or promote products derived
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#       from this software without specific prior written permission.
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfrom functools import wraps
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport json
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport os
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport sys
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport time
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfrom . import execution
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfrom . import junit_output
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochABS_PATH_PREFIX = os.getcwd() + os.sep
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ProgressIndicator(object):
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def __init__(self):
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.runner = None
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
47014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def SetRunner(self, runner):
48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.runner = runner
49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Starting(self):
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pass
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Done(self):
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pass
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def AboutToRun(self, test):
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pass
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    pass
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
62014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def Heartbeat(self):
63014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    pass
64014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def PrintFailureHeader(self, test):
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if test.suite.IsNegativeTest(test):
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      negative_marker = '[negative] '
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      negative_marker = ''
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print "=== %(label)s %(negative)s===" % {
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'label': test.GetLabel(),
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'negative': negative_marker
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
75014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def _EscapeCommand(self, test):
76014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    command = execution.GetCommand(test, self.runner.context)
77014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    parts = []
78014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    for part in command:
79014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if ' ' in part:
80014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        # Escape spaces.  We may need to escape more characters for this
81014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        # to work properly.
82014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        parts.append('"%s"' % part)
83014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      else:
84014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        parts.append(part)
85014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return " ".join(parts)
86014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
87014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
88014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochclass IndicatorNotifier(object):
89014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  """Holds a list of progress indicators and notifies them all on events."""
90014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def __init__(self):
91014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.indicators = []
92014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
93014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def Register(self, indicator):
94014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.indicators.append(indicator)
95014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
96014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
97014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# Forge all generic event-dispatching methods in IndicatorNotifier, which are
98014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# part of the ProgressIndicator interface.
99014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochfor func_name in ProgressIndicator.__dict__:
100014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  func = getattr(ProgressIndicator, func_name)
101014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if callable(func) and not func.__name__.startswith('_'):
102014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    def wrap_functor(f):
103014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      @wraps(f)
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      def functor(self, *args, **kwargs):
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        """Generic event dispatcher."""
106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        for indicator in self.indicators:
107014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          getattr(indicator, f.__name__)(*args, **kwargs)
108014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      return functor
109014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    setattr(IndicatorNotifier, func_name, wrap_functor(func))
110014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass SimpleProgressIndicator(ProgressIndicator):
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  """Abstract base class for {Verbose,Dots}ProgressIndicator"""
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Starting(self):
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print 'Running %i tests' % self.runner.total
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Done(self):
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    for failed in self.runner.failed:
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.PrintFailureHeader(failed)
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if failed.output.stderr:
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- stderr ---"
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print failed.output.stderr.strip()
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if failed.output.stdout:
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- stdout ---"
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print failed.output.stdout.strip()
128014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      print "Command: %s" % self._EscapeCommand(failed)
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if failed.output.HasCrashed():
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "exit code: %d" % failed.output.exit_code
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- CRASHED ---"
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if failed.output.HasTimedOut():
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- TIMEOUT ---"
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if len(self.runner.failed) == 0:
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "==="
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "=== All tests succeeded"
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "==="
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "==="
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "=== %i tests failed" % len(self.runner.failed)
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if self.runner.crashed > 0:
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "=== %i tests CRASHED" % self.runner.crashed
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print "==="
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass VerboseProgressIndicator(SimpleProgressIndicator):
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def AboutToRun(self, test):
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print 'Starting %s...' % test.GetLabel()
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    sys.stdout.flush()
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if has_unexpected_output:
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasCrashed():
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        outcome = 'CRASH'
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      else:
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        outcome = 'FAIL'
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      outcome = 'pass'
161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print 'Done running %s: %s' % (test.GetLabel(), outcome)
162014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    sys.stdout.flush()
163014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
164014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def Heartbeat(self):
165014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    print 'Still working...'
166014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    sys.stdout.flush()
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass DotsProgressIndicator(SimpleProgressIndicator):
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    total = self.runner.succeeded + len(self.runner.failed)
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (total > 1) and (total % 50 == 1):
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      sys.stdout.write('\n')
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if has_unexpected_output:
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasCrashed():
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.write('C')
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.flush()
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      elif test.output.HasTimedOut():
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.write('T')
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.flush()
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      else:
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.write('F')
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        sys.stdout.flush()
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      sys.stdout.write('.')
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      sys.stdout.flush()
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass CompactProgressIndicator(ProgressIndicator):
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  """Abstract base class for {Color,Monochrome}ProgressIndicator"""
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def __init__(self, templates):
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    super(CompactProgressIndicator, self).__init__()
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.templates = templates
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.last_status_length = 0
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.start_time = time.time()
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Done(self):
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.PrintProgress('Done')
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print ""  # Line break.
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def AboutToRun(self, test):
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.PrintProgress(test.GetLabel())
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if has_unexpected_output:
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.ClearLine(self.last_status_length)
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.PrintFailureHeader(test)
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stdout = test.output.stdout.strip()
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if len(stdout):
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print self.templates['stdout'] % stdout
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stderr = test.output.stderr.strip()
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if len(stderr):
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print self.templates['stderr'] % stderr
216014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      print "Command: %s" % self._EscapeCommand(test)
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasCrashed():
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "exit code: %d" % test.output.exit_code
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- CRASHED ---"
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasTimedOut():
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print "--- TIMEOUT ---"
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Truncate(self, string, length):
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if length and (len(string) > (length - 3)):
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return string[:(length - 3)] + "..."
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return string
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def PrintProgress(self, name):
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.ClearLine(self.last_status_length)
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    elapsed = time.time() - self.start_time
232014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    progress = 0 if not self.runner.total else (
233014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        ((self.runner.total - self.runner.remaining) * 100) //
234014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch          self.runner.total)
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    status = self.templates['status_line'] % {
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'passed': self.runner.succeeded,
237014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'progress': progress,
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'failed': len(self.runner.failed),
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'test': name,
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'mins': int(elapsed) / 60,
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'secs': int(elapsed) % 60
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    status = self.Truncate(status, 78)
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.last_status_length = len(status)
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print status,
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    sys.stdout.flush()
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass ColorProgressIndicator(CompactProgressIndicator):
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def __init__(self):
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    templates = {
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'status_line': ("[%(mins)02i:%(secs)02i|"
254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                      "\033[34m%%%(progress) 4d\033[0m|"
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                      "\033[32m+%(passed) 4d\033[0m|"
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                      "\033[31m-%(failed) 4d\033[0m]: %(test)s"),
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'stdout': "\033[1m%s\033[0m",
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'stderr': "\033[31m%s\033[0m",
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    super(ColorProgressIndicator, self).__init__(templates)
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def ClearLine(self, last_line_length):
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print "\033[1K\r",
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass MonochromeProgressIndicator(CompactProgressIndicator):
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def __init__(self):
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    templates = {
270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      'status_line': ("[%(mins)02i:%(secs)02i|%%%(progress) 4d|"
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                      "+%(passed) 4d|-%(failed) 4d]: %(test)s"),
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'stdout': '%s',
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      'stderr': '%s',
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    super(MonochromeProgressIndicator, self).__init__(templates)
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def ClearLine(self, last_line_length):
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print ("\r" + (" " * last_line_length) + "\r"),
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass JUnitTestProgressIndicator(ProgressIndicator):
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
283014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def __init__(self, junitout, junittestsuite):
284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.outputter = junit_output.JUnitTestOutput(junittestsuite)
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if junitout:
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.outfile = open(junitout, "w")
287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.outfile = sys.stdout
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Done(self):
291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.outputter.FinishAndWrite(self.outfile)
292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if self.outfile != sys.stdout:
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.outfile.close()
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    fail_text = ""
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if has_unexpected_output:
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stdout = test.output.stdout.strip()
299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if len(stdout):
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        fail_text += "stdout:\n%s\n" % stdout
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      stderr = test.output.stderr.strip()
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if len(stderr):
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        fail_text += "stderr:\n%s\n" % stderr
304014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      fail_text += "Command: %s" % self._EscapeCommand(test)
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasCrashed():
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if test.output.HasTimedOut():
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        fail_text += "--- TIMEOUT ---"
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.outputter.HasRunTest(
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        [test.GetLabel()] + self.runner.context.mode_flags + test.flags,
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        test.duration,
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        fail_text)
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochclass JsonTestProgressIndicator(ProgressIndicator):
316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
317014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def __init__(self, json_test_results, arch, mode, random_seed):
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.json_test_results = json_test_results
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.arch = arch
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.mode = mode
321014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.random_seed = random_seed
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.results = []
323014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.tests = []
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def Done(self):
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    complete_results = []
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if os.path.exists(self.json_test_results):
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      with open(self.json_test_results, "r") as f:
329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        # Buildbot might start out with an empty file.
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        complete_results = json.loads(f.read() or "[]")
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
332014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    # Sort tests by duration.
333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    timed_tests = [t for t in self.tests if t.duration is not None]
334014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    timed_tests.sort(lambda a, b: cmp(b.duration, a.duration))
335014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    slowest_tests = [
336014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      {
337014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        "name": test.GetLabel(),
338014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        "flags": test.flags,
339014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        "command": self._EscapeCommand(test).replace(ABS_PATH_PREFIX, ""),
340014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        "duration": test.duration,
341014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      } for test in timed_tests[:20]
342014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    ]
343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    complete_results.append({
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "arch": self.arch,
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "mode": self.mode,
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "results": self.results,
348014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "slowest_tests": slowest_tests,
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    })
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    with open(self.json_test_results, "w") as f:
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      f.write(json.dumps(complete_results))
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  def HasRun(self, test, has_unexpected_output):
355014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    # Buffer all tests for sorting the durations in the end.
356014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    self.tests.append(test)
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if not has_unexpected_output:
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      # Omit tests that run as expected. Passing tests of reruns after failures
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      # will have unexpected_output to be reported here has well.
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    self.results.append({
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "name": test.GetLabel(),
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "flags": test.flags,
365014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "command": self._EscapeCommand(test).replace(ABS_PATH_PREFIX, ""),
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "run": test.run,
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "stdout": test.output.stdout,
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "stderr": test.output.stderr,
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "exit_code": test.output.exit_code,
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "result": test.suite.GetOutcome(test),
371958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      "expected": list(test.outcomes or ["PASS"]),
372014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "duration": test.duration,
373014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
374014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      # TODO(machenbach): This stores only the global random seed from the
375014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      # context and not possible overrides when using random-seed stress.
376014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "random_seed": self.random_seed,
377014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "target_name": test.suite.shell(),
378014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "variant": test.variant,
379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    })
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochPROGRESS_INDICATORS = {
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'verbose': VerboseProgressIndicator,
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'dots': DotsProgressIndicator,
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'color': ColorProgressIndicator,
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  'mono': MonochromeProgressIndicator
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
388