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