2 # Copyright 2014 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Test the failures_lib module."""
8 from __future__ import print_function
13 sys.path.insert(0, os.path.abspath('%s/../..' % os.path.dirname(__file__)))
14 from chromite.cbuildbot import failures_lib
15 from chromite.lib import cros_test_lib
18 class CompoundFailureTest(cros_test_lib.TestCase):
19 """Test the CompoundFailure class."""
21 def _CreateExceptInfos(self, cls, message='', traceback='', num=1):
22 """A helper function to create a list of ExceptInfo objects."""
25 exc_infos.extend(failures_lib.CreateExceptInfo(cls(message), traceback))
29 def testHasEmptyList(self):
30 """Tests the HasEmptyList method."""
31 self.assertTrue(failures_lib.CompoundFailure().HasEmptyList())
32 exc_infos = self._CreateExceptInfos(KeyError)
34 failures_lib.CompoundFailure(exc_infos=exc_infos).HasEmptyList())
36 def testHasAndMatchesFailureType(self):
37 """Tests the HasFailureType and the MatchesFailureType methods."""
38 # Create a CompoundFailure instance with mixed types of exceptions.
39 exc_infos = self._CreateExceptInfos(KeyError)
40 exc_infos.extend(self._CreateExceptInfos(ValueError))
41 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
42 self.assertTrue(exc.HasFailureType(KeyError))
43 self.assertTrue(exc.HasFailureType(ValueError))
44 self.assertFalse(exc.MatchesFailureType(KeyError))
45 self.assertFalse(exc.MatchesFailureType(ValueError))
47 # Create a CompoundFailure instance with a single type of exceptions.
48 exc_infos = self._CreateExceptInfos(KeyError, num=5)
49 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
50 self.assertTrue(exc.HasFailureType(KeyError))
51 self.assertFalse(exc.HasFailureType(ValueError))
52 self.assertTrue(exc.MatchesFailureType(KeyError))
53 self.assertFalse(exc.MatchesFailureType(ValueError))
55 def testHasFatalFailure(self):
56 """Tests the HasFatalFailure method."""
57 exc_infos = self._CreateExceptInfos(KeyError)
58 exc_infos.extend(self._CreateExceptInfos(ValueError))
59 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
60 self.assertTrue(exc.HasFatalFailure())
61 self.assertTrue(exc.HasFatalFailure(whitelist=[KeyError]))
62 self.assertFalse(exc.HasFatalFailure(whitelist=[KeyError, ValueError]))
64 exc = failures_lib.CompoundFailure()
65 self.assertFalse(exc.HasFatalFailure())
67 def testMessageContainsAllInfo(self):
68 """Tests that by default, all information is included in the message."""
69 exc_infos = self._CreateExceptInfos(KeyError, message='bar1',
71 exc_infos.extend(self._CreateExceptInfos(ValueError, message='bar2',
73 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
74 self.assertTrue('bar1' in str(exc))
75 self.assertTrue('bar2' in str(exc))
76 self.assertTrue('KeyError' in str(exc))
77 self.assertTrue('ValueError' in str(exc))
78 self.assertTrue('foo1' in str(exc))
79 self.assertTrue('foo2' in str(exc))
82 class SetFailureTypeTest(cros_test_lib.TestCase):
83 """Test that the SetFailureType decorator works."""
84 ERROR_MESSAGE = 'You failed!'
86 class TacoNotTasty(failures_lib.CompoundFailure):
87 """Raised when the taco is not tasty."""
89 class NoGuacamole(TacoNotTasty):
90 """Raised when no guacamole in the taco."""
92 class SubparLunch(failures_lib.CompoundFailure):
93 """Raised when the lunch is subpar."""
95 class FooException(Exception):
96 """A foo exception."""
98 def _GetFunction(self, set_type, raise_type, *args, **kwargs):
99 """Returns a function to test.
102 set_type: The exception type that the function is decorated with.
103 raise_type: The exception type that the function raises.
104 *args: args to pass to the instance of |raise_type|.
107 The function to test.
109 @failures_lib.SetFailureType(set_type)
111 raise raise_type(*args, **kwargs)
115 def testAssertionFailOnIllegalExceptionType(self):
116 """Assertion should fail if the pre-set type is not allowed ."""
117 self.assertRaises(AssertionError, self._GetFunction, ValueError,
120 def testReraiseAsNewException(self):
121 """Tests that the pre-set exception type is raised correctly."""
123 self._GetFunction(self.TacoNotTasty, self.FooException,
124 self.ERROR_MESSAGE)()
125 except Exception as e:
126 self.assertTrue(isinstance(e, self.TacoNotTasty))
127 self.assertTrue(e.message, self.ERROR_MESSAGE)
128 self.assertEqual(len(e.exc_infos), 1)
129 self.assertEqual(e.exc_infos[0].str, self.ERROR_MESSAGE)
130 self.assertEqual(e.exc_infos[0].type, self.FooException)
131 self.assertTrue(isinstance(e.exc_infos[0].traceback, str))
133 def testReraiseACompoundFailure(self):
134 """Tests that the list of ExceptInfo objects are copied over."""
135 tb1 = 'Dummy traceback1'
136 tb2 = 'Dummy traceback2'
137 org_infos = failures_lib.CreateExceptInfo(ValueError('No taco.'), tb1) + \
138 failures_lib.CreateExceptInfo(OSError('No salsa'), tb2)
140 self._GetFunction(self.SubparLunch, self.TacoNotTasty,
141 exc_infos=org_infos)()
142 except Exception as e:
143 self.assertTrue(isinstance(e, self.SubparLunch))
144 # The orignal exceptions stored in exc_infos are preserved.
145 self.assertEqual(e.exc_infos, org_infos)
146 # All essential inforamtion should be included in the message of
148 self.assertTrue(tb1 in str(e))
149 self.assertTrue(tb2 in str(e))
150 self.assertTrue(str(ValueError) in str(e))
151 self.assertTrue(str(OSError) in str(e))
152 self.assertTrue(str('No taco') in str(e))
153 self.assertTrue(str('No salsa') in str(e))
155 # Assert that summary does not contain the textual tracebacks.
156 self.assertFalse(tb1 in e.ToSummaryString())
157 self.assertFalse(tb2 in e.ToSummaryString())
159 def testReraiseACompoundFailureWithEmptyList(self):
160 """Tests that a CompoundFailure with empty list is handled correctly."""
162 self._GetFunction(self.SubparLunch, self.TacoNotTasty,
163 message='empty list')()
164 except Exception as e:
165 self.assertTrue(isinstance(e, self.SubparLunch))
166 self.assertEqual(e.exc_infos[0].type, self.TacoNotTasty)
168 def testReraiseOriginalException(self):
169 """Tests that the original exception is re-raised."""
170 # NoGuacamole is a subclass of TacoNotTasty, so the wrapper has no
172 f = self._GetFunction(self.TacoNotTasty, self.NoGuacamole)
173 self.assertRaises(self.NoGuacamole, f)
175 def testPassArgsToWrappedFunctor(self):
176 """Tests that we can pass arguments to the functor."""
177 @failures_lib.SetFailureType(self.TacoNotTasty)
181 @failures_lib.SetFailureType(self.TacoNotTasty)
185 # Test passing arguments.
186 self.assertEqual(f('foo'), 'foo')
187 # Test passing keyword arguments.
188 self.assertEqual(g(kwarg='bar'), 'bar')
191 class ExceptInfoTest(cros_test_lib.TestCase):
192 """Tests the namedtuple class ExceptInfo."""
194 def testConvertToExceptInfo(self):
195 """Tests converting an exception to an ExceptInfo object."""
196 traceback = 'Dummy traceback'
197 message = 'Taco is not a valid option!'
198 except_infos = failures_lib.CreateExceptInfo(
199 ValueError(message), traceback)
201 self.assertEqual(except_infos[0].type, ValueError)
202 self.assertEqual(except_infos[0].str, message)
203 self.assertEqual(except_infos[0].traceback, traceback)
206 if __name__ == '__main__':