3 # Copyright 2014 The Chromium OS Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 """Test the failures_lib module."""
12 sys.path.insert(0, os.path.abspath('%s/../..' % os.path.dirname(__file__)))
13 from chromite.cbuildbot import failures_lib
14 from chromite.lib import cros_test_lib
17 class CompoundFailureTest(cros_test_lib.TestCase):
18 """Test the CompoundFailure class."""
20 def _CreateExceptInfos(self, cls, message='', traceback='', num=1):
21 """A helper function to create a list of ExceptInfo objects."""
24 exc_infos.extend(failures_lib.CreateExceptInfo(cls(message), traceback))
28 def testHasEmptyList(self):
29 """Tests the HasEmptyList method."""
30 self.assertTrue(failures_lib.CompoundFailure().HasEmptyList())
31 exc_infos = self._CreateExceptInfos(KeyError)
33 failures_lib.CompoundFailure(exc_infos=exc_infos).HasEmptyList())
35 def testHasAndMatchesFailureType(self):
36 """Tests the HasFailureType and the MatchesFailureType methods."""
37 # Create a CompoundFailure instance with mixed types of exceptions.
38 exc_infos = self._CreateExceptInfos(KeyError)
39 exc_infos.extend(self._CreateExceptInfos(ValueError))
40 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
41 self.assertTrue(exc.HasFailureType(KeyError))
42 self.assertTrue(exc.HasFailureType(ValueError))
43 self.assertFalse(exc.MatchesFailureType(KeyError))
44 self.assertFalse(exc.MatchesFailureType(ValueError))
46 # Create a CompoundFailure instance with a single type of exceptions.
47 exc_infos = self._CreateExceptInfos(KeyError, num=5)
48 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
49 self.assertTrue(exc.HasFailureType(KeyError))
50 self.assertFalse(exc.HasFailureType(ValueError))
51 self.assertTrue(exc.MatchesFailureType(KeyError))
52 self.assertFalse(exc.MatchesFailureType(ValueError))
54 def testHasFatalFailure(self):
55 """Tests the HasFatalFailure method."""
56 exc_infos = self._CreateExceptInfos(KeyError)
57 exc_infos.extend(self._CreateExceptInfos(ValueError))
58 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
59 self.assertTrue(exc.HasFatalFailure())
60 self.assertTrue(exc.HasFatalFailure(whitelist=[KeyError]))
61 self.assertFalse(exc.HasFatalFailure(whitelist=[KeyError, ValueError]))
63 exc = failures_lib.CompoundFailure()
64 self.assertFalse(exc.HasFatalFailure())
66 def testMessageContainsAllInfo(self):
67 """Tests that by default, all information is included in the message."""
68 exc_infos = self._CreateExceptInfos(KeyError, message='bar1',
70 exc_infos.extend(self._CreateExceptInfos(ValueError, message='bar2',
72 exc = failures_lib.CompoundFailure(exc_infos=exc_infos)
73 self.assertTrue('bar1' in str(exc))
74 self.assertTrue('bar2' in str(exc))
75 self.assertTrue('KeyError' in str(exc))
76 self.assertTrue('ValueError' in str(exc))
77 self.assertTrue('foo1' in str(exc))
78 self.assertTrue('foo2' in str(exc))
81 class SetFailureTypeTest(cros_test_lib.TestCase):
82 """Test that the SetFailureType decorator works."""
83 ERROR_MESSAGE = 'You failed!'
85 class TacoNotTasty(failures_lib.CompoundFailure):
86 """Raised when the taco is not tasty."""
88 class NoGuacamole(TacoNotTasty):
89 """Raised when no guacamole in the taco."""
91 class SubparLunch(failures_lib.CompoundFailure):
92 """Raised when the lunch is subpar."""
94 class FooException(Exception):
95 """A foo exception."""
97 def _GetFunction(self, set_type, raise_type, *args, **kwargs):
98 """Returns a function to test.
101 set_type: The exception type that the function is decorated with.
102 raise_type: The exception type that the function raises.
103 *args: args to pass to the instance of |raise_type|.
106 The function to test.
108 @failures_lib.SetFailureType(set_type)
110 raise raise_type(*args, **kwargs)
114 def testAssertionFailOnIllegalExceptionType(self):
115 """Assertion should fail if the pre-set type is not allowed ."""
116 self.assertRaises(AssertionError, self._GetFunction, ValueError,
119 def testReraiseAsNewException(self):
120 """Tests that the pre-set exception type is raised correctly."""
122 self._GetFunction(self.TacoNotTasty, self.FooException,
123 self.ERROR_MESSAGE)()
124 except Exception as e:
125 self.assertTrue(isinstance(e, self.TacoNotTasty))
126 self.assertTrue(e.message, self.ERROR_MESSAGE)
127 self.assertEqual(len(e.exc_infos), 1)
128 self.assertEqual(e.exc_infos[0].str, self.ERROR_MESSAGE)
129 self.assertEqual(e.exc_infos[0].type, self.FooException)
130 self.assertTrue(isinstance(e.exc_infos[0].traceback, str))
132 def testReraiseACompoundFailure(self):
133 """Tests that the list of ExceptInfo objects are copied over."""
134 tb1 = 'Dummy traceback1'
135 tb2 = 'Dummy traceback2'
136 org_infos = failures_lib.CreateExceptInfo(ValueError('No taco.'), tb1) + \
137 failures_lib.CreateExceptInfo(OSError('No salsa'), tb2)
139 self._GetFunction(self.SubparLunch, self.TacoNotTasty,
140 exc_infos=org_infos)()
141 except Exception as e:
142 self.assertTrue(isinstance(e, self.SubparLunch))
143 # The orignal exceptions stored in exc_infos are preserved.
144 self.assertEqual(e.exc_infos, org_infos)
145 # All essential inforamtion should be included in the message of
147 self.assertTrue(tb1 in str(e))
148 self.assertTrue(tb2 in str(e))
149 self.assertTrue(str(ValueError) in str(e))
150 self.assertTrue(str(OSError) in str(e))
151 self.assertTrue(str('No taco') in str(e))
152 self.assertTrue(str('No salsa') in str(e))
154 # Assert that summary does not contain the textual tracebacks.
155 self.assertFalse(tb1 in e.ToSummaryString())
156 self.assertFalse(tb2 in e.ToSummaryString())
158 def testReraiseACompoundFailureWithEmptyList(self):
159 """Tests that a CompoundFailure with empty list is handled correctly."""
161 self._GetFunction(self.SubparLunch, self.TacoNotTasty,
162 message='empty list')()
163 except Exception as e:
164 self.assertTrue(isinstance(e, self.SubparLunch))
165 self.assertEqual(e.exc_infos[0].type, self.TacoNotTasty)
167 def testReraiseOriginalException(self):
168 """Tests that the original exception is re-raised."""
169 # NoGuacamole is a subclass of TacoNotTasty, so the wrapper has no
171 f = self._GetFunction(self.TacoNotTasty, self.NoGuacamole)
172 self.assertRaises(self.NoGuacamole, f)
174 def testPassArgsToWrappedFunctor(self):
175 """Tests that we can pass arguments to the functor."""
176 @failures_lib.SetFailureType(self.TacoNotTasty)
180 @failures_lib.SetFailureType(self.TacoNotTasty)
184 # Test passing arguments.
185 self.assertEqual(f('foo'), 'foo')
186 # Test passing keyword arguments.
187 self.assertEqual(g(kwarg='bar'), 'bar')
190 class ExceptInfoTest(cros_test_lib.TestCase):
191 """Tests the namedtuple class ExceptInfo."""
193 def testConvertToExceptInfo(self):
194 """Tests converting an exception to an ExceptInfo object."""
195 traceback = 'Dummy traceback'
196 message = 'Taco is not a valid option!'
197 except_infos = failures_lib.CreateExceptInfo(
198 ValueError(message), traceback)
200 self.assertEqual(except_infos[0].type, ValueError)
201 self.assertEqual(except_infos[0].str, message)
202 self.assertEqual(except_infos[0].traceback, traceback)
205 if __name__ == '__main__':