| OLD | NEW |
| (Empty) | |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """ |
| 6 Unit tests for decorators.py. |
| 7 """ |
| 8 |
| 9 # pylint: disable=W0613 |
| 10 |
| 11 import time |
| 12 import traceback |
| 13 import unittest |
| 14 |
| 15 from pylib.device import decorators |
| 16 from pylib.device import device_errors |
| 17 |
| 18 _DEFAULT_TIMEOUT = 30 |
| 19 _DEFAULT_RETRIES = 3 |
| 20 |
| 21 class DecoratorsTest(unittest.TestCase): |
| 22 _decorated_function_called_count = 0 |
| 23 |
| 24 def testFunctionDecoratorSetsTimeout(self): |
| 25 """ Tests that the WithTimeoutAndRetries decorator sets |timeout| |
| 26 appropriately. |
| 27 """ |
| 28 @decorators.WithTimeoutAndRetriesDefaults( |
| 29 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
| 30 def alwaysReturnTimeoutVal(timeout=None, retries=None): |
| 31 return timeout |
| 32 |
| 33 self.assertEquals(_DEFAULT_TIMEOUT, alwaysReturnTimeoutVal()) |
| 34 self.assertEquals(8, alwaysReturnTimeoutVal(timeout=8)) |
| 35 |
| 36 def testFunctionDecoratorSetsRetries(self): |
| 37 """ Tests that the WithTimeoutAndRetries decorator sets |retries| |
| 38 appropriately. |
| 39 """ |
| 40 @decorators.WithTimeoutAndRetriesDefaults( |
| 41 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
| 42 def alwaysReturnRetriesVal(timeout=None, retries=None): |
| 43 return retries |
| 44 |
| 45 self.assertEquals(_DEFAULT_RETRIES, alwaysReturnRetriesVal()) |
| 46 self.assertEquals(1, alwaysReturnRetriesVal(retries=1)) |
| 47 |
| 48 def testFunctionDecoratorDoesTimeouts(self): |
| 49 """ Tests that the WithTimeoutAndRetries decorator handles the timeout |
| 50 logic. |
| 51 """ |
| 52 DecoratorsTest._decorated_function_called_count = 0 |
| 53 @decorators.WithTimeoutAndRetriesDefaults( |
| 54 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
| 55 def alwaysTimesOut(timeout=None, retries=None): |
| 56 DecoratorsTest._decorated_function_called_count += 1 |
| 57 time.sleep(100 * timeout) |
| 58 |
| 59 start_time = time.time() |
| 60 with self.assertRaises(device_errors.CommandTimeoutError): |
| 61 alwaysTimesOut(timeout=1, retries=0) |
| 62 elapsed_time = time.time() - start_time |
| 63 self.assertTrue(elapsed_time >= 1) |
| 64 self.assertEquals(1, DecoratorsTest._decorated_function_called_count) |
| 65 |
| 66 def testFunctionDecoratorDoesRetries(self): |
| 67 """ Tests that the WithTimeoutAndRetries decorator handles the retries |
| 68 logic. |
| 69 """ |
| 70 DecoratorsTest._decorated_function_called_count = 0 |
| 71 @decorators.WithTimeoutAndRetriesDefaults( |
| 72 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
| 73 def alwaysRaisesCommandFailedError(timeout=None, retries=None): |
| 74 DecoratorsTest._decorated_function_called_count += 1 |
| 75 raise device_errors.CommandFailedError(['testCommand'], |
| 76 'testCommand failed') |
| 77 |
| 78 with self.assertRaises(device_errors.CommandFailedError): |
| 79 alwaysRaisesCommandFailedError(retries=10) |
| 80 self.assertEquals(11, DecoratorsTest._decorated_function_called_count) |
| 81 |
| 82 def testFunctionDecoratorNoDefaults(self): |
| 83 """ Tests that the WithTimeoutAndRetries decorator requires values for |
| 84 timeout and retries when no defaults are supplied. |
| 85 """ |
| 86 @decorators.WithTimeoutAndRetries |
| 87 def requiresExplicitTimeoutAndRetries(timeout=None, retries=None): |
| 88 return (timeout, retries) |
| 89 with self.assertRaises(TypeError): |
| 90 requiresExplicitTimeoutAndRetries() |
| 91 with self.assertRaises(TypeError): |
| 92 requiresExplicitTimeoutAndRetries(timeout=10) |
| 93 with self.assertRaises(TypeError): |
| 94 requiresExplicitTimeoutAndRetries(retries=0) |
| 95 expected_timeout = 10 |
| 96 expected_retries = 1 |
| 97 actual_timeout, actual_retries = ( |
| 98 requiresExplicitTimeoutAndRetries(timeout=expected_timeout, |
| 99 retries=expected_retries)) |
| 100 self.assertEquals(expected_timeout, actual_timeout) |
| 101 self.assertEquals(expected_retries, actual_retries) |
| 102 |
| 103 class _MethodDecoratorTestObject(object): |
| 104 """ An object suitable for testing the |
| 105 WithTimeoutAndRetriesFromInstance method decorator. |
| 106 """ |
| 107 |
| 108 def __init__(self, test_case, default_timeout=_DEFAULT_TIMEOUT, |
| 109 default_retries=_DEFAULT_RETRIES): |
| 110 self._test_case = test_case |
| 111 self.default_timeout = default_timeout |
| 112 self.default_retries = default_retries |
| 113 self.function_call_counters = { |
| 114 'alwaysRaisesCommandFailedError': 0, |
| 115 'alwaysTimesOut': 0, |
| 116 'requiresExplicitTimeoutAndRetries': 0, |
| 117 } |
| 118 |
| 119 # pylint: disable=R0201 |
| 120 |
| 121 @decorators.WithTimeoutAndRetriesFromInstance('default_timeout', |
| 122 'default_retries') |
| 123 def alwaysReturnTimeoutVal(self, timeout=None, retries=None): |
| 124 return timeout |
| 125 |
| 126 @decorators.WithTimeoutAndRetriesFromInstance('default_timeout', |
| 127 'default_retries') |
| 128 def alwaysReturnRetriesVal(self, timeout=None, retries=None): |
| 129 return retries |
| 130 |
| 131 # pylint: enable=R0201 |
| 132 |
| 133 @decorators.WithTimeoutAndRetriesFromInstance('default_timeout', |
| 134 'default_retries') |
| 135 def alwaysTimesOut(self, timeout=None, retries=None): |
| 136 self.function_call_counters['alwaysTimesOut'] += 1 |
| 137 time.sleep(100 * timeout) |
| 138 self._test_case.assertFalse(True, msg='Failed to time out?') |
| 139 |
| 140 @decorators.WithTimeoutAndRetriesFromInstance('default_timeout', |
| 141 'default_retries') |
| 142 def alwaysRaisesCommandFailedError(self, timeout=None, retries=None): |
| 143 self.function_call_counters['alwaysRaisesCommandFailedError'] += 1 |
| 144 raise device_errors.CommandFailedError(['testCommand'], |
| 145 'testCommand failed') |
| 146 |
| 147 @decorators.WithTimeoutAndRetries |
| 148 def requiresExplicitTimeoutAndRetries(self, timeout=None, retries=None): |
| 149 self.function_call_counters['requiresExplicitTimeoutAndRetries'] += 1 |
| 150 return (timeout, retries) |
| 151 |
| 152 def testMethodDecoratorSetsTimeout(self): |
| 153 """ Tests that the WithTimeoutAndRetriesFromInstance decorator sets |
| 154 |timeout| appropriately. |
| 155 """ |
| 156 expected_default_timeout = 37 |
| 157 expected_custom_timeout = 38 |
| 158 test_obj = self._MethodDecoratorTestObject( |
| 159 self, default_timeout=expected_default_timeout) |
| 160 self.assertEquals( |
| 161 expected_default_timeout, test_obj.alwaysReturnTimeoutVal()) |
| 162 self.assertEquals( |
| 163 expected_custom_timeout, |
| 164 test_obj.alwaysReturnTimeoutVal(timeout=expected_custom_timeout)) |
| 165 |
| 166 def testMethodDecoratorSetsRetries(self): |
| 167 """ Tests that the WithTimeoutAndRetriesFromInstance decorator sets |
| 168 |retries| appropriately. |
| 169 """ |
| 170 expected_default_retries = 5 |
| 171 expected_custom_retries = 6 |
| 172 test_obj = self._MethodDecoratorTestObject( |
| 173 self, default_retries=expected_default_retries) |
| 174 self.assertEquals( |
| 175 expected_default_retries, test_obj.alwaysReturnRetriesVal()) |
| 176 self.assertEquals( |
| 177 expected_custom_retries, |
| 178 test_obj.alwaysReturnRetriesVal(retries=expected_custom_retries)) |
| 179 |
| 180 def testMethodDecoratorDoesTimeout(self): |
| 181 """ Tests that the WithTimeoutAndRetriesFromInstance decorator handles |
| 182 the timeout logic. |
| 183 """ |
| 184 test_obj = self._MethodDecoratorTestObject(self) |
| 185 start_time = time.time() |
| 186 with self.assertRaises(device_errors.CommandTimeoutError): |
| 187 try: |
| 188 test_obj.alwaysTimesOut(timeout=1, retries=0) |
| 189 except: |
| 190 traceback.print_exc() |
| 191 raise |
| 192 elapsed_time = time.time() - start_time |
| 193 self.assertTrue(elapsed_time >= 1) |
| 194 self.assertEquals(1, test_obj.function_call_counters['alwaysTimesOut']) |
| 195 |
| 196 def testMethodDecoratorDoesRetries(self): |
| 197 """ Tests that the WithTimeoutAndRetriesFromInstance decorator handles |
| 198 the retries logic. |
| 199 """ |
| 200 test_obj = self._MethodDecoratorTestObject(self) |
| 201 with self.assertRaises(device_errors.CommandFailedError): |
| 202 try: |
| 203 test_obj.alwaysRaisesCommandFailedError(retries=10) |
| 204 except: |
| 205 traceback.print_exc() |
| 206 raise |
| 207 self.assertEquals( |
| 208 11, test_obj.function_call_counters['alwaysRaisesCommandFailedError']) |
| 209 |
| 210 def testMethodDecoratorNoDefaults(self): |
| 211 """ Tests that the WithTimeoutAndRetries decorator requires defaults |
| 212 when applied to a method. |
| 213 """ |
| 214 test_obj = self._MethodDecoratorTestObject(self) |
| 215 with self.assertRaises(TypeError): |
| 216 test_obj.requiresExplicitTimeoutAndRetries() |
| 217 with self.assertRaises(TypeError): |
| 218 test_obj.requiresExplicitTimeoutAndRetries(timeout=10) |
| 219 with self.assertRaises(TypeError): |
| 220 test_obj.requiresExplicitTimeoutAndRetries(retries=0) |
| 221 expected_timeout = 10 |
| 222 expected_retries = 1 |
| 223 actual_timeout, actual_retries = ( |
| 224 test_obj.requiresExplicitTimeoutAndRetries(timeout=expected_timeout, |
| 225 retries=expected_retries)) |
| 226 self.assertEquals(expected_timeout, actual_timeout) |
| 227 self.assertEquals(expected_retries, actual_retries) |
| 228 |
| 229 |
| 230 if __name__ == '__main__': |
| 231 unittest.main() |
| 232 |
| 233 |
| OLD | NEW |