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 os |
| 12 import sys |
| 13 import time |
| 14 import traceback |
| 15 import unittest |
| 16 |
| 17 from pylib import constants |
| 18 from pylib.device import decorators |
| 19 from pylib.device import device_errors |
| 20 from pylib.utils import reraiser_thread |
| 21 |
| 22 # TODO(jbudorick) Remove once the DeviceUtils implementations are no longer |
| 23 # backed by AndroidCommands / android_testrunner. |
| 24 sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'third_party', |
| 25 'android_testrunner')) |
| 26 import errors as old_errors |
| 27 |
| 28 _DEFAULT_TIMEOUT = 30 |
| 29 _DEFAULT_RETRIES = 3 |
| 30 |
| 31 class DecoratorsTest(unittest.TestCase): |
| 32 _decorated_function_called_count = 0 |
| 33 |
| 34 def testFunctionDecoratorDoesTimeouts(self): |
| 35 """Tests that the base decorator handles the timeout logic.""" |
| 36 DecoratorsTest._decorated_function_called_count = 0 |
| 37 @decorators.WithTimeoutAndRetries |
| 38 def alwaysTimesOut(timeout=None, retries=None): |
| 39 DecoratorsTest._decorated_function_called_count += 1 |
| 40 time.sleep(100) |
| 41 |
| 42 start_time = time.time() |
| 43 with self.assertRaises(device_errors.CommandTimeoutError): |
| 44 alwaysTimesOut(timeout=1, retries=0) |
| 45 elapsed_time = time.time() - start_time |
| 46 self.assertTrue(elapsed_time >= 1) |
| 47 self.assertEquals(1, DecoratorsTest._decorated_function_called_count) |
| 48 |
| 49 def testFunctionDecoratorDoesRetries(self): |
| 50 """Tests that the base decorator handles the retries logic.""" |
| 51 DecoratorsTest._decorated_function_called_count = 0 |
| 52 @decorators.WithTimeoutAndRetries |
| 53 def alwaysRaisesCommandFailedError(timeout=None, retries=None): |
| 54 DecoratorsTest._decorated_function_called_count += 1 |
| 55 raise device_errors.CommandFailedError('testCommand failed') |
| 56 |
| 57 with self.assertRaises(device_errors.CommandFailedError): |
| 58 alwaysRaisesCommandFailedError(timeout=30, retries=10) |
| 59 self.assertEquals(11, DecoratorsTest._decorated_function_called_count) |
| 60 |
| 61 def testFunctionDecoratorRequiresParams(self): |
| 62 """Tests that the base decorator requires timeout and retries params.""" |
| 63 @decorators.WithTimeoutAndRetries |
| 64 def requiresExplicitTimeoutAndRetries(timeout=None, retries=None): |
| 65 return (timeout, retries) |
| 66 |
| 67 with self.assertRaises(KeyError): |
| 68 requiresExplicitTimeoutAndRetries() |
| 69 with self.assertRaises(KeyError): |
| 70 requiresExplicitTimeoutAndRetries(timeout=10) |
| 71 with self.assertRaises(KeyError): |
| 72 requiresExplicitTimeoutAndRetries(retries=0) |
| 73 expected_timeout = 10 |
| 74 expected_retries = 1 |
| 75 (actual_timeout, actual_retries) = ( |
| 76 requiresExplicitTimeoutAndRetries(timeout=expected_timeout, |
| 77 retries=expected_retries)) |
| 78 self.assertEquals(expected_timeout, actual_timeout) |
| 79 self.assertEquals(expected_retries, actual_retries) |
| 80 |
| 81 def testFunctionDecoratorTranslatesOldExceptions(self): |
| 82 """Tests that the explicit decorator translates old exceptions.""" |
| 83 @decorators.WithTimeoutAndRetries |
| 84 def alwaysRaisesProvidedException(exception, timeout=None, retries=None): |
| 85 raise exception |
| 86 |
| 87 exception_desc = 'Old response timeout error' |
| 88 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 89 alwaysRaisesProvidedException( |
| 90 old_errors.WaitForResponseTimedOutError(exception_desc), |
| 91 timeout=10, retries=1) |
| 92 self.assertEquals(exception_desc, str(e.exception)) |
| 93 |
| 94 exception_desc = 'Old device error' |
| 95 with self.assertRaises(device_errors.DeviceUnreachableError) as e: |
| 96 alwaysRaisesProvidedException( |
| 97 old_errors.DeviceUnresponsiveError(exception_desc), |
| 98 timeout=10, retries=1) |
| 99 self.assertEquals(exception_desc, str(e.exception)) |
| 100 |
| 101 def testFunctionDecoratorTranslatesReraiserExceptions(self): |
| 102 """Tests that the explicit decorator translates reraiser exceptions.""" |
| 103 @decorators.WithTimeoutAndRetries |
| 104 def alwaysRaisesProvidedException(exception, timeout=None, retries=None): |
| 105 raise exception |
| 106 |
| 107 exception_desc = 'Reraiser thread timeout error' |
| 108 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 109 alwaysRaisesProvidedException( |
| 110 reraiser_thread.TimeoutError(exception_desc), |
| 111 timeout=10, retries=1) |
| 112 self.assertEquals(exception_desc, str(e.exception)) |
| 113 |
| 114 def testDefaultsFunctionDecoratorDoesTimeouts(self): |
| 115 """Tests that the defaults decorator handles timeout logic.""" |
| 116 DecoratorsTest._decorated_function_called_count = 0 |
| 117 @decorators.WithTimeoutAndRetriesDefaults(1, 0) |
| 118 def alwaysTimesOut(timeout=None, retries=None): |
| 119 DecoratorsTest._decorated_function_called_count += 1 |
| 120 time.sleep(100) |
| 121 |
| 122 start_time = time.time() |
| 123 with self.assertRaises(device_errors.CommandTimeoutError): |
| 124 alwaysTimesOut() |
| 125 elapsed_time = time.time() - start_time |
| 126 self.assertTrue(elapsed_time >= 1) |
| 127 self.assertEquals(1, DecoratorsTest._decorated_function_called_count) |
| 128 |
| 129 DecoratorsTest._decorated_function_called_count = 0 |
| 130 with self.assertRaises(device_errors.CommandTimeoutError): |
| 131 alwaysTimesOut(timeout=2) |
| 132 elapsed_time = time.time() - start_time |
| 133 self.assertTrue(elapsed_time >= 2) |
| 134 self.assertEquals(1, DecoratorsTest._decorated_function_called_count) |
| 135 |
| 136 def testDefaultsFunctionDecoratorDoesRetries(self): |
| 137 """Tests that the defaults decorator handles retries logic.""" |
| 138 DecoratorsTest._decorated_function_called_count = 0 |
| 139 @decorators.WithTimeoutAndRetriesDefaults(30, 10) |
| 140 def alwaysRaisesCommandFailedError(timeout=None, retries=None): |
| 141 DecoratorsTest._decorated_function_called_count += 1 |
| 142 raise device_errors.CommandFailedError('testCommand failed') |
| 143 |
| 144 with self.assertRaises(device_errors.CommandFailedError): |
| 145 alwaysRaisesCommandFailedError() |
| 146 self.assertEquals(11, DecoratorsTest._decorated_function_called_count) |
| 147 |
| 148 DecoratorsTest._decorated_function_called_count = 0 |
| 149 with self.assertRaises(device_errors.CommandFailedError): |
| 150 alwaysRaisesCommandFailedError(retries=5) |
| 151 self.assertEquals(6, DecoratorsTest._decorated_function_called_count) |
| 152 |
| 153 def testDefaultsFunctionDecoratorPassesValues(self): |
| 154 """Tests that the defaults decorator passes timeout and retries kwargs.""" |
| 155 @decorators.WithTimeoutAndRetriesDefaults(30, 10) |
| 156 def alwaysReturnsTimeouts(timeout=None, retries=None): |
| 157 return timeout |
| 158 |
| 159 self.assertEquals(30, alwaysReturnsTimeouts()) |
| 160 self.assertEquals(120, alwaysReturnsTimeouts(timeout=120)) |
| 161 |
| 162 @decorators.WithTimeoutAndRetriesDefaults(30, 10) |
| 163 def alwaysReturnsRetries(timeout=None, retries=None): |
| 164 return retries |
| 165 |
| 166 self.assertEquals(10, alwaysReturnsRetries()) |
| 167 self.assertEquals(1, alwaysReturnsRetries(retries=1)) |
| 168 |
| 169 def testDefaultsFunctionDecoratorTranslatesOldExceptions(self): |
| 170 """Tests that the explicit decorator translates old exceptions.""" |
| 171 @decorators.WithTimeoutAndRetriesDefaults(30, 10) |
| 172 def alwaysRaisesProvidedException(exception, timeout=None, retries=None): |
| 173 raise exception |
| 174 |
| 175 exception_desc = 'Old response timeout error' |
| 176 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 177 alwaysRaisesProvidedException( |
| 178 old_errors.WaitForResponseTimedOutError(exception_desc)) |
| 179 self.assertEquals(exception_desc, str(e.exception)) |
| 180 |
| 181 exception_desc = 'Old device error' |
| 182 with self.assertRaises(device_errors.DeviceUnreachableError) as e: |
| 183 alwaysRaisesProvidedException( |
| 184 old_errors.DeviceUnresponsiveError(exception_desc)) |
| 185 self.assertEquals(exception_desc, str(e.exception)) |
| 186 |
| 187 def testDefaultsFunctionDecoratorTranslatesReraiserExceptions(self): |
| 188 """Tests that the explicit decorator translates reraiser exceptions.""" |
| 189 @decorators.WithTimeoutAndRetriesDefaults(30, 10) |
| 190 def alwaysRaisesProvidedException(exception, timeout=None, retries=None): |
| 191 raise exception |
| 192 |
| 193 exception_desc = 'Reraiser thread timeout error' |
| 194 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 195 alwaysRaisesProvidedException( |
| 196 reraiser_thread.TimeoutError(exception_desc)) |
| 197 self.assertEquals(exception_desc, str(e.exception)) |
| 198 |
| 199 def testExplicitFunctionDecoratorDoesTimeouts(self): |
| 200 """Tests that the explicit decorator handles timeout logic.""" |
| 201 DecoratorsTest._decorated_function_called_count = 0 |
| 202 @decorators.WithExplicitTimeoutAndRetries(1, 0) |
| 203 def alwaysTimesOut(): |
| 204 DecoratorsTest._decorated_function_called_count += 1 |
| 205 time.sleep(100) |
| 206 |
| 207 start_time = time.time() |
| 208 with self.assertRaises(device_errors.CommandTimeoutError): |
| 209 alwaysTimesOut() |
| 210 elapsed_time = time.time() - start_time |
| 211 self.assertTrue(elapsed_time >= 1) |
| 212 self.assertEquals(1, DecoratorsTest._decorated_function_called_count) |
| 213 |
| 214 def testExplicitFunctionDecoratorDoesRetries(self): |
| 215 """Tests that the explicit decorator handles retries logic.""" |
| 216 DecoratorsTest._decorated_function_called_count = 0 |
| 217 @decorators.WithExplicitTimeoutAndRetries(30, 10) |
| 218 def alwaysRaisesCommandFailedError(): |
| 219 DecoratorsTest._decorated_function_called_count += 1 |
| 220 raise device_errors.CommandFailedError('testCommand failed') |
| 221 |
| 222 with self.assertRaises(device_errors.CommandFailedError): |
| 223 alwaysRaisesCommandFailedError() |
| 224 self.assertEquals(11, DecoratorsTest._decorated_function_called_count) |
| 225 |
| 226 def testExplicitDecoratorTranslatesOldExceptions(self): |
| 227 """Tests that the explicit decorator translates old exceptions.""" |
| 228 @decorators.WithExplicitTimeoutAndRetries(30, 10) |
| 229 def alwaysRaisesProvidedException(exception): |
| 230 raise exception |
| 231 |
| 232 exception_desc = 'Old response timeout error' |
| 233 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 234 alwaysRaisesProvidedException( |
| 235 old_errors.WaitForResponseTimedOutError(exception_desc)) |
| 236 self.assertEquals(exception_desc, str(e.exception)) |
| 237 |
| 238 exception_desc = 'Old device error' |
| 239 with self.assertRaises(device_errors.DeviceUnreachableError) as e: |
| 240 alwaysRaisesProvidedException( |
| 241 old_errors.DeviceUnresponsiveError(exception_desc)) |
| 242 self.assertEquals(exception_desc, str(e.exception)) |
| 243 |
| 244 def testExplicitDecoratorTranslatesReraiserExceptions(self): |
| 245 """Tests that the explicit decorator translates reraiser exceptions.""" |
| 246 @decorators.WithExplicitTimeoutAndRetries(30, 10) |
| 247 def alwaysRaisesProvidedException(exception): |
| 248 raise exception |
| 249 |
| 250 exception_desc = 'Reraiser thread timeout error' |
| 251 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 252 alwaysRaisesProvidedException( |
| 253 reraiser_thread.TimeoutError(exception_desc)) |
| 254 self.assertEquals(exception_desc, str(e.exception)) |
| 255 |
| 256 class _MethodDecoratorTestObject(object): |
| 257 """An object suitable for testing the method decorator.""" |
| 258 |
| 259 def __init__(self, test_case, default_timeout=_DEFAULT_TIMEOUT, |
| 260 default_retries=_DEFAULT_RETRIES): |
| 261 self._test_case = test_case |
| 262 self.default_timeout = default_timeout |
| 263 self.default_retries = default_retries |
| 264 self.function_call_counters = { |
| 265 'alwaysRaisesCommandFailedError': 0, |
| 266 'alwaysTimesOut': 0, |
| 267 'requiresExplicitTimeoutAndRetries': 0, |
| 268 } |
| 269 |
| 270 @decorators.WithTimeoutAndRetriesFromInstance( |
| 271 'default_timeout', 'default_retries') |
| 272 def alwaysTimesOut(self, timeout=None, retries=None): |
| 273 self.function_call_counters['alwaysTimesOut'] += 1 |
| 274 time.sleep(100) |
| 275 self._test_case.assertFalse(True, msg='Failed to time out?') |
| 276 |
| 277 @decorators.WithTimeoutAndRetriesFromInstance( |
| 278 'default_timeout', 'default_retries') |
| 279 def alwaysRaisesCommandFailedError(self, timeout=None, retries=None): |
| 280 self.function_call_counters['alwaysRaisesCommandFailedError'] += 1 |
| 281 raise device_errors.CommandFailedError('testCommand failed') |
| 282 |
| 283 # pylint: disable=no-self-use |
| 284 |
| 285 @decorators.WithTimeoutAndRetriesFromInstance( |
| 286 'default_timeout', 'default_retries') |
| 287 def alwaysReturnsTimeout(self, timeout=None, retries=None): |
| 288 return timeout |
| 289 |
| 290 @decorators.WithTimeoutAndRetriesFromInstance( |
| 291 'default_timeout', 'default_retries') |
| 292 def alwaysReturnsRetries(self, timeout=None, retries=None): |
| 293 return retries |
| 294 |
| 295 @decorators.WithTimeoutAndRetriesFromInstance( |
| 296 'default_timeout', 'default_retries') |
| 297 def alwaysRaisesProvidedException(self, exception, timeout=None, |
| 298 retries=None): |
| 299 raise exception |
| 300 |
| 301 # pylint: enable=no-self-use |
| 302 |
| 303 |
| 304 def testMethodDecoratorDoesTimeout(self): |
| 305 """Tests that the method decorator handles timeout logic.""" |
| 306 test_obj = self._MethodDecoratorTestObject(self) |
| 307 start_time = time.time() |
| 308 with self.assertRaises(device_errors.CommandTimeoutError): |
| 309 try: |
| 310 test_obj.alwaysTimesOut(timeout=1, retries=0) |
| 311 except: |
| 312 traceback.print_exc() |
| 313 raise |
| 314 elapsed_time = time.time() - start_time |
| 315 self.assertTrue(elapsed_time >= 1) |
| 316 self.assertEquals(1, test_obj.function_call_counters['alwaysTimesOut']) |
| 317 |
| 318 def testMethodDecoratorDoesRetries(self): |
| 319 """Tests that the method decorator handles retries logic.""" |
| 320 test_obj = self._MethodDecoratorTestObject(self) |
| 321 with self.assertRaises(device_errors.CommandFailedError): |
| 322 try: |
| 323 test_obj.alwaysRaisesCommandFailedError(retries=10) |
| 324 except: |
| 325 traceback.print_exc() |
| 326 raise |
| 327 self.assertEquals( |
| 328 11, test_obj.function_call_counters['alwaysRaisesCommandFailedError']) |
| 329 |
| 330 def testMethodDecoratorPassesValues(self): |
| 331 """Tests that the method decorator passes timeout and retries kwargs.""" |
| 332 test_obj = self._MethodDecoratorTestObject( |
| 333 self, default_timeout=42, default_retries=31) |
| 334 self.assertEquals(42, test_obj.alwaysReturnsTimeout()) |
| 335 self.assertEquals(41, test_obj.alwaysReturnsTimeout(timeout=41)) |
| 336 self.assertEquals(31, test_obj.alwaysReturnsRetries()) |
| 337 self.assertEquals(32, test_obj.alwaysReturnsRetries(retries=32)) |
| 338 |
| 339 def testMethodDecoratorTranslatesOldExceptions(self): |
| 340 test_obj = self._MethodDecoratorTestObject(self) |
| 341 |
| 342 exception_desc = 'Old response timeout error' |
| 343 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 344 test_obj.alwaysRaisesProvidedException( |
| 345 old_errors.WaitForResponseTimedOutError(exception_desc)) |
| 346 self.assertEquals(exception_desc, str(e.exception)) |
| 347 |
| 348 exception_desc = 'Old device error' |
| 349 with self.assertRaises(device_errors.DeviceUnreachableError) as e: |
| 350 test_obj.alwaysRaisesProvidedException( |
| 351 old_errors.DeviceUnresponsiveError(exception_desc)) |
| 352 self.assertEquals(exception_desc, str(e.exception)) |
| 353 |
| 354 def testMethodDecoratorTranslatesReraiserExceptions(self): |
| 355 test_obj = self._MethodDecoratorTestObject(self) |
| 356 |
| 357 exception_desc = 'Reraiser thread timeout error' |
| 358 with self.assertRaises(device_errors.CommandTimeoutError) as e: |
| 359 test_obj.alwaysRaisesProvidedException( |
| 360 reraiser_thread.TimeoutError(exception_desc)) |
| 361 self.assertEquals(exception_desc, str(e.exception)) |
| 362 |
| 363 if __name__ == '__main__': |
| 364 unittest.main(verbosity=2) |
| 365 |
OLD | NEW |