@@ -182,35 +182,94 @@ def test_constructor_options(self):
182182        assert  retry_ ._on_error  is  _some_function 
183183
184184    def  test_with_deadline (self ):
185-         retry_  =  retry .Retry ()
185+         retry_  =  retry .Retry (
186+             predicate = mock .sentinel .predicate ,
187+             initial = 1 ,
188+             maximum = 2 ,
189+             multiplier = 3 ,
190+             deadline = 4 ,
191+             on_error = mock .sentinel .on_error ,
192+         )
186193        new_retry  =  retry_ .with_deadline (42 )
187194        assert  retry_  is  not   new_retry 
188195        assert  new_retry ._deadline  ==  42 
189196
197+         # the rest of the attributes should remain the same 
198+         assert  new_retry ._predicate  is  retry_ ._predicate 
199+         assert  new_retry ._initial  ==  retry_ ._initial 
200+         assert  new_retry ._maximum  ==  retry_ ._maximum 
201+         assert  new_retry ._multiplier  ==  retry_ ._multiplier 
202+         assert  new_retry ._on_error  is  retry_ ._on_error 
203+ 
190204    def  test_with_predicate (self ):
191-         retry_  =  retry .Retry ()
205+         retry_  =  retry .Retry (
206+             predicate = mock .sentinel .predicate ,
207+             initial = 1 ,
208+             maximum = 2 ,
209+             multiplier = 3 ,
210+             deadline = 4 ,
211+             on_error = mock .sentinel .on_error ,
212+         )
192213        new_retry  =  retry_ .with_predicate (mock .sentinel .predicate )
193214        assert  retry_  is  not   new_retry 
194215        assert  new_retry ._predicate  ==  mock .sentinel .predicate 
195216
217+         # the rest of the attributes should remain the same 
218+         assert  new_retry ._deadline  ==  retry_ ._deadline 
219+         assert  new_retry ._initial  ==  retry_ ._initial 
220+         assert  new_retry ._maximum  ==  retry_ ._maximum 
221+         assert  new_retry ._multiplier  ==  retry_ ._multiplier 
222+         assert  new_retry ._on_error  is  retry_ ._on_error 
223+ 
196224    def  test_with_delay_noop (self ):
197-         retry_  =  retry .Retry ()
225+         retry_  =  retry .Retry (
226+             predicate = mock .sentinel .predicate ,
227+             initial = 1 ,
228+             maximum = 2 ,
229+             multiplier = 3 ,
230+             deadline = 4 ,
231+             on_error = mock .sentinel .on_error ,
232+         )
198233        new_retry  =  retry_ .with_delay ()
199234        assert  retry_  is  not   new_retry 
200235        assert  new_retry ._initial  ==  retry_ ._initial 
201236        assert  new_retry ._maximum  ==  retry_ ._maximum 
202237        assert  new_retry ._multiplier  ==  retry_ ._multiplier 
203238
204239    def  test_with_delay (self ):
205-         retry_  =  retry .Retry ()
240+         retry_  =  retry .Retry (
241+             predicate = mock .sentinel .predicate ,
242+             initial = 1 ,
243+             maximum = 2 ,
244+             multiplier = 3 ,
245+             deadline = 4 ,
246+             on_error = mock .sentinel .on_error ,
247+         )
206248        new_retry  =  retry_ .with_delay (initial = 1 , maximum = 2 , multiplier = 3 )
207249        assert  retry_  is  not   new_retry 
208250        assert  new_retry ._initial  ==  1 
209251        assert  new_retry ._maximum  ==  2 
210252        assert  new_retry ._multiplier  ==  3 
211253
254+         # the rest of the attributes should remain the same 
255+         assert  new_retry ._deadline  ==  retry_ ._deadline 
256+         assert  new_retry ._predicate  is  retry_ ._predicate 
257+         assert  new_retry ._on_error  is  retry_ ._on_error 
258+ 
212259    def  test___str__ (self ):
213-         retry_  =  retry .Retry ()
260+         def  if_exception_type (exc ):
261+             return  bool (exc )  # pragma: NO COVER 
262+ 
263+         # Explicitly set all attributes as changed Retry defaults should not 
264+         # cause this test to start failing. 
265+         retry_  =  retry .Retry (
266+             predicate = if_exception_type ,
267+             initial = 1.0 ,
268+             maximum = 60.0 ,
269+             multiplier = 2.0 ,
270+             deadline = 120.0 ,
271+             on_error = None ,
272+         )
214273        assert  re .match (
215274            (
216275                r"<Retry predicate=<function.*?if_exception_type.*?>, " 
@@ -259,6 +318,54 @@ def test___call___and_execute_retry(self, sleep, uniform):
259318        sleep .assert_called_once_with (retry_ ._initial )
260319        assert  on_error .call_count  ==  1 
261320
321+     # Make uniform return half of its maximum, which is the calculated sleep time. 
322+     @mock .patch ("random.uniform" , autospec = True , side_effect = lambda  m , n : n  /  2.0 ) 
323+     @mock .patch ("time.sleep" , autospec = True ) 
324+     def  test___call___and_execute_retry_hitting_deadline (self , sleep , uniform ):
325+ 
326+         on_error  =  mock .Mock (spec = ["__call__" ], side_effect = [None ] *  10 )
327+         retry_  =  retry .Retry (
328+             predicate = retry .if_exception_type (ValueError ),
329+             initial = 1.0 ,
330+             maximum = 1024.0 ,
331+             multiplier = 2.0 ,
332+             deadline = 9.9 ,
333+         )
334+ 
335+         utcnow  =  datetime .datetime .utcnow ()
336+         utcnow_patcher  =  mock .patch (
337+             "google.api_core.datetime_helpers.utcnow" , return_value = utcnow 
338+         )
339+ 
340+         target  =  mock .Mock (spec = ["__call__" ], side_effect = [ValueError ()] *  10 )
341+         # __name__ is needed by functools.partial. 
342+         target .__name__  =  "target" 
343+ 
344+         decorated  =  retry_ (target , on_error = on_error )
345+         target .assert_not_called ()
346+ 
347+         with  utcnow_patcher  as  patched_utcnow :
348+             # Make sure that calls to fake time.sleep() also advance the mocked 
349+             # time clock. 
350+             def  increase_time (sleep_delay ):
351+                 patched_utcnow .return_value  +=  datetime .timedelta (seconds = sleep_delay )
352+             sleep .side_effect  =  increase_time 
353+ 
354+             with  pytest .raises (exceptions .RetryError ):
355+                 decorated ("meep" )
356+ 
357+         assert  target .call_count  ==  5 
358+         target .assert_has_calls ([mock .call ("meep" )] *  5 )
359+         assert  on_error .call_count  ==  5 
360+ 
361+         # check the delays 
362+         assert  sleep .call_count  ==  4   # once between each successive target calls 
363+         last_wait  =  sleep .call_args .args [0 ]
364+         total_wait  =  sum (call_args .args [0 ] for  call_args  in  sleep .call_args_list )
365+ 
366+         assert  last_wait  ==  2.9    # and not 8.0, because the last delay was shortened 
367+         assert  total_wait  ==  9.9   # the same as the deadline 
368+ 
262369    @mock .patch ("time.sleep" , autospec = True ) 
263370    def  test___init___without_retry_executed (self , sleep ):
264371        _some_function  =  mock .Mock ()
0 commit comments