Revision c7d3a832

b/lib/utils/retry.py
182 182
      current_delay = calc_delay()
183 183
      if current_delay > 0.0:
184 184
        wait_fn(current_delay)
185

  
186

  
187
def SimpleRetry(expected, fn, delay, timeout, args=None, wait_fn=time.sleep,
188
                _time_fn=time.time):
189
  """A wrapper over L{Retry} implementing a simpler interface.
190

  
191
  All the parameters are the same as for L{Retry}, except it has one
192
  extra argument: expected, which can be either a value (will be
193
  compared with the result of the function, or a callable (which will
194
  get the result passed and has to return a boolean). If the test is
195
  false, we will retry until either the timeout has passed or the
196
  tests succeeds. In both cases, the last result from calling the
197
  function will be returned.
198

  
199
  Note that this function is not expected to raise any retry-related
200
  exceptions, always simply returning values. As such, the function is
201
  designed to allow easy wrapping of code that doesn't use retry at
202
  all (e.g. "if fn(args)" replaced with "if SimpleRetry(True, fn,
203
  ...)".
204

  
205
  @see: L{Retry}
206

  
207
  """
208
  rdict = {}
209
  def helper(*innerargs):
210
    # pylint: disable-msg=W0142
211
    result = rdict["result"] = fn(*innerargs)
212
    if not ((callable(expected) and expected(result)) or result == expected):
213
      raise RetryAgain()
214
    return result
215

  
216
  try:
217
    result = Retry(helper, delay, timeout, args=args,
218
                   wait_fn=wait_fn, _time_fn=_time_fn)
219
  except RetryTimeout:
220
    assert "result" in rdict
221
    result = rdict["result"]
222
  return result
b/test/ganeti.utils.retry_unittest.py
34 34
  def setUp(self):
35 35
    testutils.GanetiTestCase.setUp(self)
36 36
    self.retries = 0
37
    self.called = 0
37 38

  
38 39
  @staticmethod
39 40
  def _RaiseRetryAgain():
......
53 54
    else:
54 55
      return True
55 56

  
57
  def _SimpleRetryAndSucceed(self, retries):
58
    self.called += 1
59
    if self.retries < retries:
60
      self.retries += 1
61
      return False
62
    else:
63
      return True
64

  
56 65
  def testRaiseTimeout(self):
57 66
    self.failUnlessRaises(utils.RetryTimeout, utils.Retry,
58 67
                          self._RaiseRetryAgain, 0.01, 0.02)
......
112 121
    else:
113 122
      self.fail("Expected RetryTimeout didn't happen")
114 123

  
124
  def testSimpleRetry(self):
125
    self.assertFalse(utils.SimpleRetry(True, lambda: False, 0.01, 0.02))
126
    self.assertFalse(utils.SimpleRetry(lambda x: x, lambda: False, 0.01, 0.02))
127
    self.assertTrue(utils.SimpleRetry(True, lambda: True, 0, 1))
128
    self.assertTrue(utils.SimpleRetry(lambda x: x, lambda: True, 0, 1))
129
    self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed,
130
                                      0, 1, args=[1]))
131
    self.assertEqual(self.retries, 1)
132
    self.assertEqual(self.called, 2)
133
    self.called = self.retries = 0
134
    self.assertTrue(utils.SimpleRetry(True, self._SimpleRetryAndSucceed,
135
                                      0, 1, args=[2]))
136
    self.assertEqual(self.called, 3)
137

  
115 138

  
116 139
if __name__ == "__main__":
117 140
  testutils.GanetiTestProgram()

Also available in: Unified diff