Repository: googleapis/java-storage
Pull request #223 (2020-04-01 23:14:24)

deps: update dependency com.google.api.grpc:proto-google-cloud-kms-v1 to v0.85.0
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| com.google.api.grpc:proto-google-cloud-kms-v1 | minor | `0.83.1` -> `0.85.0` |

---

### Renovate configuration

:date: **Schedule**: At any time (no schedule defined).

:vertical_traffic_light: **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

:recycle: **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

:no_bell: **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [WhiteSource Renovate](https://renovate.whitesourcesoftware.com). View repository job log [here](https://app.renovatebot.com/dashboard#googleapis/java-storage).

codecov[bot]: # [Codecov](https://codecov.io/gh/googleapis/java-storage/pull/223?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@b5dce9e`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/googleapis/java-storage/pull/223/graphs/tree.svg?width=650&token=ssm139YOdp&height=150&src=pr)](https://codecov.io/gh/googleapis/java-storage/pull/223?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #223   +/-   ##
=========================================
  Coverage          ?   63.67%           
  Complexity        ?      548           
=========================================
  Files             ?       31           
  Lines             ?     4782           
  Branches          ?      428           
=========================================
  Hits              ?     3045           
  Misses            ?     1577           
  Partials          ?      160
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/googleapis/java-storage/pull/223?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/googleapis/java-storage/pull/223?src=pr&el=footer). Last update [b5dce9e...a23eee0](https://codecov.io/gh/googleapis/java-storage/pull/223?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.kokoro/common.sh b/.kokoro/common.sh
index a3bbc5f6..8f09de5d 100644
--- a/.kokoro/common.sh
+++ b/.kokoro/common.sh
@@ -13,18 +13,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# set -eo pipefail
-
 function retry_with_backoff {
     attempts_left=$1
     sleep_seconds=$2
     shift 2
     command=$@
 
+
+    # store current flag state
+    flags=$-
+    
+    # allow a failures to continue
+    set +e
     echo "${command}"
     ${command}
     exit_code=$?
 
+    # restore "e" flag
+    if [[ ${flags} =~ e ]]
+    then set -e
+    else set +e
+    fi
+
     if [[ $exit_code == 0 ]]
     then
         return 0
diff --git a/.kokoro/nightly/integration.cfg b/.kokoro/nightly/integration.cfg
index 8bf59c02..ca027480 100644
--- a/.kokoro/nightly/integration.cfg
+++ b/.kokoro/nightly/integration.cfg
@@ -6,11 +6,26 @@ env_vars: {
   value: "gcr.io/cloud-devrel-kokoro-resources/java8"
 }
 
+env_vars: {
+  key: "JOB_TYPE"
+  value: "integration"
+}
+
+env_vars: {
+  key: "GCLOUD_PROJECT"
+  value: "gcloud-devel"
+}
+
 env_vars: {
   key: "ENABLE_BUILD_COP"
   value: "true"
 }
 
+env_vars: {
+    key: "GOOGLE_APPLICATION_CREDENTIALS"
+    value: "keystore/73713_java_it_service_account"
+}
+
 before_action {
   fetch_keystore {
     keystore_resource {
diff --git a/README.md b/README.md
index bcdb231c..368cbf10 100644
--- a/README.md
+++ b/README.md
@@ -216,7 +216,8 @@ See [TESTING] to read more about testing.
 Versioning
 ----------
 
-This library follows [Semantic Versioning](http://semver.org/).
+This library follows [Semantic Versioning](http://semver.org/), but does update [Storage interface](src/main/java/com.google.cloud.storage/Storage.java)
+to introduce new methods which can break your implementations if you implement this interface for testing purposes.
 
 It is currently in major version one (``1.y.z``), which means that the public API should be considered stable.
 
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 19af9709..15d64118 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -132,7 +132,7 @@
     <dependency>
       <groupId>com.google.api.grpc</groupId>
       <artifactId>proto-google-cloud-kms-v1</artifactId>
-      <version>0.83.1</version>
+      <version>0.85.0</version>
       <scope>test</scope>
     </dependency>
     <dependency>
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
index 7efc24c9..3cb99e61 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
@@ -52,12 +52,26 @@ import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 /**
- * A Google cloud storage object.
+ * An object in Google Cloud Storage. A {@code Blob} object includes the {@code BlobId} instance,
+ * the set of properties inherited from the {@link BlobInfo} class and the {@code Storage} instance.
+ * The class provides methods to perform operations on the object. Reading a property value does not
+ * issue any RPC calls. The object content is not stored within the {@code Blob} instance.
+ * Operations that access the content issue one or multiple RPC calls, depending on the content
+ * size.
  *
  * <p>Objects of this class are immutable. Operations that modify the blob like {@link #update} and
- * {@link #copyTo} return a new object. To get a {@code Blob} object with the most recent
- * information use {@link #reload}. {@code Blob} adds a layer of service-related functionality over
- * {@link BlobInfo}.
+ * {@link #copyTo} return a new object. Any changes to the object in Google Cloud Storage made after
+ * creation of the {@code Blob} are not visible in the {@code Blob}. To get a {@code Blob} object
+ * with the most recent information use {@link #reload}.
+ *
+ * <p>Example of getting the content of the object in Google Cloud Storage:
+ *
+ * <pre>{@code
+ * BlobId blobId = BlobId.of(bucketName, blobName);
+ * Blob blob = storage.get(blobId);
+ * long size = blob.getSize(); // no RPC call is required
+ * byte[] content = blob.getContent(); // one or multiple RPC calls will be issued
+ * }</pre>
  */
 public class Blob extends BlobInfo {
 
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
index f21e0215..ef38ba03 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
@@ -34,8 +34,8 @@ import com.google.common.collect.Maps;
 import com.google.common.io.BaseEncoding;
 import java.io.Serializable;
 import java.math.BigInteger;
+import java.nio.ByteBuffer;
 import java.util.AbstractMap;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -44,7 +44,21 @@ import java.util.Objects;
 import java.util.Set;
 
 /**
- * Google Storage object metadata.
+ * Information about an object in Google Cloud Storage. A {@code BlobInfo} object includes the
+ * {@code BlobId} instance and the set of properties, such as the blob's access control
+ * configuration, user provided metadata, the CRC32C checksum, etc. Instances of this class are used
+ * to create a new object in Google Cloud Storage or update the properties of an existing object. To
+ * deal with existing Storage objects the API includes the {@link Blob} class which extends {@code
+ * BlobInfo} and declares methods to perform operations on the object. Neither {@code BlobInfo} nor
+ * {@code Blob} instances keep the object content, just the object properties.
+ *
+ * <p>Example of usage {@code BlobInfo} to create an object in Google Cloud Storage:
+ *
+ * <pre>{@code
+ * BlobId blobId = BlobId.of(bucketName, blobName);
+ * BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("text/plain").build();
+ * Blob blob = storage.create(blobInfo, "Hello, world".getBytes(StandardCharsets.UTF_8));
+ * }</pre>
  *
  * @see <a href="https://cloud.google.com/storage/docs/concepts-techniques#concepts">Concepts and
  *     Terminology</a>
@@ -232,6 +246,7 @@ public class BlobInfo implements Serializable {
      *
      * @see <a href="https://cloud.google.com/storage/docs/hashes-etags#_JSONAPI">Hashes and ETags:
      *     Best Practices</a>
+     * @throws IllegalArgumentException when given an invalid hexadecimal value.
      */
     public abstract Builder setMd5FromHexString(String md5HexString);
 
@@ -252,6 +267,7 @@ public class BlobInfo implements Serializable {
      *
      * @see <a href="https://cloud.google.com/storage/docs/hashes-etags#_JSONAPI">Hashes and ETags:
      *     Best Practices</a>
+     * @throws IllegalArgumentException when given an invalid hexadecimal value.
      */
     public abstract Builder setCrc32cFromHexString(String crc32cHexString);
 
@@ -293,7 +309,7 @@ public class BlobInfo implements Serializable {
   }
 
   static final class BuilderImpl extends Builder {
-
+    private final String hexDecimalValues = "0123456789abcdef";
     private BlobId blobId;
     private String generatedId;
     private String contentType;
@@ -442,16 +458,27 @@ public class BlobInfo implements Serializable {
       return this;
     }
 
+    @Override
     public Builder setMd5FromHexString(String md5HexString) {
       if (md5HexString == null) {
         return this;
       }
-      byte[] bytes = new BigInteger(md5HexString, 16).toByteArray();
-      int leadingEmptyBytes = bytes.length - md5HexString.length() / 2;
-      if (leadingEmptyBytes > 0) {
-        bytes = Arrays.copyOfRange(bytes, leadingEmptyBytes, bytes.length);
+      if (md5HexString.length() % 2 != 0) {
+        throw new IllegalArgumentException(
+            "each byte must be represented by 2 valid hexadecimal characters");
       }
-      this.md5 = BaseEncoding.base64().encode(bytes);
+      String md5HexStringLower = md5HexString.toLowerCase();
+      ByteBuffer md5ByteBuffer = ByteBuffer.allocate(md5HexStringLower.length() / 2);
+      for (int charIndex = 0; charIndex < md5HexStringLower.length(); charIndex += 2) {
+        int higherOrderBits = this.hexDecimalValues.indexOf(md5HexStringLower.charAt(charIndex));
+        int lowerOrderBits = this.hexDecimalValues.indexOf(md5HexStringLower.charAt(charIndex + 1));
+        if (higherOrderBits == -1 || lowerOrderBits == -1) {
+          throw new IllegalArgumentException(
+              "each byte must be represented by 2 valid hexadecimal characters");
+        }
+        md5ByteBuffer.put((byte) (higherOrderBits << 4 | lowerOrderBits));
+      }
+      this.md5 = BaseEncoding.base64().encode(md5ByteBuffer.array());
       return this;
     }
 
@@ -466,12 +493,23 @@ public class BlobInfo implements Serializable {
       if (crc32cHexString == null) {
         return this;
       }
-      byte[] bytes = new BigInteger(crc32cHexString, 16).toByteArray();
-      int leadingEmptyBytes = bytes.length - crc32cHexString.length() / 2;
-      if (leadingEmptyBytes > 0) {
-        bytes = Arrays.copyOfRange(bytes, leadingEmptyBytes, bytes.length);
+      if (crc32cHexString.length() % 2 != 0) {
+        throw new IllegalArgumentException(
+            "each byte must be represented by 2 valid hexadecimal characters");
+      }
+      String crc32cHexStringLower = crc32cHexString.toLowerCase();
+      ByteBuffer crc32cByteBuffer = ByteBuffer.allocate(crc32cHexStringLower.length() / 2);
+      for (int charIndex = 0; charIndex < crc32cHexStringLower.length(); charIndex += 2) {
+        int higherOrderBits = this.hexDecimalValues.indexOf(crc32cHexStringLower.charAt(charIndex));
+        int lowerOrderBits =
+            this.hexDecimalValues.indexOf(crc32cHexStringLower.charAt(charIndex + 1));
+        if (higherOrderBits == -1 || lowerOrderBits == -1) {
+          throw new IllegalArgumentException(
+              "each byte must be represented by 2 valid hexadecimal characters");
+        }
+        crc32cByteBuffer.put((byte) (higherOrderBits << 4 | lowerOrderBits));
       }
-      this.crc32c = BaseEncoding.base64().encode(bytes);
+      this.crc32c = BaseEncoding.base64().encode(crc32cByteBuffer.array());
       return this;
     }
 
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobReadChannel.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobReadChannel.java
index cd9f08d9..c5fce5bd 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobReadChannel.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobReadChannel.java
@@ -133,12 +133,12 @@ class BlobReadChannel implements ReadChannel {
         if (result.y().length > 0 && lastEtag != null && !Objects.equals(result.x(), lastEtag)) {
           StringBuilder messageBuilder = new StringBuilder();
           messageBuilder.append("Blob ").append(blob).append(" was updated while reading");
-          throw new StorageException(0, messageBuilder.toString());
+          throw new IOException(messageBuilder.toString());
         }
         lastEtag = result.x();
         buffer = result.y();
       } catch (RetryHelper.RetryHelperException e) {
-        throw StorageException.translateAndThrow(e);
+        throw new IOException(e);
       }
       if (toRead > buffer.length) {
         endOfStream = true;
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index c95213d8..a9bb589a 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -19,6 +19,7 @@ package com.google.cloud.storage;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import com.google.api.core.InternalExtensionOnly;
 import com.google.api.gax.paging.Page;
 import com.google.auth.ServiceAccountSigner;
 import com.google.auth.ServiceAccountSigner.SigningException;
@@ -55,6 +56,7 @@ import java.util.concurrent.TimeUnit;
  *
  * @see <a href="https://cloud.google.com/storage/docs">Google Cloud Storage</a>
  */
+@InternalExtensionOnly
 public interface Storage extends Service<StorageOptions> {
 
   enum PredefinedAcl {
diff --git a/pom.xml b/pom.xml
index ccd699de..2df8c308 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-shared-config</artifactId>
-    <version>0.4.0</version>
+    <version>0.5.0</version>
   </parent>
 
   <developers>
@@ -77,7 +77,7 @@
       <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
-        <version>28.2-android</version>
+        <version>29.0-android</version>
       </dependency>
       <dependency>
         <groupId>com.google.http-client</groupId>
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 2d979c7e..bd7d378c 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -30,7 +30,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>libraries-bom</artifactId>
-        <version>4.4.1</version>
+        <version>5.1.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
diff --git a/synth.metadata b/synth.metadata
index 1a8f7a39..f739ebe1 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -1,11 +1,19 @@
 {
-  "updateTime": "2020-03-30T22:54:24.805818Z",
+  "updateTime": "2020-04-09T11:28:44.677622Z",
   "sources": [
+    {
+      "git": {
+        "name": ".",
+        "remote": "https://github.com/googleapis/java-storage.git",
+        "sha": "397fcd981848ec5e02d7686b41050a4715aa90c3"
+      }
+    },
     {
       "git": {
         "name": "synthtool",
         "remote": "https://github.com/googleapis/synthtool.git",
-        "sha": "a003d8655d3ebec2bbbd5fc3898e91e152265c67"
+        "sha": "c7e0e517d7f46f77bebd27da2e5afcaa6eee7e25",
+        "log": "c7e0e517d7f46f77bebd27da2e5afcaa6eee7e25\nbuild(java): fix nightly integration test config to run integrations (#465)\n\nThis was only running the units.\nbd69a2aa7b70875f3c988e269706b22fefbef40e\nbuild(java): fix retry_with_backoff when -e option set (#475)\n\n\nd9b173c427bfa0c6cca818233562e7e8841a357c\nfix: record version of working repo in synth.metadata (#473)\n\nPartial revert of b37cf74d12e9a42b9de9e61a4f26133d7cd9c168.\nf73a541770d95a609e5be6bf6b3b220d17cefcbe\nfeat(discogapic): allow local discovery-artifact-manager (#474)\n\n\n8cf0f5d93a70c3dcb0b4999d3152c46d4d9264bf\ndoc: describe the Autosynth & Synthtool protocol (#472)\n\n* doc: describe the Autosynth & Synthtool protocol\n\n* Accommodate review comments.\n980baaa738a1ad8fa02b4fdbd56be075ee77ece5\nfix: pin sphinx to <3.0.0 as new version causes new error (#471)\n\nThe error `toctree contains reference to document changlelog that doesn't have a title: no link will be generated` occurs as of 3.0.0. Pinning to 2.x until we address the docs build issue.\n\nTowards #470\n\nI did this manually for python-datastore https://github.com/googleapis/python-datastore/pull/22\n928b2998ac5023e7c7e254ab935f9ef022455aad\nchore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.15 (#466)\n\nCo-authored-by: Jeffrey Rennie <rennie@google.com>\n188f1b1d53181f739b98f8aa5d40cfe99eb90c47\nfix: allow local and external deps to be specified (#469)\n\nModify noxfile.py to allow local and external dependencies for\nsystem tests to be specified.\n1df68ed6735ddce6797d0f83641a731c3c3f75b4\nfix: apache license URL (#468)\n\n\nf4a59efa54808c4b958263de87bc666ce41e415f\nfeat: Add discogapic support for GAPICBazel generation (#459)\n\n* feat: Add discogapic support for GAPICBazel generation\n\n* reformat with black\n\n* Rename source repository variable\n\nCo-authored-by: Jeffrey Rennie <rennie@google.com>\n99820243d348191bc9c634f2b48ddf65096285ed\nfix: update template files for Node.js libraries (#463)\n\n\n3cbe6bcd5623139ac9834c43818424ddca5430cb\nfix(ruby): remove dead troubleshooting link from generated auth guide (#462)\n\n\n"
       }
     }
   ]


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
index a57be6df..ea4f6dbd 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
@@ -49,12 +49,16 @@ public class BlobInfoTest {
   private static final String CONTENT_LANGUAGE = "En";
   private static final String CRC32 = "FF00";
   private static final String CRC32_HEX_STRING = "145d34";
+  private static final String CRC32_HEX_STRING_LEADING_ZEROS = "005d34";
+  private static final String CRC32_BASE64_LEADING_ZEROS = "AF00";
   private static final Long DELETE_TIME = System.currentTimeMillis();
   private static final String ETAG = "0xFF00";
   private static final Long GENERATION = 1L;
   private static final String GENERATED_ID = "B/N:1";
   private static final String MD5 = "FF00";
   private static final String MD5_HEX_STRING = "145d34";
+  private static final String MD5_HEX_STRING_LEADING_ZEROS = "0006a7de52b4e0b82602ce09809523ca";
+  private static final String MD5_BASE64_LEADING_ZEROS = "AAan3lK04LgmAs4JgJUjyg==";
   private static final String MEDIA_LINK = "http://media/b/n";
   private static final Map<String, String> METADATA = ImmutableMap.of("n1", "v1", "n2", "v2");
   private static final Long META_GENERATION = 10L;
@@ -132,6 +136,15 @@ public class BlobInfoTest {
     assertEquals(MD5, blobInfo.getMd5());
   }
 
+  @Test
+  public void testToBuilderSetMd5FromHexStringLeadingZeros() {
+    BlobInfo blobInfo =
+        BlobInfo.newBuilder(BlobId.of("b2", "n2"))
+            .setMd5FromHexString(MD5_HEX_STRING_LEADING_ZEROS)
+            .build();
+    assertEquals(MD5_BASE64_LEADING_ZEROS, blobInfo.getMd5());
+  }
+
   @Test
   public void testToBuilderSetCrc32cFromHexString() {
     BlobInfo blobInfo =
@@ -139,6 +152,15 @@ public class BlobInfoTest {
     assertEquals(CRC32, blobInfo.getCrc32c());
   }
 
+  @Test
+  public void testToBuilderSetCrc32cFromHexStringLeadingZeros() {
+    BlobInfo blobInfo =
+        BlobInfo.newBuilder(BlobId.of("b2", "n2"))
+            .setCrc32cFromHexString(CRC32_HEX_STRING_LEADING_ZEROS)
+            .build();
+    assertEquals(CRC32_BASE64_LEADING_ZEROS, blobInfo.getCrc32c());
+  }
+
   @Test
   public void testToBuilderIncomplete() {
     BlobInfo incompleteBlobInfo = BlobInfo.newBuilder(BlobId.of("b2", "n2")).build();
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 f1388ebe..dafb0b2a 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
@@ -23,6 +23,7 @@ import static org.easymock.EasyMock.replay;
 import static org.easymock.EasyMock.verify;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -71,7 +72,7 @@ public class BlobReadChannelTest {
   }
 
   @After
-  public void tearDown() throws Exception {
+  public void tearDown() {
     verify(rpcFactoryMock, storageRpcMock);
   }
 
@@ -154,7 +155,7 @@ public class BlobReadChannelTest {
     reader = new BlobReadChannel(options, BLOB_ID, EMPTY_RPC_OPTIONS);
     assertTrue(reader.isOpen());
     reader.close();
-    assertTrue(!reader.isOpen());
+    assertFalse(reader.isOpen());
   }
 
   @Test
@@ -190,7 +191,7 @@ public class BlobReadChannelTest {
     try {
       reader.read(secondReadBuffer);
       fail("Expected ReadChannel read to throw StorageException");
-    } catch (StorageException ex) {
+    } catch (IOException ex) {
       StringBuilder messageBuilder = new StringBuilder();
       messageBuilder.append("Blob ").append(blobId).append(" was updated while reading");
       assertEquals(messageBuilder.toString(), ex.getMessage());
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
index 6abc233f..52a6acd7 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
@@ -1751,14 +1751,14 @@ public class ITStorageTest {
         storage.reader(blob.getBlobId(), Storage.BlobSourceOption.metagenerationMatch(-1L))) {
       reader.read(ByteBuffer.allocate(42));
       fail("StorageException was expected");
-    } catch (StorageException ex) {
+    } catch (IOException ex) {
       // expected
     }
     try (ReadChannel reader =
         storage.reader(blob.getBlobId(), Storage.BlobSourceOption.generationMatch(-1L))) {
       reader.read(ByteBuffer.allocate(42));
       fail("StorageException was expected");
-    } catch (StorageException ex) {
+    } catch (IOException ex) {
       // expected
     }
     BlobId blobIdWrongGeneration = BlobId.of(BUCKET, blobName, -1L);
@@ -1766,7 +1766,7 @@ public class ITStorageTest {
         storage.reader(blobIdWrongGeneration, Storage.BlobSourceOption.generationMatch())) {
       reader.read(ByteBuffer.allocate(42));
       fail("StorageException was expected");
-    } catch (StorageException ex) {
+    } catch (IOException ex) {
       // expected
     }
   }
@@ -1798,7 +1798,7 @@ public class ITStorageTest {
       readBytes = ByteBuffer.allocate(chunkSize);
       reader.read(readBytes);
       fail("StorageException was expected");
-    } catch (StorageException ex) {
+    } catch (IOException ex) {
       StringBuilder messageBuilder = new StringBuilder();
       messageBuilder.append("Blob ").append(blob.getBlobId()).append(" was updated while reading");
       assertEquals(messageBuilder.toString(), ex.getMessage());