Commit c7d3a832 authored by Iustin Pop's avatar Iustin Pop
Browse files

Add a simple wrapper over utils.Retry



The new wrapper makes moving legacy code to utils.Retry or adding
retries in existing code simpler.
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parent d1e9c98d
......@@ -182,3 +182,41 @@ def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep,
current_delay = calc_delay()
if current_delay > 0.0:
wait_fn(current_delay)
def SimpleRetry(expected, fn, delay, timeout, args=None, wait_fn=time.sleep,
_time_fn=time.time):
"""A wrapper over L{Retry} implementing a simpler interface.
All the parameters are the same as for L{Retry}, except it has one
extra argument: expected, which can be either a value (will be
compared with the result of the function, or a callable (which will
get the result passed and has to return a boolean). If the test is
false, we will retry until either the timeout has passed or the
tests succeeds. In both cases, the last result from calling the
function will be returned.
Note that this function is not expected to raise any retry-related
exceptions, always simply returning values. As such, the function is
designed to allow easy wrapping of code that doesn't use retry at
all (e.g. "if fn(args)" replaced with "if SimpleRetry(True, fn,
...)".
@see: L{Retry}
"""
rdict = {}
def helper(*innerargs):
# pylint: disable-msg=W0142
result = rdict["result"] = fn(*innerargs)
if not ((callable(expected) and expected(result)) or result == expected):
raise RetryAgain()
return result
try:
result = Retry(helper, delay, timeout, args=args,
wait_fn=wait_fn, _time_fn=_time_fn)
except RetryTimeout:
assert "result" in rdict
result = rdict["result"]
return result
......@@ -34,6 +34,7 @@ class TestRetry(testutils.GanetiTestCase):
def setUp(self):
testutils.GanetiTestCase.setUp(self)
self.retries = 0
self.called = 0
@staticmethod
def _RaiseRetryAgain():
......@@ -53,6 +54,14 @@ class TestRetry(testutils.GanetiTestCase):
else:
return True
def _SimpleRetryAndSucceed(self, retries):
self.called += 1
if self.retries < retries:
self.retries += 1
return False
else:
return True
def testRaiseTimeout(self):
self.failUnlessRaises(utils.RetryTimeout, utils.Retry,
self._RaiseRetryAgain, 0.01, 0.02)
......@@ -112,6 +121,20 @@ class TestRetry(testutils.GanetiTestCase):
else:
self.fail("Expected RetryTimeout didn't happen")
def testSimpleRetry(self):
self.assertFalse(utils.SimpleRetry(True, lambda: False, 0.01, 0.02))
self.assertFalse(utils.SimpleRetry(lambda x: x, lambda: False, 0.01, 0.02))
self.assertTrue(utils.SimpleRetry(True, lambda: True, 0, 1))
self.assertTrue(utils.SimpleRetry(lambda x: x, lambda: True, 0, 1))
self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed,
0, 1, args=[1]))
self.assertEqual(self.retries, 1)
self.assertEqual(self.called, 2)
self.called = self.retries = 0
self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed,
0, 1, args=[2]))
self.assertEqual(self.called, 3)
if __name__ == "__main__":
testutils.GanetiTestProgram()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment