Repository: googleapis/java-storage
Pull request #175 (2020-03-12 00:24:39)

chore: release 1.105.2-SNAPSHOT
:robot: I have created a release \*beep\* \*boop\* 
---
### Updating meta-information for bleeding-edge SNAPSHOT release.
---


This PR was generated with [Release Please](https://github.com/googleapis/release-please).


Patch:
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 84ca0fc1..8520f95c 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -2,7 +2,7 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <artifactId>google-cloud-storage</artifactId>
-  <version>1.105.1</version><!-- {x-version-update:google-cloud-storage:current} -->
+  <version>1.105.2-SNAPSHOT</version><!-- {x-version-update:google-cloud-storage:current} -->
   <packaging>jar</packaging>
   <name>Google Cloud Storage</name>
   <url>https://github.com/googleapis/java-storage</url>
@@ -12,7 +12,7 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-storage-parent</artifactId>
-    <version>1.105.1</version><!-- {x-version-update:google-cloud-storage:current} -->
+    <version>1.105.2-SNAPSHOT</version><!-- {x-version-update:google-cloud-storage:current} -->
   </parent>
   <properties>
     <site.installationModule>google-cloud-storage</site.installationModule>
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageException.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageException.java
index 01153a35..1f740194 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageException.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageException.java
@@ -33,6 +33,9 @@ import java.util.Set;
  */
 @InternalApi
 public final class StorageException extends BaseHttpServiceException {
+  private static final String INTERNAL_ERROR = "internalError";
+  private static final String CONNECTION_CLOSED_PREMATURELY = "connectionClosedPrematurely";
+  private static final String CONNECTION_RESET = "connectionReset";
 
   // see: https://cloud.google.com/storage/docs/resumable-uploads-xml#practices
   private static final Set<Error> RETRYABLE_ERRORS =
@@ -43,7 +46,9 @@ public final class StorageException extends BaseHttpServiceException {
           new Error(500, null),
           new Error(429, null),
           new Error(408, null),
-          new Error(null, "internalError"));
+          new Error(null, INTERNAL_ERROR),
+          new Error(null, CONNECTION_CLOSED_PREMATURELY),
+          new Error(null, CONNECTION_RESET));
 
   private static final long serialVersionUID = -4168430271327813063L;
 
@@ -55,6 +60,10 @@ public final class StorageException extends BaseHttpServiceException {
     super(code, message, null, true, RETRYABLE_ERRORS, cause);
   }
 
+  public StorageException(int code, String message, String reason, Throwable cause) {
+    super(code, message, reason, true, RETRYABLE_ERRORS, cause);
+  }
+
   public StorageException(IOException exception) {
     super(exception, true, RETRYABLE_ERRORS);
   }
@@ -73,4 +82,23 @@ public final class StorageException extends BaseHttpServiceException {
     BaseServiceException.translate(ex);
     throw new StorageException(UNKNOWN_CODE, ex.getMessage(), ex.getCause());
   }
+
+  /**
+   * Translate IOException to a StorageException representing the cause of the error. This method
+   * defaults to idempotent always being {@code true}. Additionally, this method translates
+   * transient issues Connection Closed Prematurely and Connection Reset as retryable errors.
+   *
+   * @returns {@code StorageException}
+   */
+  public static StorageException translate(IOException exception) {
+    if (exception.getMessage().contains("Connection closed prematurely")) {
+      return new StorageException(
+          0, exception.getMessage(), CONNECTION_CLOSED_PREMATURELY, exception);
+    } else if (exception.getMessage().contains("Connection reset")) {
+      return new StorageException(0, exception.getMessage(), CONNECTION_RESET, exception);
+    } else {
+      // default
+      return new StorageException(exception);
+    }
+  }
 }
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
index 5a6e947a..c677cbdb 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
@@ -701,7 +701,7 @@ public class HttpStorageRpc implements StorageRpc {
       return Tuple.of(etag, output.toByteArray());
     } catch (IOException ex) {
       span.setStatus(Status.UNKNOWN.withDescription(ex.getMessage()));
-      StorageException serviceException = translate(ex);
+      StorageException serviceException = StorageException.translate(ex);
       if (serviceException.getCode() == SC_REQUESTED_RANGE_NOT_SATISFIABLE) {
         return Tuple.of(null, new byte[0]);
       }
diff --git a/pom.xml b/pom.xml
index 802908a9..8d85eb5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <groupId>com.google.cloud</groupId>
   <artifactId>google-cloud-storage-parent</artifactId>
   <packaging>pom</packaging>
-  <version>1.105.1</version><!-- {x-version-update:google-cloud-storage:current} -->
+  <version>1.105.2-SNAPSHOT</version><!-- {x-version-update:google-cloud-storage:current} -->
   <name>Storage Parent</name>
   <url>https://github.com/googleapis/java-storage</url>
   <description>
@@ -103,7 +103,7 @@
       <dependency>
         <groupId>io.grpc</groupId>
         <artifactId>grpc-bom</artifactId>
-        <version>1.28.0</version>
+        <version>1.27.2</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
diff --git a/versions.txt b/versions.txt
index 3661bfee..74ebd7ca 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
 # Format:
 # module:released-version:current-version
 
-google-cloud-storage:1.105.1:1.105.1
\ No newline at end of file
+google-cloud-storage:1.105.1:1.105.2-SNAPSHOT
\ No newline at end of file


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobReadChannelTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobReadChannelTest.java
index 181e5414..f1388ebe 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobReadChannelTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobReadChannelTest.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.fail;
 
 import com.google.cloud.ReadChannel;
 import com.google.cloud.RestorableState;
-import com.google.cloud.ServiceOptions;
 import com.google.cloud.Tuple;
 import com.google.cloud.storage.spi.StorageRpcFactory;
 import com.google.cloud.storage.spi.v1.StorageRpc;
@@ -68,7 +67,6 @@ public class BlobReadChannelTest {
         StorageOptions.newBuilder()
             .setProjectId("projectId")
             .setServiceRpcFactory(rpcFactoryMock)
-            .setRetrySettings(ServiceOptions.getNoRetrySettings())
             .build();
   }
 
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageExceptionTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageExceptionTest.java
index 5060fdc6..e065f401 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageExceptionTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageExceptionTest.java
@@ -32,7 +32,9 @@ import com.google.api.client.http.HttpResponseException;
 import com.google.cloud.BaseServiceException;
 import com.google.cloud.RetryHelper.RetryHelperException;
 import java.io.IOException;
+import java.net.SocketException;
 import java.net.SocketTimeoutException;
+import javax.net.ssl.SSLException;
 import org.junit.Test;
 
 public class StorageExceptionTest {
@@ -135,6 +137,29 @@ public class StorageExceptionTest {
     assertTrue(exception.isRetryable());
   }
 
+  @Test
+  public void testTranslateConnectionReset() {
+    StorageException exception =
+        StorageException.translate(
+            new IOException(
+                "Connection has been shutdown: "
+                    + new SSLException(new SocketException("Connection reset"))));
+    assertEquals(0, exception.getCode());
+    assertEquals("connectionReset", exception.getReason());
+    assertTrue(exception.isRetryable());
+  }
+
+  @Test
+  public void testTranslateConnectionClosedPrematurely() {
+    StorageException exception =
+        StorageException.translate(
+            new IOException(
+                "Connection closed prematurely: bytesRead = 1114112, Content-Length = 10485760"));
+    assertEquals(0, exception.getCode());
+    assertEquals("connectionClosedPrematurely", exception.getReason());
+    assertTrue(exception.isRetryable());
+  }
+
   @Test
   public void testTranslateAndThrow() throws Exception {
     Exception cause = new StorageException(503, "message");