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 |