def test_retry_cancel(self): retries = 5 retrier = RetryingCaller(retries, reactor=self._clock) ret_vals = tuple(( ValueError('call attempt {}'.format(i)) for i in range(retries) )) + ( 'success', ) call = mock.Mock(side_effect=ret_vals) d = retrier.retry(call) self._clock.advance(0) d.cancel() self._clock.pump(RetryingCaller.DoublingBackoffGeneratorFactoryMixin._basegenerator(retries + 1)) # pylint: disable=protected-access expected = [ (), ] self.assertEqual(call.call_args_list, expected) self.assertFailure(d, t_defer.CancelledError) d.addErrback(lambda _res: None) # silence the unhandled error
def test_retry(self): retries = 5 retrier = RetryingCaller(retries, reactor=self._clock) ret_vals_0 = tuple(( ValueError('call_0 attempt {}'.format(i)) for i in range(retries - 1) )) + ( 'success_0', ) call_0 = mock.Mock(side_effect=ret_vals_0) d_0 = retrier.retry(call_0) ret_vals_1 = tuple(( ValueError('call_1 attempt {}'.format(i)) for i in range(retries) )) + ( 'success_1', ) call_1 = mock.Mock(side_effect=ret_vals_1) d_1 = retrier.retry(call_1) ret_vals_2 = tuple(( ValueError('call_2 attempt {}'.format(i)) for i in range(retries + 1) )) + ( 'success_2', ) call_2 = mock.Mock(side_effect=ret_vals_2) d_2 = retrier.retry(call_2) dl = t_defer.DeferredList(( d_0, d_1, d_2 ), consumeErrors=True) self._clock.advance(0) self._clock.pump(RetryingCaller.DoublingBackoffGeneratorFactoryMixin._basegenerator(retries + 1)) # pylint: disable=protected-access self.assertTrue(d_0.called) self.assertTrue(d_1.called) self.assertTrue(d_2.called) self.assertTrue(dl.called) success_0, ret_val_0 = dl.result[0] self.assertTrue(success_0) self.assertEqual(ret_val_0, 'success_0') expected_0 = [ (), ] * len(ret_vals_0) self.assertEqual(call_0.call_args_list, expected_0) success_1, ret_val_1 = dl.result[1] self.assertTrue(success_1) self.assertEqual(ret_val_1, 'success_1') expected_1 = [ (), ] * len(ret_vals_1) self.assertEqual(call_1.call_args_list, expected_1) success_2, ret_val_2 = dl.result[2] self.assertFalse(success_2) self.assertIsInstance(ret_val_2, t_failure.Failure) self.assertIsNotNone(ret_val_2.check(ValueError)) error_2 = ret_val_2.value self.assertEqual(error_2.args, ( 'call_2 attempt {}'.format(retries), )) expected_2 = [ (), ] * (len(ret_vals_2) - 1) self.assertEqual(call_2.call_args_list, expected_2)
def test_first_error(self): err_msg = 'Weee!' def _none(*_, **__): # pylint: disable=unused-argument return def _raise(*_, **__): # pylint: disable=unused-argument raise RuntimeError(err_msg) def _call(): dl = t_defer.DeferredList(( t_defer.maybeDeferred(_none), t_defer.maybeDeferred(_raise) ), fireOnOneErrback=True, consumeErrors=True) return dl retrying_caller = RetryingCaller(0, reactor=self._clock) d = retrying_caller.retry(_call) self._clock.advance(0) self. assertFailure(d, RuntimeError) self.assertEqual(d.result.args, ( err_msg, )) d.addErrback(lambda _res: None) # silence the unhandled error
def test_retry_on(self): errors = ( TimeoutError, TimeoutError, t_defer.CancelledError ) retries = len(errors) + 1 failure_inspector = RetryingCaller.RetryOnFailureInspectorMixin() failure_inspector.retry_on = ( TimeoutError, ) retrier = RetryingCaller(retries, failure_inspector_factory=failure_inspector, reactor=self._clock) error_raiser = mock.Mock(side_effect=errors) d = retrier.retry(error_raiser, -273) self._clock.advance(0) self._clock.pump(RetryingCaller.DoublingBackoffGeneratorFactoryMixin._basegenerator(retries)) # pylint: disable=protected-access expected = [ ( ( -273, ), ), ( ( -273, ), ), ( ( -273, ), ), ] self.assertTrue(d.called) self.assertEqual(error_raiser.call_args_list, expected) self.assertFailure(d, t_defer.CancelledError) d.addErrback(lambda _res: None) # silence the unhandled error