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

Side by Side Diff: scripts/master/log_parser/gtest_command.py

Issue 9134001: Add parsing of "Failing tests:" from gtest output. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | scripts/master/unittests/gtest_command_unittest.py » ('j') | no next file with comments »
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 """A buildbot command for running and interpreting GTest tests.""" 6 """A buildbot command for running and interpreting GTest tests."""
7 7
8 import fileinput 8 import fileinput
9 import re 9 import re
10 import sys 10 import sys
11 from buildbot.steps import shell 11 from buildbot.steps import shell
12 from buildbot.status import builder 12 from buildbot.status import builder
13 from buildbot.process import buildstep 13 from buildbot.process import buildstep
14 14
15 class TestObserver(buildstep.LogLineObserver): 15 class TestObserver(buildstep.LogLineObserver):
16 """This class knows how to understand GTest test output.""" 16 """This class knows how to understand GTest test output."""
17 # TestAbbrFromTestID needs to be a member function. 17 # TestAbbrFromTestID needs to be a member function.
18 # pylint: disable=R0201 18 # pylint: disable=R0201
19 19
20 def __init__(self): 20 def __init__(self):
21 buildstep.LogLineObserver.__init__(self) 21 buildstep.LogLineObserver.__init__(self)
22 22
23 # State tracking for log parsing 23 # State tracking for log parsing
24 self._current_test = '' 24 self._current_test = ''
25 self._failure_description = [] 25 self._failure_description = []
26 self._current_suppression_hash = '' 26 self._current_suppression_hash = ''
27 self._current_suppression = [] 27 self._current_suppression = []
28 self._parsing_failures = False
28 29
29 # Line number currently being processed. 30 # Line number currently being processed.
30 self._line_number = 0 31 self._line_number = 0
31 32
32 # List of parsing errors, as human-readable strings. 33 # List of parsing errors, as human-readable strings.
33 self.internal_error_lines = [] 34 self.internal_error_lines = []
34 35
35 # Tests are stored here as 'test.name': (status, [description]). 36 # Tests are stored here as 'test.name': (status, [description]).
36 # The status should be one of ('started', 'OK', 'failed', 'timeout', 37 # The status should be one of ('started', 'OK', 'failed', 'timeout',
37 # 'warning'). Warning indicates that a test did not pass when run in 38 # 'warning'). Warning indicates that a test did not pass when run in
38 # parallel with other tests but passed when run alone. The description is 39 # parallel with other tests but passed when run alone. The description is
39 # a list of lines detailing the test's error, as reported in the log. 40 # a list of lines detailing the test's error, as reported in the log.
40 self._test_status = {} 41 self._test_status = {}
41 42
42 # Suppressions are stored here as 'hash': [suppression]. 43 # Suppressions are stored here as 'hash': [suppression].
43 self._suppressions = {} 44 self._suppressions = {}
44 45
45 # This may be either text or a number. It will be used in the phrase 46 # This may be either text or a number. It will be used in the phrase
46 # '%s disabled' or '%s flaky' on the waterfall display. 47 # '%s disabled' or '%s flaky' on the waterfall display.
47 self.disabled_tests = 0 48 self.disabled_tests = 0
48 self.flaky_tests = 0 49 self.flaky_tests = 0
49 50
50 # Regular expressions for parsing GTest logs. Test names look like 51 # Regular expressions for parsing GTest logs. Test names look like
51 # SomeTestCase.SomeTest 52 # SomeTestCase.SomeTest
52 # SomeName/SomeTestCase.SomeTest/1 53 # SomeName/SomeTestCase.SomeTest/1
53 # This regexp also matches SomeName.SomeTest/1, which should be harmless. 54 # This regexp also matches SomeName.SomeTest/1, which should be harmless.
54 test_name_regexp = r'((\w+/)?\w+\.\w+(/\d+)?)' 55 test_name_regexp = r'((\w+/)?\w+\.\w+(/\d+)?)'
55 56
57 self._test_name = re.compile(test_name_regexp)
56 self._test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regexp) 58 self._test_start = re.compile('\[\s+RUN\s+\] ' + test_name_regexp)
57 self._test_ok = re.compile('\[\s+OK\s+\] ' + test_name_regexp) 59 self._test_ok = re.compile('\[\s+OK\s+\] ' + test_name_regexp)
58 self._test_fail = re.compile('\[\s+FAILED\s+\] ' + test_name_regexp) 60 self._test_fail = re.compile('\[\s+FAILED\s+\] ' + test_name_regexp)
59 self._test_timeout = re.compile( 61 self._test_timeout = re.compile(
60 'Test timeout \([0-9]+ ms\) exceeded for ' + test_name_regexp) 62 'Test timeout \([0-9]+ ms\) exceeded for ' + test_name_regexp)
61 self._disabled = re.compile(' YOU HAVE (\d+) DISABLED TEST') 63 self._disabled = re.compile(' YOU HAVE (\d+) DISABLED TEST')
62 self._flaky = re.compile(' YOU HAVE (\d+) FLAKY TEST') 64 self._flaky = re.compile(' YOU HAVE (\d+) FLAKY TEST')
63 65
64 self._suppression_start = re.compile( 66 self._suppression_start = re.compile(
65 'Suppression \(error hash=#([0-9A-F]+)#\):') 67 'Suppression \(error hash=#([0-9A-F]+)#\):')
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 if self._current_suppression_hash: 284 if self._current_suppression_hash:
283 self._current_suppression.append(line) 285 self._current_suppression.append(line)
284 return 286 return
285 287
286 # Random line: if we're in a test, collect it for the failure description. 288 # Random line: if we're in a test, collect it for the failure description.
287 # Tests may run simultaneously, so this might be off, but it's worth a try. 289 # Tests may run simultaneously, so this might be off, but it's worth a try.
288 # This also won't work if a test times out before it begins running. 290 # This also won't work if a test times out before it begins running.
289 if self._current_test: 291 if self._current_test:
290 self._failure_description.append(line) 292 self._failure_description.append(line)
291 293
294 # Parse the "Failing tests:" list at the end of the output, and add any
295 # additional failed tests to the list. For example, this includes tests
296 # that crash after the OK line.
297 if self._parsing_failures:
298 results = self._test_name.search(line)
299 if results:
300 test_name = results.group(1)
301 status = self._StatusOfTest(test_name)
302 if status in ('not known', 'OK'):
303 self._test_status[test_name] = (
304 'failed', ['Unknown error, see stdio log.'])
305 else:
306 self._parsing_failures = False
307 elif line.startswith('Failing tests:'):
308 self._parsing_failures = True
292 309
293 class GTestCommand(shell.ShellCommand): 310 class GTestCommand(shell.ShellCommand):
294 """Buildbot command that knows how to display GTest output.""" 311 """Buildbot command that knows how to display GTest output."""
295 # TestAbbrFromTestID needs to be a member function. 312 # TestAbbrFromTestID needs to be a member function.
296 # pylint: disable=R0201 313 # pylint: disable=R0201
297 314
298 _GTEST_DASHBOARD_BASE = ("http://test-results.appspot.com" 315 _GTEST_DASHBOARD_BASE = ("http://test-results.appspot.com"
299 "/dashboards/flakiness_dashboard.html") 316 "/dashboards/flakiness_dashboard.html")
300 317
301 def __init__(self, **kwargs): 318 def __init__(self, **kwargs):
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 print 'Failed tests:\n' 407 print 'Failed tests:\n'
391 for failed_test in observer.FailedTests(True, True): 408 for failed_test in observer.FailedTests(True, True):
392 for fail_line in observer.FailureDescription(failed_test): 409 for fail_line in observer.FailureDescription(failed_test):
393 print fail_line.strip() 410 print fail_line.strip()
394 print '' 411 print ''
395 return 0 412 return 0
396 413
397 414
398 if '__main__' == __name__: 415 if '__main__' == __name__:
399 sys.exit(Main()) 416 sys.exit(Main())
OLDNEW
« no previous file with comments | « no previous file | scripts/master/unittests/gtest_command_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698