async def test___init___when_retry_is_executed(self, sleep, uniform): _some_function = mock.Mock() retry_ = retry_async.AsyncRetry( predicate=retry_async.if_exception_type(ValueError), on_error=_some_function) # check the proper creation of the class assert retry_._on_error is _some_function target = mock.AsyncMock(spec=["__call__"], side_effect=[ValueError(), ValueError(), 42]) # __name__ is needed by functools.partial. target.__name__ = "target" wrapped = retry_(target) target.assert_not_called() result = await wrapped("meep") assert result == 42 assert target.call_count == 3 assert _some_function.call_count == 2 target.assert_has_calls([mock.call("meep"), mock.call("meep")]) sleep.assert_any_call(retry_._initial)
async def test_retry_target_non_retryable_error(utcnow, sleep): predicate = retry_async.if_exception_type(ValueError) exception = TypeError() target = mock.Mock(side_effect=exception) with pytest.raises(TypeError) as exc_info: await retry_async.retry_target(target, predicate, range(10), None) assert exc_info.value == exception sleep.assert_not_called()
async def test_done_w_retry(): RETRY_PREDICATE = retry_async.if_exception_type(exceptions.TooManyRequests) test_retry = retry_async.AsyncRetry(predicate=RETRY_PREDICATE) expected_result = struct_pb2.Struct() responses = [ make_operation_proto(), # Second operation response includes the result. make_operation_proto(done=True, response=expected_result), ] future, refresh, _ = make_operation_future(responses) await future.done(retry=test_retry) refresh.assert_called_once_with(retry=test_retry)
async def test_retry_target_success(utcnow, sleep): predicate = retry_async.if_exception_type(ValueError) call_count = [0] async def target(): call_count[0] += 1 if call_count[0] < 3: raise ValueError() return 42 result = await retry_async.retry_target(target, predicate, range(10), None) assert result == 42 assert call_count[0] == 3 sleep.assert_has_calls([mock.call(0), mock.call(1)])
async def test___call___and_execute_retry_hitting_deadline( self, sleep, uniform): on_error = mock.Mock(spec=["__call__"], side_effect=[None] * 10) retry_ = retry_async.AsyncRetry( predicate=retry_async.if_exception_type(ValueError), initial=1.0, maximum=1024.0, multiplier=2.0, deadline=9.9, ) utcnow = datetime.datetime.utcnow() utcnow_patcher = mock.patch("google.api_core.datetime_helpers.utcnow", return_value=utcnow) target = mock.AsyncMock(spec=["__call__"], side_effect=[ValueError()] * 10) # __name__ is needed by functools.partial. target.__name__ = "target" decorated = retry_(target, on_error=on_error) target.assert_not_called() with utcnow_patcher as patched_utcnow: # Make sure that calls to fake asyncio.sleep() also advance the mocked # time clock. def increase_time(sleep_delay): patched_utcnow.return_value += datetime.timedelta( seconds=sleep_delay) sleep.side_effect = increase_time with pytest.raises(exceptions.RetryError): await decorated("meep") assert target.call_count == 5 target.assert_has_calls([mock.call("meep")] * 5) assert on_error.call_count == 5 # check the delays assert sleep.call_count == 4 # once between each successive target calls last_wait = sleep.call_args.args[0] total_wait = sum(call_args.args[0] for call_args in sleep.call_args_list) assert last_wait == 2.9 # and not 8.0, because the last delay was shortened assert total_wait == 9.9 # the same as the deadline
async def test_wrap_method_with_overriding_retry_and_timeout(unused_sleep): fake_call = grpc_helpers_async.FakeUnaryUnaryCall(42) method = mock.Mock( spec=aio.UnaryUnaryMultiCallable, side_effect=[exceptions.NotFound(None), fake_call], ) default_retry = retry_async.AsyncRetry() default_timeout = timeout.ConstantTimeout(60) wrapped_method = gapic_v1.method_async.wrap_method(method, default_retry, default_timeout) result = await wrapped_method( retry=retry_async.AsyncRetry( retry_async.if_exception_type(exceptions.NotFound)), timeout=timeout.ConstantTimeout(22), ) assert result == 42 assert method.call_count == 2 method.assert_called_with(timeout=22, metadata=mock.ANY)
async def test___init___without_retry_executed(self, sleep): _some_function = mock.Mock() retry_ = retry_async.AsyncRetry( predicate=retry_async.if_exception_type(ValueError), on_error=_some_function) # check the proper creation of the class assert retry_._on_error is _some_function target = mock.AsyncMock(spec=["__call__"], side_effect=[42]) # __name__ is needed by functools.partial. target.__name__ = "target" wrapped = retry_(target) result = await wrapped("meep") assert result == 42 target.assert_called_once_with("meep") sleep.assert_not_called() _some_function.assert_not_called()
async def test___call___and_execute_retry(self, sleep, uniform): on_error = mock.Mock(spec=["__call__"], side_effect=[None]) retry_ = retry_async.AsyncRetry( predicate=retry_async.if_exception_type(ValueError)) target = mock.AsyncMock(spec=["__call__"], side_effect=[ValueError(), 42]) # __name__ is needed by functools.partial. target.__name__ = "target" decorated = retry_(target, on_error=on_error) target.assert_not_called() result = await decorated("meep") assert result == 42 assert target.call_count == 2 target.assert_has_calls([mock.call("meep"), mock.call("meep")]) sleep.assert_called_once_with(retry_._initial) assert on_error.call_count == 1
async def test_retry_target_deadline_exceeded(utcnow, sleep): predicate = retry_async.if_exception_type(ValueError) exception = ValueError("meep") target = mock.Mock(side_effect=exception) # Setup the timeline so that the first call takes 5 seconds but the second # call takes 6, which puts the retry over the deadline. utcnow.side_effect = [ # The first call to utcnow establishes the start of the timeline. datetime.datetime.min, datetime.datetime.min + datetime.timedelta(seconds=5), datetime.datetime.min + datetime.timedelta(seconds=11), ] with pytest.raises(exceptions.RetryError) as exc_info: await retry_async.retry_target(target, predicate, range(10), deadline=10) assert exc_info.value.cause == exception assert exc_info.match("Deadline of 10.0s exceeded") assert exc_info.match("last exception: meep") assert target.call_count == 2
async def test_retry_target_w_on_error(utcnow, sleep): predicate = retry_async.if_exception_type(ValueError) call_count = {"target": 0} to_raise = ValueError() async def target(): call_count["target"] += 1 if call_count["target"] < 3: raise to_raise return 42 on_error = mock.Mock() result = await retry_async.retry_target(target, predicate, range(10), None, on_error=on_error) assert result == 42 assert call_count["target"] == 3 on_error.assert_has_calls([mock.call(to_raise), mock.call(to_raise)]) sleep.assert_has_calls([mock.call(0), mock.call(1)])