failures_lib: do not print the textual tracebacks for CompoundFailure
Including the textual tracebacks in __str__ makes the failure reason
hard to read on the waterfall. Remove the tracebacks from __str__, but
still print them in HandleExceptionAsError/Warning for debugging
purpose.
BUG=chromium:382731
TEST=`cbuildbot/run_tests`
Change-Id: Iea992dbda67d734cdeaa3c2c4e33e1375354680b
Reviewed-on: https://chromium-review.googlesource.com/203177
Tested-by: Yu-Ju Hong <yjhong@chromium.org>
Reviewed-by: Yu-Ju Hong <yjhong@chromium.org>
Commit-Queue: Yu-Ju Hong <yjhong@chromium.org>
diff --git a/cbuildbot/failures_lib.py b/cbuildbot/failures_lib.py
index d3d5e14..e7d2b79 100644
--- a/cbuildbot/failures_lib.py
+++ b/cbuildbot/failures_lib.py
@@ -79,12 +79,22 @@
"""
self.exc_infos = exc_infos if exc_infos else []
if not message:
- # By default, print all stored ExceptInfo objects.
- message = '\n'.join(['%s: %s\n%s' % e for e in self.exc_infos])
+ # By default, print the type and string of each ExceptInfo object.
+ message = '\n'.join(['%s: %s' % (e.type, e.str) for e in self.exc_infos])
super(CompoundFailure, self).__init__(message=message,
possibly_flaky=possibly_flaky)
+ def ToFullMessage(self):
+ """Returns a string with all information in self.exc_infos."""
+ if self.HasEmptyList():
+ # Fall back to return self.message if list is empty.
+ return self.message
+ else:
+ # This includes the textual traceback(s).
+ return '\n'.join(['{e.type}: {e.str} {e.traceback}'.format(e=ex) for
+ ex in self.exc_infos])
+
def HasEmptyList(self):
"""Returns True if self.exc_infos is empty."""
return not bool(self.exc_infos)
diff --git a/cbuildbot/failures_lib_unittest.py b/cbuildbot/failures_lib_unittest.py
index f3fce4d..417d3f3 100755
--- a/cbuildbot/failures_lib_unittest.py
+++ b/cbuildbot/failures_lib_unittest.py
@@ -72,10 +72,10 @@
exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
self.assertTrue('bar1' in str(exc))
self.assertTrue('bar2' in str(exc))
- self.assertTrue('foo1' in str(exc))
- self.assertTrue('foo2' in str(exc))
self.assertTrue('KeyError' in str(exc))
self.assertTrue('ValueError' in str(exc))
+ self.assertTrue('foo1' in exc.ToFullMessage())
+ self.assertTrue('foo2' in exc.ToFullMessage())
class SetFailureTypeTest(cros_test_lib.TestCase):
@@ -144,8 +144,8 @@
self.assertEqual(e.exc_infos, org_infos)
# All essential inforamtion should be included in the message of
# the new excpetion.
- self.assertTrue(tb1 in str(e))
- self.assertTrue(tb2 in str(e))
+ self.assertTrue(tb1 in e.ToFullMessage())
+ self.assertTrue(tb2 in e.ToFullMessage())
self.assertTrue(str(ValueError) in str(e))
self.assertTrue(str(OSError) in str(e))
self.assertTrue(str('No taco') in str(e))
diff --git a/cbuildbot/stages/generic_stages.py b/cbuildbot/stages/generic_stages.py
index 7539d56..3d70508 100644
--- a/cbuildbot/stages/generic_stages.py
+++ b/cbuildbot/stages/generic_stages.py
@@ -265,7 +265,9 @@
A string description of the exception.
"""
exc_type, exc_value = exc_info[:2]
- if issubclass(exc_type, failures_lib.StepFailure):
+ if issubclass(exc_type, failures_lib.CompoundFailure):
+ return exc_value.ToFullMessage()
+ elif issubclass(exc_type, failures_lib.StepFailure):
return str(exc_value)
else:
return ''.join(traceback.format_exception(*exc_info))
diff --git a/lib/parallel_unittest.py b/lib/parallel_unittest.py
index f07f359..ef1cb21 100755
--- a/lib/parallel_unittest.py
+++ b/lib/parallel_unittest.py
@@ -351,8 +351,8 @@
ex_str = str(ex)
self.assertTrue(exc_type in [x.type for x in ex.exc_infos])
- self.assertTrue('Traceback' in ex_str)
self.assertEqual(output_str, _GREETING)
+ self.assertTrue(str(exc_type) in ex_str)
def testExceptionRaising(self):
"""Tests the exceptions are raised correctly."""