@@ -601,7 +601,7 @@ def test_end_on_empty_operation(self):
601601 assert final_op .final_status == StatusCode .OK
602602 assert final_op .completed_attempts == []
603603
604- def test_build_wrapped_predicate (self ):
604+ def test_build_wrapped_fn_handlers_predicate (self ):
605605 """
606606 predicate generated by object should terminate attempt or operation
607607 based on passed in predicate
@@ -610,23 +610,61 @@ def test_build_wrapped_predicate(self):
610610 cls = type (self ._make_one (object ()))
611611 # ensure predicate is called with the exception
612612 mock_predicate = mock .Mock ()
613- cls .build_wrapped_predicate (mock .Mock (), mock_predicate )(input_exc )
613+ pred , _ = cls .build_wrapped_fn_handlers (mock .Mock (), mock_predicate )
614+ pred (input_exc )
614615 assert mock_predicate .call_count == 1
615616 assert mock_predicate .call_args [0 ][0 ] == input_exc
616617 assert len (mock_predicate .call_args [0 ]) == 1
617618 # if predicate is true, end the attempt
618619 mock_instance = mock .Mock ()
619- cls .build_wrapped_predicate (mock_instance , lambda x : True )(input_exc )
620+ pred , _ = cls .build_wrapped_fn_handlers (mock_instance , lambda x : True )
621+ pred (input_exc )
620622 assert mock_instance .end_attempt_with_status .call_count == 1
621623 assert mock_instance .end_attempt_with_status .call_args [0 ][0 ] == input_exc
622624 assert len (mock_instance .end_attempt_with_status .call_args [0 ]) == 1
623625 # if predicate is false, end the operation
624626 mock_instance = mock .Mock ()
625- cls .build_wrapped_predicate (mock_instance , lambda x : False )(input_exc )
627+ pred , _ = cls .build_wrapped_fn_handlers (mock_instance , lambda x : False )
628+ pred (input_exc )
626629 assert mock_instance .end_with_status .call_count == 1
627630 assert mock_instance .end_with_status .call_args [0 ][0 ] == input_exc
628631 assert len (mock_instance .end_with_status .call_args [0 ]) == 1
629632
633+ def test_build_wrapped_fn_handlers_exc_factory (self ):
634+ """
635+ exception factory generated by object should terminate operation
636+ on timeout
637+ """
638+ from google .api_core .retry import RetryFailureReason
639+ from google .api_core .exceptions import DeadlineExceeded
640+
641+ cls = type (self ._make_one (object ()))
642+ # ensure inner factory is called with the exception
643+ _ , factory = cls .build_wrapped_fn_handlers (mock .Mock (), None )
644+ with mock .patch (
645+ "google.cloud.bigtable.data._metrics.data_model._retry_exception_factory"
646+ ) as mock_factory :
647+ expected_return = (object (), object ())
648+ mock_factory .return_value = expected_return
649+ args = ("a" , "b" , "c" )
650+ got_result = factory (* args )
651+ assert expected_return == got_result
652+ assert mock_factory .call_count == 1
653+ assert mock_factory .call_args [0 ] == args
654+
655+ # if called with reason == TIMEOUT, end the operation
656+ mock_instance = mock .Mock ()
657+ _ , factory = cls .build_wrapped_fn_handlers (mock_instance , None )
658+ factory ([], RetryFailureReason .TIMEOUT , None )
659+ assert mock_instance .end_with_status .call_count == 1
660+ assert type (mock_instance .end_with_status .call_args [0 ][0 ]) == DeadlineExceeded
661+
662+ # if called with reason==NON_RETRYABLE_ERROR, do not
663+ mock_instance = mock .Mock ()
664+ _ , factory = cls .build_wrapped_fn_handlers (mock_instance , None )
665+ factory ([], RetryFailureReason .NON_RETRYABLE_ERROR , None )
666+ assert mock_instance .end_with_status .call_count == 0
667+
630668 def test__exc_to_status (self ):
631669 """
632670 Should return grpc_status_code if grpc error, otherwise UNKNOWN
0 commit comments