@@ -1214,11 +1214,6 @@ async def test_bulk_mutate_rows_failure_unauthorized(
12141214 handler .clear ()
12151215 with pytest .raises (MutationsExceptionGroup ) as e :
12161216 await authorized_view .bulk_mutate_rows ([entry ])
1217- assert len (e .value .exceptions ) == 1
1218- assert isinstance (e .value .exceptions [0 ].__cause__ , GoogleAPICallError )
1219- assert (
1220- e .value .exceptions [0 ].__cause__ .grpc_status_code .name == "PERMISSION_DENIED"
1221- )
12221217 # validate counts
12231218 assert len (handler .completed_operations ) == 1
12241219 assert len (handler .completed_attempts ) == 1
@@ -1242,6 +1237,45 @@ async def test_bulk_mutate_rows_failure_unauthorized(
12421237 and attempt .gfe_latency_ns < operation .duration_ns
12431238 )
12441239
1240+ @CrossSync .pytest
1241+ async def test_bulk_mutate_rows_failure_unauthorized_with_retries (
1242+ self , handler , authorized_view , cluster_config
1243+ ):
1244+ """retry unauthorized request multiple times before timing out"""
1245+ from google .cloud .bigtable .data .mutations import RowMutationEntry , SetCell
1246+ from google .cloud .bigtable .data .exceptions import MutationsExceptionGroup
1247+
1248+ row_key = b"row_key_1"
1249+ mutation = SetCell ("unauthorized" , b"q" , b"v" )
1250+ entry = RowMutationEntry (row_key , [mutation ])
1251+
1252+ handler .clear ()
1253+ with pytest .raises (MutationsExceptionGroup ) as e :
1254+ await authorized_view .bulk_mutate_rows ([entry ], retryable_errors = [PermissionDenied ], operation_timeout = 25 )
1255+ assert len (e .value .exceptions ) == 1
1256+ # validate counts
1257+ assert len (handler .completed_operations ) == 1
1258+ assert len (handler .completed_attempts ) > 1
1259+ assert len (handler .cancelled_operations ) == 0
1260+ # validate operation
1261+ operation = handler .completed_operations [0 ]
1262+ assert operation .final_status .name == "DEADLINE_EXCEEDED"
1263+ assert operation .op_type .value == "MutateRows"
1264+ assert operation .is_streaming is False
1265+ assert len (operation .completed_attempts ) > 1
1266+ assert operation .cluster_id == next (iter (cluster_config .keys ()))
1267+ assert (
1268+ operation .zone
1269+ == cluster_config [operation .cluster_id ].location .split ("/" )[- 1 ]
1270+ )
1271+ # validate attempts
1272+ for attempt in handler .completed_attempts :
1273+ assert attempt .end_status .name == "PERMISSION_DENIED"
1274+ assert (
1275+ attempt .gfe_latency_ns >= 0
1276+ and attempt .gfe_latency_ns < operation .duration_ns
1277+ )
1278+
12451279 @CrossSync .pytest
12461280 async def test_mutate_rows_batcher (self , table , temp_rows , handler , cluster_config ):
12471281 from google .cloud .bigtable .data .mutations import RowMutationEntry
0 commit comments