Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(348)

Side by Side Diff: scripts/common/gtest_utils.py

Issue 10636008: Convert runtest to have a built-in annotator. (Closed) Base URL: http://git.chromium.org/chromium/tools/build.git@master
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | scripts/slave/gtest/test_result.py » ('j') | scripts/slave/runtest.py » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import re 6 import re
7 7
8 8
9 class GTestLogParser(object): 9 class GTestLogParser(object):
10 """This helper class process GTest test output.""" 10 """This helper class process GTest test output."""
11 11
12 def __init__(self): 12 def __init__(self):
13 # State tracking for log parsing 13 # State tracking for log parsing
14 self.completed = False
14 self._current_test = '' 15 self._current_test = ''
15 self._failure_description = [] 16 self._failure_description = []
16 self._current_suppression_hash = '' 17 self._current_suppression_hash = ''
17 self._current_suppression = [] 18 self._current_suppression = []
18 self._parsing_failures = False 19 self._parsing_failures = False
19 20
20 # Line number currently being processed. 21 # Line number currently being processed.
21 self._line_number = 0 22 self._line_number = 0
22 23
23 # List of parsing errors, as human-readable strings. 24 # List of parsing errors, as human-readable strings.
(...skipping 13 matching lines...) Expand all
37 # '%s disabled' or '%s flaky' on the waterfall display. 38 # '%s disabled' or '%s flaky' on the waterfall display.
38 self._disabled_tests = 0 39 self._disabled_tests = 0
39 self._flaky_tests = 0 40 self._flaky_tests = 0
40 41
41 # Regular expressions for parsing GTest logs. Test names look like 42 # Regular expressions for parsing GTest logs. Test names look like
42 # SomeTestCase.SomeTest 43 # SomeTestCase.SomeTest
43 # SomeName/SomeTestCase.SomeTest/1 44 # SomeName/SomeTestCase.SomeTest/1
44 # This regexp also matches SomeName.SomeTest/1, which should be harmless. 45 # This regexp also matches SomeName.SomeTest/1, which should be harmless.
45 test_name_regexp = r'((\w+/)?\w+\.\w+(/\d+)?)' 46 test_name_regexp = r'((\w+/)?\w+\.\w+(/\d+)?)'
46 47
48 self._master_name_re = re.compile('\[Running for master: "([^"]*)"')
49 self.master_name = ''
50
47 self._test_name = re.compile(test_name_regexp) 51 self._test_name = re.compile(test_name_regexp)
48 self._test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regexp) 52 self._test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regexp)
49 self._test_ok = re.compile('\[\s+OK\s+\] ' + test_name_regexp) 53 self._test_ok = re.compile('\[\s+OK\s+\] ' + test_name_regexp)
50 self._test_fail = re.compile('\[\s+FAILED\s+\] ' + test_name_regexp) 54 self._test_fail = re.compile('\[\s+FAILED\s+\] ' + test_name_regexp)
55 self._test_passed = re.compile('\[\s+PASSED\s+\] \d+ tests?.')
51 self._test_timeout = re.compile( 56 self._test_timeout = re.compile(
52 'Test timeout \([0-9]+ ms\) exceeded for ' + test_name_regexp) 57 'Test timeout \([0-9]+ ms\) exceeded for ' + test_name_regexp)
53 self._disabled = re.compile(' YOU HAVE (\d+) DISABLED TEST') 58 self._disabled = re.compile(' YOU HAVE (\d+) DISABLED TEST')
54 self._flaky = re.compile(' YOU HAVE (\d+) FLAKY TEST') 59 self._flaky = re.compile(' YOU HAVE (\d+) FLAKY TEST')
55 60
56 self._suppression_start = re.compile( 61 self._suppression_start = re.compile(
57 'Suppression \(error hash=#([0-9A-F]+)#\):') 62 'Suppression \(error hash=#([0-9A-F]+)#\):')
58 self._suppression_end = re.compile('^}\s*$') 63 self._suppression_end = re.compile('^}\s*$')
59 64
60 self._retry_message = re.compile('RETRYING FAILED TESTS:') 65 self._retry_message = re.compile('RETRYING FAILED TESTS:')
61 self.retrying_failed = False 66 self.retrying_failed = False
62 67
68 def GetCurrentTest(self):
69 return self._current_test
70
63 def _StatusOfTest(self, test): 71 def _StatusOfTest(self, test):
64 """Returns the status code for the given test, or 'not known'.""" 72 """Returns the status code for the given test, or 'not known'."""
65 test_status = self._test_status.get(test, ('not known', [])) 73 test_status = self._test_status.get(test, ('not known', []))
66 return test_status[0] 74 return test_status[0]
67 75
68 def _TestsByStatus(self, status, include_fails, include_flaky): 76 def _TestsByStatus(self, status, include_fails, include_flaky):
69 """Returns list of tests with the given status. 77 """Returns list of tests with the given status.
70 78
71 Args: 79 Args:
72 include_fails: If False, tests containing 'FAILS_' anywhere in their 80 include_fails: If False, tests containing 'FAILS_' anywhere in their
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 """Returns list of suppression hashes found in the log.""" 159 """Returns list of suppression hashes found in the log."""
152 return self._suppressions.keys() 160 return self._suppressions.keys()
153 161
154 def Suppression(self, suppression_hash): 162 def Suppression(self, suppression_hash):
155 """Returns a list containing the suppression for a given hash. 163 """Returns a list containing the suppression for a given hash.
156 164
157 If the suppression hash doesn't exist, returns []. 165 If the suppression hash doesn't exist, returns [].
158 """ 166 """
159 return self._suppressions.get(suppression_hash, []) 167 return self._suppressions.get(suppression_hash, [])
160 168
169 def CompletedWithoutFailure(self):
170 """Returns True if all tests completed and no tests failed unexpectedly."""
171
cmp 2012/06/28 19:14:16 nit: remove empty line
172 if not self.completed:
173 return False
174
175 # don't count FAILS and FLAKY here
176 if self.FailedTests():
177 return False
178
179 return True
cmp 2012/06/28 19:14:16 let's condense lines 172-179 to one line: return
180
161 def ProcessLine(self, line): 181 def ProcessLine(self, line):
162 """This is called once with each line of the test log.""" 182 """This is called once with each line of the test log."""
163 183
164 # Track line number for error messages. 184 # Track line number for error messages.
165 self._line_number += 1 185 self._line_number += 1
166 186
167 # Note: When sharding, the number of disabled and flaky tests will be read 187 # Note: When sharding, the number of disabled and flaky tests will be read
168 # multiple times, so this will only show the most recent values (but they 188 # multiple times, so this will only show the most recent values (but they
169 # should all be the same anyway). 189 # should all be the same anyway).
170 190
191 # Is it a line listing the master name?
192 if not self.master_name:
193 results = self._master_name_re.search(line)
194 if results:
195 self.master_name = results.group(1)
196
197 # Is it a line declaring all tests passed?
198 results = self._test_passed.search(line)
199 if results:
200 self.completed = True
201 self._current_test = ''
202 return
203
171 # Is it a line reporting disabled tests? 204 # Is it a line reporting disabled tests?
172 results = self._disabled.search(line) 205 results = self._disabled.search(line)
173 if results: 206 if results:
174 try: 207 try:
175 disabled = int(results.group(1)) 208 disabled = int(results.group(1))
176 except ValueError: 209 except ValueError:
177 disabled = 0 210 disabled = 0
178 if disabled > 0 and isinstance(self._disabled_tests, int): 211 if disabled > 0 and isinstance(self._disabled_tests, int):
179 self._disabled_tests = disabled 212 self._disabled_tests = disabled
180 else: 213 else:
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 if results: 336 if results:
304 test_name = results.group(1) 337 test_name = results.group(1)
305 status = self._StatusOfTest(test_name) 338 status = self._StatusOfTest(test_name)
306 if status in ('not known', 'OK'): 339 if status in ('not known', 'OK'):
307 self._test_status[test_name] = ( 340 self._test_status[test_name] = (
308 'failed', ['Unknown error, see stdio log.']) 341 'failed', ['Unknown error, see stdio log.'])
309 else: 342 else:
310 self._parsing_failures = False 343 self._parsing_failures = False
311 elif line.startswith('Failing tests:'): 344 elif line.startswith('Failing tests:'):
312 self._parsing_failures = True 345 self._parsing_failures = True
OLDNEW
« no previous file with comments | « no previous file | scripts/slave/gtest/test_result.py » ('j') | scripts/slave/runtest.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698