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_wrap_method_with_overriding_retry_deadline( utcnow, unused_sleep): fake_call = grpc_helpers_async.FakeUnaryUnaryCall(42) method = mock.Mock( spec=aio.UnaryUnaryMultiCallable, side_effect=([exceptions.InternalServerError(None)] * 4) + [fake_call], ) default_retry = retry_async.AsyncRetry() default_timeout = timeout.ExponentialTimeout(deadline=60) wrapped_method = gapic_v1.method_async.wrap_method(method, default_retry, default_timeout) # Overriding only the retry's deadline should also override the timeout's # deadline. result = await wrapped_method(retry=default_retry.with_deadline(30)) assert result == 42 timeout_args = [call[1]["timeout"] for call in method.call_args_list] assert timeout_args == [5.0, 10.0, 20.0, 26.0, 25.0] assert utcnow.call_count == ( 1 + 1 # Compute wait_for timeout in retry_async + 5 # First to set the deadline. + 5 # One for each min(timeout, maximum, (DEADLINE - NOW).seconds) )
def test_constructor_defaults(self): retry_ = retry_async.AsyncRetry() assert retry_._predicate == retry_async.if_transient_error assert retry_._initial == 1 assert retry_._maximum == 60 assert retry_._multiplier == 2 assert retry_._deadline == 120 assert retry_._on_error is None
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_wrap_method_with_overriding_timeout_as_a_number(): fake_call = grpc_helpers_async.FakeUnaryUnaryCall(42) method = mock.Mock(spec=aio.UnaryUnaryMultiCallable, return_value=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(timeout=22) assert result == 42 method.assert_called_once_with(timeout=22, metadata=mock.ANY)
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___call___and_execute_success(self, sleep): retry_ = retry_async.AsyncRetry() target = mock.AsyncMock(spec=["__call__"], return_value=42) # __name__ is needed by functools.partial. target.__name__ = "target" decorated = retry_(target) target.assert_not_called() result = await decorated("meep") assert result == 42 target.assert_called_once_with("meep") sleep.assert_not_called()
def test_with_delay_noop(self): retry_ = retry_async.AsyncRetry( predicate=mock.sentinel.predicate, initial=1, maximum=2, multiplier=3, deadline=4, on_error=mock.sentinel.on_error, ) new_retry = retry_.with_delay() assert retry_ is not new_retry assert new_retry._initial == retry_._initial assert new_retry._maximum == retry_._maximum assert new_retry._multiplier == retry_._multiplier
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_default_retry_and_timeout(unused_sleep): fake_call = grpc_helpers_async.FakeUnaryUnaryCall(42) method = mock.Mock( spec=aio.UnaryUnaryMultiCallable, side_effect=[exceptions.InternalServerError(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() assert result == 42 assert method.call_count == 2 method.assert_called_with(timeout=60, metadata=mock.ANY)
def test_constructor_options(self): _some_function = mock.Mock() retry_ = retry_async.AsyncRetry( predicate=mock.sentinel.predicate, initial=1, maximum=2, multiplier=3, deadline=4, on_error=_some_function, ) assert retry_._predicate == mock.sentinel.predicate assert retry_._initial == 1 assert retry_._maximum == 2 assert retry_._multiplier == 3 assert retry_._deadline == 4 assert retry_._on_error is _some_function
def test_with_delay(self): retry_ = retry_async.AsyncRetry( predicate=mock.sentinel.predicate, initial=1, maximum=2, multiplier=3, deadline=4, on_error=mock.sentinel.on_error, ) new_retry = retry_.with_delay(initial=1, maximum=2, multiplier=3) assert retry_ is not new_retry assert new_retry._initial == 1 assert new_retry._maximum == 2 assert new_retry._multiplier == 3 # the rest of the attributes should remain the same assert new_retry._deadline == retry_._deadline assert new_retry._predicate is retry_._predicate assert new_retry._on_error is retry_._on_error
def test___str__(self): def if_exception_type(exc): return bool(exc) # pragma: NO COVER # Explicitly set all attributes as changed Retry defaults should not # cause this test to start failing. retry_ = retry_async.AsyncRetry( predicate=if_exception_type, initial=1.0, maximum=60.0, multiplier=2.0, deadline=120.0, on_error=None, ) assert re.match( (r"<AsyncRetry predicate=<function.*?if_exception_type.*?>, " r"initial=1.0, maximum=60.0, multiplier=2.0, deadline=120.0, " r"on_error=None>"), str(retry_), )
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
from google.api_core.future import base class _OperationNotComplete(Exception): """Private exception used for polling via retry.""" pass RETRY_PREDICATE = retry.if_exception_type( _OperationNotComplete, exceptions.TooManyRequests, exceptions.InternalServerError, exceptions.BadGateway, ) DEFAULT_RETRY = retry_async.AsyncRetry(predicate=RETRY_PREDICATE) class AsyncFuture(base.Future): """A Future that polls peer service to self-update. The :meth:`done` method should be implemented by subclasses. The polling behavior will repeatedly call ``done`` until it returns True. .. note:: Privacy here is intended to prevent the final class from overexposing, not to prevent subclasses from accessing methods. Args: retry (google.api_core.retry.Retry): The retry configuration used