Skip to content

Commit 523377e

Browse files
fix: change customer StorageException from RuntimeException to StatusRuntimeException (#1559)
* fix: change customer StorageException from RuntimeException to StatusRuntimeException so that Beam connector can consume it. * fix clirr fix clirr fix clirr nit * update unit test * lint * update based on comments * add another unit test * clean up * clean up * update clirr and test case
1 parent 42b28e0 commit 523377e

File tree

4 files changed

+69
-17
lines changed

4 files changed

+69
-17
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
3+
<differences>
4+
<difference>
5+
<differenceType>7005</differenceType>
6+
<className>com/google/cloud/bigquery/storage/v1/Exceptions$SchemaMismatchedException</className>
7+
<method>Exceptions$SchemaMismatchedException(java.lang.String, java.lang.String, java.lang.Throwable)</method>
8+
<to>Exceptions$SchemaMismatchedException(io.grpc.Status, io.grpc.Metadata, java.lang.String)</to>
9+
</difference>
10+
<difference>
11+
<differenceType>7005</differenceType>
12+
<className>com/google/cloud/bigquery/storage/v1/Exceptions$StreamFinalizedException</className>
13+
<method>Exceptions$StreamFinalizedException(java.lang.String, java.lang.String, java.lang.Throwable)</method>
14+
<to>Exceptions$StreamFinalizedException(io.grpc.Status, io.grpc.Metadata, java.lang.String)</to>
15+
</difference>
16+
</differences>

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/Exceptions.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
import com.google.common.collect.ImmutableMap;
2020
import com.google.protobuf.Any;
2121
import com.google.protobuf.InvalidProtocolBufferException;
22+
import io.grpc.Metadata;
23+
import io.grpc.Status;
24+
import io.grpc.StatusRuntimeException;
2225
import io.grpc.protobuf.StatusProto;
2326
import javax.annotation.Nullable;
2427

@@ -30,7 +33,7 @@ public WriterClosedException(String streamName) {
3033
}
3134
}
3235
/** Main Storage Exception. Might contain map of streams to errors for that stream. */
33-
public static class StorageException extends RuntimeException {
36+
public static class StorageException extends StatusRuntimeException {
3437

3538
private final ImmutableMap<String, GrpcStatusCode> errors;
3639
private final String streamName;
@@ -40,11 +43,11 @@ private StorageException() {
4043
}
4144

4245
private StorageException(
43-
@Nullable String message,
44-
@Nullable Throwable cause,
46+
@Nullable Status grpcStatus,
47+
@Nullable Metadata metadata,
4548
@Nullable String streamName,
4649
ImmutableMap<String, GrpcStatusCode> errors) {
47-
super(message, cause);
50+
super(grpcStatus, metadata);
4851
this.streamName = streamName;
4952
this.errors = errors;
5053
}
@@ -60,8 +63,8 @@ public String getStreamName() {
6063

6164
/** Stream has already been finalized. */
6265
public static final class StreamFinalizedException extends StorageException {
63-
protected StreamFinalizedException(String name, String message, Throwable cause) {
64-
super(message, cause, name, ImmutableMap.of());
66+
protected StreamFinalizedException(Status grpcStatus, Metadata metadata, String name) {
67+
super(grpcStatus, metadata, name, ImmutableMap.of());
6568
}
6669
}
6770

@@ -70,8 +73,8 @@ protected StreamFinalizedException(String name, String message, Throwable cause)
7073
* This can be resolved by updating the table's schema with the message schema.
7174
*/
7275
public static final class SchemaMismatchedException extends StorageException {
73-
protected SchemaMismatchedException(String name, String message, Throwable cause) {
74-
super(message, cause, name, ImmutableMap.of());
76+
protected SchemaMismatchedException(Status grpcStatus, Metadata metadata, String name) {
77+
super(grpcStatus, metadata, name, ImmutableMap.of());
7578
}
7679
}
7780

@@ -98,15 +101,17 @@ private static StorageError toStorageError(com.google.rpc.Status rpcStatus) {
98101
public static StorageException toStorageException(
99102
com.google.rpc.Status rpcStatus, Throwable exception) {
100103
StorageError error = toStorageError(rpcStatus);
104+
Status grpcStatus =
105+
Status.fromCodeValue(rpcStatus.getCode()).withDescription(rpcStatus.getMessage());
101106
if (error == null) {
102107
return null;
103108
}
104109
switch (error.getCode()) {
105110
case STREAM_FINALIZED:
106-
return new StreamFinalizedException(error.getEntity(), error.getErrorMessage(), exception);
111+
return new StreamFinalizedException(grpcStatus, null, error.getEntity());
107112

108113
case SCHEMA_MISMATCH_EXTRA_FIELDS:
109-
return new SchemaMismatchedException(error.getEntity(), error.getErrorMessage(), exception);
114+
return new SchemaMismatchedException(grpcStatus, null, error.getEntity());
110115

111116
default:
112117
return null;

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1/StreamWriterTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.api.gax.grpc.testing.MockServiceHelper;
2727
import com.google.api.gax.rpc.ApiException;
2828
import com.google.api.gax.rpc.StatusCode.Code;
29+
import com.google.api.gax.rpc.UnknownException;
2930
import com.google.cloud.bigquery.storage.test.Test.FooType;
3031
import com.google.cloud.bigquery.storage.v1.StorageError.StorageErrorCode;
3132
import com.google.common.base.Strings;
@@ -343,6 +344,21 @@ public void testAppendFailedSchemaError() throws Exception {
343344
writer.close();
344345
}
345346

347+
@Test
348+
public void testAppendFailRandomException() throws Exception {
349+
StreamWriter writer = getTestStreamWriter();
350+
// Trigger a non-StatusRuntimeException for append operation (although grpc API should not
351+
// return anything other than StatusRuntimeException)
352+
IllegalArgumentException illegalArgumentException =
353+
new IllegalArgumentException("Illegal argument");
354+
testBigQueryWrite.addException(illegalArgumentException);
355+
ApiFuture<AppendRowsResponse> appendFuture1 = sendTestMessage(writer, new String[] {"A"});
356+
UnknownException actualError = assertFutureException(UnknownException.class, appendFuture1);
357+
assertEquals(Code.UNKNOWN, actualError.getStatusCode().getCode());
358+
359+
writer.close();
360+
}
361+
346362
@Test
347363
public void longIdleBetweenAppends() throws Exception {
348364
StreamWriter writer = getTestStreamWriter();

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1/it/ITBigQueryWriteManualClientTest.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.common.truth.Truth.assertThat;
2020
import static org.junit.Assert.assertEquals;
2121
import static org.junit.Assert.assertFalse;
22+
import static org.junit.Assert.assertNotNull;
2223
import static org.junit.Assert.assertTrue;
2324

2425
import com.google.api.core.ApiFuture;
@@ -27,11 +28,15 @@
2728
import com.google.cloud.bigquery.Schema;
2829
import com.google.cloud.bigquery.storage.test.Test.*;
2930
import com.google.cloud.bigquery.storage.v1.*;
31+
import com.google.cloud.bigquery.storage.v1.Exceptions.SchemaMismatchedException;
32+
import com.google.cloud.bigquery.storage.v1.Exceptions.StreamFinalizedException;
3033
import com.google.cloud.bigquery.testing.RemoteBigQueryHelper;
3134
import com.google.common.collect.ImmutableList;
3235
import com.google.protobuf.ByteString;
3336
import com.google.protobuf.Descriptors;
3437
import com.google.protobuf.Descriptors.DescriptorValidationException;
38+
import io.grpc.Status;
39+
import io.grpc.Status.Code;
3540
import java.io.IOException;
3641
import java.math.BigDecimal;
3742
import java.util.*;
@@ -835,8 +840,10 @@ public void testStreamSchemaMisMatchError() throws IOException, InterruptedExcep
835840
Assert.fail("Should fail");
836841
} catch (ExecutionException e) {
837842
assertEquals(Exceptions.SchemaMismatchedException.class, e.getCause().getClass());
838-
assertThat(e.getCause().getMessage())
839-
.contains("Schema mismatch due to extra fields in user schema");
843+
Exceptions.SchemaMismatchedException actualError = (SchemaMismatchedException) e.getCause();
844+
assertNotNull(actualError.getStreamName());
845+
// This verifies that the Beam connector can consume this custom exception's grpc StatusCode
846+
assertEquals(Code.INVALID_ARGUMENT, Status.fromThrowable(e.getCause()).getCode());
840847
}
841848
}
842849
}
@@ -853,20 +860,28 @@ public void testStreamFinalizedError()
853860
.build());
854861
try (StreamWriter streamWriter =
855862
StreamWriter.newBuilder(writeStream.getName())
856-
.setWriterSchema(ProtoSchemaConverter.convert(UpdatedFooType.getDescriptor()))
863+
.setWriterSchema(ProtoSchemaConverter.convert(FooType.getDescriptor()))
857864
.build()) {
865+
// Append once before finalizing the stream
866+
ApiFuture<AppendRowsResponse> response =
867+
streamWriter.append(CreateProtoRowsMultipleColumns(new String[] {"a"}), /*offset=*/ 0);
868+
response.get();
858869
// Finalize the stream in order to trigger STREAM_FINALIZED error
859870
client.finalizeWriteStream(
860871
FinalizeWriteStreamRequest.newBuilder().setName(writeStream.getName()).build());
861872
// Try to append to a finalized stream
862-
ApiFuture<AppendRowsResponse> response =
863-
streamWriter.append(CreateProtoRowsMultipleColumns(new String[] {"a"}), /*offset=*/ 0);
873+
ApiFuture<AppendRowsResponse> response2 =
874+
streamWriter.append(CreateProtoRowsMultipleColumns(new String[] {"a"}), /*offset=*/ 1);
864875
try {
865-
response.get();
876+
response2.get();
866877
Assert.fail("Should fail");
867878
} catch (ExecutionException e) {
868879
assertEquals(Exceptions.StreamFinalizedException.class, e.getCause().getClass());
869-
assertThat(e.getCause().getMessage()).contains("Stream is finalized");
880+
Exceptions.StreamFinalizedException actualError = (StreamFinalizedException) e.getCause();
881+
assertNotNull(actualError.getStreamName());
882+
// This verifies that the Beam connector can consume this custom exception's grpc StatusCode
883+
assertEquals(Code.INVALID_ARGUMENT, Status.fromThrowable(e.getCause()).getCode());
884+
assertThat(e.getCause().getMessage()).contains("Stream has been finalized");
870885
}
871886
}
872887
}

0 commit comments

Comments
 (0)