1515 */
1616package com .google .cloud .bigtable .data .v2 .stub ;
1717
18- import static com .google .cloud .bigtable .gaxx .retrying .RetryInfoRetryAlgorithm .RETRY_INFO_KEY ;
1918import static com .google .common .truth .Truth .assertThat ;
2019
2120import com .google .api .gax .core .NoCredentialsProvider ;
2221import com .google .api .gax .grpc .GrpcStatusCode ;
2322import com .google .api .gax .grpc .GrpcTransportChannel ;
2423import com .google .api .gax .rpc .ApiException ;
24+ import com .google .api .gax .rpc .ErrorDetails ;
2525import com .google .api .gax .rpc .FixedTransportChannelProvider ;
2626import com .google .api .gax .rpc .InternalException ;
2727import com .google .api .gax .rpc .UnavailableException ;
5555import com .google .cloud .bigtable .data .v2 .models .RowMutation ;
5656import com .google .cloud .bigtable .data .v2 .models .RowMutationEntry ;
5757import com .google .common .base .Stopwatch ;
58+ import com .google .common .collect .ImmutableList ;
5859import com .google .common .collect .Queues ;
60+ import com .google .protobuf .Any ;
5961import com .google .rpc .RetryInfo ;
6062import io .grpc .Metadata ;
6163import io .grpc .Status ;
@@ -77,6 +79,9 @@ public class RetryInfoTest {
7779
7880 @ Rule public GrpcServerRule serverRule = new GrpcServerRule ();
7981
82+ private static final Metadata .Key <byte []> ERROR_DETAILS_KEY =
83+ Metadata .Key .of ("grpc-status-details-bin" , Metadata .BINARY_BYTE_MARSHALLER );
84+
8085 private FakeBigtableService service ;
8186 private BigtableDataClient client ;
8287 private BigtableDataSettings .Builder settings ;
@@ -167,6 +172,42 @@ public void testMutateRowsNonRetryableErrorWithRetryInfo() {
167172 false );
168173 }
169174
175+ @ Test
176+ public void testMutateRowsPartialFailure () {
177+ service .partial = true ;
178+
179+ verifyRetryInfoIsUsed (
180+ () ->
181+ client .bulkMutateRows (
182+ BulkMutation .create ("fake-table" )
183+ .add (RowMutationEntry .create ("row-key-1" ).setCell ("cf" , "q" , "v" ))),
184+ true );
185+ }
186+
187+ @ Test
188+ public void testMutateRowsPartialFailureNonRetryableError () {
189+ service .partial = true ;
190+
191+ verifyRetryInfoIsUsed (
192+ () ->
193+ client .bulkMutateRows (
194+ BulkMutation .create ("fake-table" )
195+ .add (RowMutationEntry .create ("row-key-1" ).setCell ("cf" , "q" , "v" ))),
196+ false );
197+ }
198+
199+ // TODO: add this test back
200+ // @Test
201+ public void testMutateRowsPartialFailureCanBeDisabled () {
202+ service .partial = true ;
203+
204+ verifyRetryInfoCanBeDisabled (
205+ () ->
206+ client .bulkMutateRows (
207+ BulkMutation .create ("fake-table" )
208+ .add (RowMutationEntry .create ("row-key-1" ).setCell ("cf" , "q" , "v" ))));
209+ }
210+
170211 @ Test
171212 public void testMutateRowsDisableRetryInfo () throws IOException {
172213 settings .stubSettings ().setEnableRetryInfo (false );
@@ -366,27 +407,37 @@ private void verifyRetryInfoCanBeDisabled(Runnable runnable) {
366407 private void enqueueRetryableExceptionWithDelay (com .google .protobuf .Duration delay ) {
367408 Metadata trailers = new Metadata ();
368409 RetryInfo retryInfo = RetryInfo .newBuilder ().setRetryDelay (delay ).build ();
369- trailers .put (RETRY_INFO_KEY , retryInfo );
410+ ErrorDetails errorDetails =
411+ ErrorDetails .builder ().setRawErrorMessages (ImmutableList .of (Any .pack (retryInfo ))).build ();
412+ byte [] status =
413+ com .google .rpc .Status .newBuilder ().addDetails (Any .pack (retryInfo )).build ().toByteArray ();
414+ trailers .put (ERROR_DETAILS_KEY , status );
370415
371416 ApiException exception =
372417 new UnavailableException (
373418 new StatusRuntimeException (Status .UNAVAILABLE , trailers ),
374419 GrpcStatusCode .of (Status .Code .UNAVAILABLE ),
375- true );
420+ true ,
421+ errorDetails );
376422
377423 service .expectations .add (exception );
378424 }
379425
380426 private ApiException enqueueNonRetryableExceptionWithDelay (com .google .protobuf .Duration delay ) {
381427 Metadata trailers = new Metadata ();
382428 RetryInfo retryInfo = RetryInfo .newBuilder ().setRetryDelay (delay ).build ();
383- trailers .put (RETRY_INFO_KEY , retryInfo );
429+ ErrorDetails errorDetails =
430+ ErrorDetails .builder ().setRawErrorMessages (ImmutableList .of (Any .pack (retryInfo ))).build ();
431+ byte [] status =
432+ com .google .rpc .Status .newBuilder ().addDetails (Any .pack (retryInfo )).build ().toByteArray ();
433+ trailers .put (ERROR_DETAILS_KEY , status );
384434
385435 ApiException exception =
386436 new InternalException (
387437 new StatusRuntimeException (Status .INTERNAL , trailers ),
388438 GrpcStatusCode .of (Status .Code .INTERNAL ),
389- false );
439+ false ,
440+ errorDetails );
390441
391442 service .expectations .add (exception );
392443
@@ -395,6 +446,7 @@ private ApiException enqueueNonRetryableExceptionWithDelay(com.google.protobuf.D
395446
396447 private class FakeBigtableService extends BigtableGrpc .BigtableImplBase {
397448 Queue <Exception > expectations = Queues .newArrayDeque ();
449+ boolean partial = false ;
398450
399451 @ Override
400452 public void readRows (
@@ -434,8 +486,26 @@ public void mutateRows(
434486 responseObserver .onNext (builder .build ());
435487 responseObserver .onCompleted ();
436488 } else {
437- Exception expectedRpc = expectations .poll ();
438- responseObserver .onError (expectedRpc );
489+ if (partial ) {
490+ ApiException expectedRpc = (ApiException ) expectations .poll ();
491+ MutateRowsResponse .Builder builder = MutateRowsResponse .newBuilder ();
492+ builder .addEntries (
493+ 0 ,
494+ MutateRowsResponse .Entry .newBuilder ()
495+ .setStatus (
496+ com .google .rpc .Status .newBuilder ()
497+ .setCode (expectedRpc .getStatusCode ().getCode ().getHttpStatusCode ())
498+ .addDetails (Any .pack (expectedRpc .getErrorDetails ().getRetryInfo ())))
499+ .build ());
500+ for (int i = 1 ; i < request .getEntriesCount (); i ++) {
501+ builder .addEntriesBuilder ().setIndex (i );
502+ }
503+ responseObserver .onNext (builder .build ());
504+ responseObserver .onCompleted ();
505+ } else {
506+ Exception expectedRpc = expectations .poll ();
507+ responseObserver .onError (expectedRpc );
508+ }
439509 }
440510 }
441511
0 commit comments