Repository: googleapis/java-storage
Pull request #221 (2020-04-01 19:15:21)

chore(deps): update dependency com.google.cloud:libraries-bom to v4.4.0
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [com.google.cloud:libraries-bom](https://togithub.com/GoogleCloudPlatform/cloud-opensource-java) | minor | `4.3.0` -> `4.4.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/221?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@7beb99d`). [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/221/graphs/tree.svg?width=650&token=ssm139YOdp&height=150&src=pr)](https://codecov.io/gh/googleapis/java-storage/pull/221?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #221   +/-   ##
=========================================
  Coverage          ?   63.61%           
  Complexity        ?      548           
=========================================
  Files             ?       31           
  Lines             ?     4782           
  Branches          ?      428           
=========================================
  Hits              ?     3042           
  Misses            ?     1580           
  Partials          ?      160
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/googleapis/java-storage/pull/221?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/221?src=pr&el=footer). Last update [7beb99d...604b783](https://codecov.io/gh/googleapis/java-storage/pull/221?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index f833a062..86bb6be3 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -20,17 +20,22 @@ scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}"))
 ## cd to the parent directory, i.e. the root of the git repo
 cd ${scriptDir}/..
 
+# include common functions
+source ${scriptDir}/common.sh
+
 # Print out Java version
 java -version
 echo ${JOB_TYPE}
 
-mvn install -B -V \
-  -DskipTests=true \
-  -Dclirr.skip=true \
-  -Denforcer.skip=true \
-  -Dmaven.javadoc.skip=true \
-  -Dgcloud.download.skip=true \
-  -T 1C
+# attempt to install 3 times with exponential backoff (starting with 10 seconds)
+retry_with_backoff 3 10 \
+  mvn install -B -V \
+    -DskipTests=true \
+    -Dclirr.skip=true \
+    -Denforcer.skip=true \
+    -Dmaven.javadoc.skip=true \
+    -Dgcloud.download.skip=true \
+    -T 1C
 
 # if GOOGLE_APPLICATION_CREDIENTIALS is specified as a relative path prepend Kokoro root directory onto it
 if [[ ! -z "${GOOGLE_APPLICATION_CREDENTIALS}" && "${GOOGLE_APPLICATION_CREDENTIALS}" != /* ]]; then
diff --git a/.kokoro/common.sh b/.kokoro/common.sh
new file mode 100644
index 00000000..a3bbc5f6
--- /dev/null
+++ b/.kokoro/common.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# Copyright 2020 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# 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=$@
+
+    echo "${command}"
+    ${command}
+    exit_code=$?
+
+    if [[ $exit_code == 0 ]]
+    then
+        return 0
+    fi
+
+    # failure
+    if [[ ${attempts_left} > 0 ]]
+    then
+        echo "failure (${exit_code}), sleeping ${sleep_seconds}..."
+        sleep ${sleep_seconds}
+        new_attempts=$((${attempts_left} - 1))
+        new_sleep=$((${sleep_seconds} * 2))
+        retry_with_backoff ${new_attempts} ${new_sleep} ${command}
+    fi
+
+    return $exit_code
+}
diff --git a/.kokoro/dependencies.sh b/.kokoro/dependencies.sh
index 04a288b1..0aade871 100755
--- a/.kokoro/dependencies.sh
+++ b/.kokoro/dependencies.sh
@@ -15,7 +15,13 @@
 
 set -eo pipefail
 
-cd github/java-storage/
+## Get the directory of the build script
+scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}"))
+## cd to the parent directory, i.e. the root of the git repo
+cd ${scriptDir}/..
+
+# include common functions
+source ${scriptDir}/common.sh
 
 # Print out Java
 java -version
@@ -24,8 +30,9 @@ echo $JOB_TYPE
 export MAVEN_OPTS="-Xmx1024m -XX:MaxPermSize=128m"
 
 # this should run maven enforcer
-mvn install -B -V \
-  -DskipTests=true \
-  -Dclirr.skip=true
+retry_with_backoff 3 10 \
+  mvn install -B -V \
+    -DskipTests=true \
+    -Dclirr.skip=true
 
 mvn -B dependency:analyze -DfailOnWarning=true
diff --git a/.kokoro/linkage-monitor.sh b/.kokoro/linkage-monitor.sh
index 158641cb..759ab4e2 100755
--- a/.kokoro/linkage-monitor.sh
+++ b/.kokoro/linkage-monitor.sh
@@ -17,18 +17,26 @@ set -eo pipefail
 # Display commands being run.
 set -x
 
-cd github/java-storage/
+## Get the directory of the build script
+scriptDir=$(realpath $(dirname "${BASH_SOURCE[0]}"))
+## cd to the parent directory, i.e. the root of the git repo
+cd ${scriptDir}/..
+
+# include common functions
+source ${scriptDir}/common.sh
 
 # Print out Java version
 java -version
 echo ${JOB_TYPE}
 
-mvn install -B -V \
-  -DskipTests=true \
-  -Dclirr.skip=true \
-  -Denforcer.skip=true \
-  -Dmaven.javadoc.skip=true \
-  -Dgcloud.download.skip=true
+# attempt to install 3 times with exponential backoff (starting with 10 seconds)
+retry_with_backoff 3 10 \
+  mvn install -B -V \
+    -DskipTests=true \
+    -Dclirr.skip=true \
+    -Denforcer.skip=true \
+    -Dmaven.javadoc.skip=true \
+    -Dgcloud.download.skip=true
 
 # Kokoro job cloud-opensource-java/ubuntu/linkage-monitor-gcs creates this JAR
 JAR=linkage-monitor-latest-all-deps.jar
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 27e62626..7efc24c9 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
@@ -26,6 +26,7 @@ import com.google.api.services.storage.model.StorageObject;
 import com.google.auth.ServiceAccountSigner;
 import com.google.auth.ServiceAccountSigner.SigningException;
 import com.google.cloud.ReadChannel;
+import com.google.cloud.RetryHelper;
 import com.google.cloud.Tuple;
 import com.google.cloud.WriteChannel;
 import com.google.cloud.storage.Acl.Entity;
@@ -230,21 +231,25 @@ public class Blob extends BlobInfo {
     final CountingOutputStream countingOutputStream = new CountingOutputStream(outputStream);
     final StorageRpc storageRpc = this.options.getStorageRpcV1();
     final Map<StorageRpc.Option, ?> requestOptions = StorageImpl.optionMap(getBlobId(), options);
-    runWithRetries(
-        callable(
-            new Runnable() {
-              @Override
-              public void run() {
-                storageRpc.read(
-                    getBlobId().toPb(),
-                    requestOptions,
-                    countingOutputStream.getCount(),
-                    countingOutputStream);
-              }
-            }),
-        this.options.getRetrySettings(),
-        StorageImpl.EXCEPTION_HANDLER,
-        this.options.getClock());
+    try {
+      runWithRetries(
+          callable(
+              new Runnable() {
+                @Override
+                public void run() {
+                  storageRpc.read(
+                      getBlobId().toPb(),
+                      requestOptions,
+                      countingOutputStream.getCount(),
+                      countingOutputStream);
+                }
+              }),
+          this.options.getRetrySettings(),
+          StorageImpl.EXCEPTION_HANDLER,
+          this.options.getClock());
+    } catch (RetryHelper.RetryHelperException e) {
+      StorageException.translateAndThrow(e);
+    }
   }
 
   /**
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageOperations.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageOperations.java
deleted file mode 100644
index 6ff178ff..00000000
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageOperations.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.cloud.storage;
-
-import com.google.cloud.WriteChannel;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-/** Utility methods to perform various operations with the Storage such as upload. */
-public final class StorageOperations {
-
-  private final Storage storage;
-  private static final int DEFAULT_BUFFER_SIZE = 15 * 1024 * 1024;
-  private static final int MIN_BUFFER_SIZE = 256 * 1024;
-
-  /**
-   * Creates a new StorageOperations instance associated with the given storage.
-   *
-   * @param storage the Storage
-   */
-  public StorageOperations(Storage storage) {
-    this.storage = storage;
-  }
-
-  /**
-   * Uploads {@code path} to the blob using {@link Storage#writer}. By default any MD5 and CRC32C
-   * values in the given {@code blobInfo} are ignored unless requested via the {@link
-   * Storage.BlobWriteOption#md5Match()} and {@link Storage.BlobWriteOption#crc32cMatch()} options.
-   * Folder upload is not supported.
-   *
-   * <p>Example of uploading a file:
-   *
-   * <pre>{@code
-   * String bucketName = "my-unique-bucket";
-   * String fileName = "readme.txt";
-   * BlobId blobId = BlobId.of(bucketName, fileName);
-   * BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("text/plain").build();
-   * new StorageOperations(storage).upload(blobInfo, Paths.get(fileName));
-   * }</pre>
-   *
-   * @param blobInfo blob to create
-   * @param path file to upload
-   * @param options blob write options
-   * @throws IOException on I/O error
-   * @throws StorageException on failure
-   * @see #upload(BlobInfo, Path, int, Storage.BlobWriteOption...)
-   */
-  public void upload(BlobInfo blobInfo, Path path, Storage.BlobWriteOption... options)
-      throws IOException {
-    upload(blobInfo, path, DEFAULT_BUFFER_SIZE, options);
-  }
-
-  /**
-   * Uploads {@code path} to the blob using {@link Storage#writer} and {@code bufferSize}. By
-   * default any MD5 and CRC32C values in the given {@code blobInfo} are ignored unless requested
-   * via the {@link Storage.BlobWriteOption#md5Match()} and {@link
-   * Storage.BlobWriteOption#crc32cMatch()} options. Folder upload is not supported.
-   *
-   * <p>{@link #upload(BlobInfo, Path, Storage.BlobWriteOption...)} invokes this method with a
-   * buffer size of 15 MiB. Users can pass alternative values. Larger buffer sizes might improve the
-   * upload performance but require more memory. This can cause an OutOfMemoryError or add
-   * significant garbage collection overhead. Smaller buffer sizes reduce memory consumption, that
-   * is noticeable when uploading many objects in parallel. Buffer sizes less than 256 KiB are
-   * treated as 256 KiB.
-   *
-   * <p>Example of uploading a humongous file:
-   *
-   * <pre>{@code
-   * BlobId blobId = BlobId.of(bucketName, blobName);
-   * BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("video/webm").build();
-   *
-   * int largeBufferSize = 150 * 1024 * 1024;
-   * Path file = Paths.get("humongous.file");
-   * new StorageOperations(storage).upload(blobInfo, file, largeBufferSize);
-   * }</pre>
-   *
-   * @param blobInfo blob to create
-   * @param path file to upload
-   * @param bufferSize size of the buffer I/O operations
-   * @param options blob write options
-   * @throws IOException on I/O error
-   * @throws StorageException on failure
-   */
-  public void upload(
-      BlobInfo blobInfo, Path path, int bufferSize, Storage.BlobWriteOption... options)
-      throws IOException {
-    if (Files.isDirectory(path)) {
-      throw new StorageException(0, path + " is a directory");
-    }
-    try (InputStream input = Files.newInputStream(path)) {
-      upload(blobInfo, input, bufferSize, options);
-    }
-  }
-
-  /**
-   * Reads bytes from an input stream and uploads those bytes to the blob using {@link
-   * Storage#writer}. By default any MD5 and CRC32C values in the given {@code blobInfo} are ignored
-   * unless requested via the {@link Storage.BlobWriteOption#md5Match()} and {@link
-   * Storage.BlobWriteOption#crc32cMatch()} options.
-   *
-   * <p>Example of uploading data with CRC32C checksum:
-   *
-   * <pre>{@code
-   * BlobId blobId = BlobId.of(bucketName, blobName);
-   * byte[] content = "Hello, world".getBytes(StandardCharsets.UTF_8);
-   * Hasher hasher = Hashing.crc32c().newHasher().putBytes(content);
-   * String crc32c = BaseEncoding.base64().encode(Ints.toByteArray(hasher.hash().asInt()));
-   * BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setCrc32c(crc32c).build();
-   * new StorageOperations(storage).upload(blobInfo, new ByteArrayInputStream(content),
-   *     Storage.BlobWriteOption.crc32cMatch());
-   * }</pre>
-   *
-   * @param blobInfo blob to create
-   * @param content input stream to read from
-   * @param options blob write options
-   * @throws IOException on I/O error
-   * @throws StorageException on failure
-   * @see #upload(BlobInfo, InputStream, int, Storage.BlobWriteOption...)
-   */
-  public void upload(BlobInfo blobInfo, InputStream content, Storage.BlobWriteOption... options)
-      throws IOException {
-    upload(blobInfo, content, DEFAULT_BUFFER_SIZE, options);
-  }
-
-  /**
-   * Reads bytes from an input stream and uploads those bytes to the blob using {@link
-   * Storage#writer} and {@code bufferSize}. By default any MD5 and CRC32C values in the given
-   * {@code blobInfo} are ignored unless requested via the {@link
-   * Storage.BlobWriteOption#md5Match()} and {@link Storage.BlobWriteOption#crc32cMatch()} options.
-   *
-   * <p>{@link #upload(BlobInfo, InputStream, Storage.BlobWriteOption...)} )} invokes this method
-   * with a buffer size of 15 MiB. Users can pass alternative values. Larger buffer sizes might
-   * improve the upload performance but require more memory. This can cause an OutOfMemoryError or
-   * add significant garbage collection overhead. Smaller buffer sizes reduce memory consumption,
-   * that is noticeable when uploading many objects in parallel. Buffer sizes less than 256 KiB are
-   * treated as 256 KiB.
-   *
-   * @param blobInfo blob to create
-   * @param content input stream to read from
-   * @param bufferSize size of the buffer I/O operations
-   * @param options blob write options
-   * @throws IOException on I/O error
-   * @throws StorageException on failure
-   */
-  public void upload(
-      BlobInfo blobInfo, InputStream content, int bufferSize, Storage.BlobWriteOption... options)
-      throws IOException {
-    try (WriteChannel writer = storage.writer(blobInfo, options)) {
-      upload(Channels.newChannel(content), writer, bufferSize);
-    }
-  }
-
-  /*
-   * Uploads the given content to the storage using specified write channel and the given buffer
-   * size. This method does not close any channels.
-   */
-  private static void upload(ReadableByteChannel reader, WriteChannel writer, int bufferSize)
-      throws IOException {
-    bufferSize = Math.max(bufferSize, MIN_BUFFER_SIZE);
-    ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
-    writer.setChunkSize(bufferSize);
-
-    while (reader.read(buffer) >= 0) {
-      buffer.flip();
-      writer.write(buffer);
-      buffer.clear();
-    }
-  }
-}
diff --git a/renovate.json b/renovate.json
index fc641270..1dcdf893 100644
--- a/renovate.json
+++ b/renovate.json
@@ -56,7 +56,9 @@
     },
     {
       "packagePatterns": [
-        "^com.google.cloud:libraries-bom"
+        "^com.google.cloud:google-cloud-storage",
+        "^com.google.cloud:libraries-bom",
+        "^com.google.cloud.samples:shared-configuration"
       ],
       "semanticCommitType": "chore",
       "semanticCommitScope": "deps"
@@ -75,4 +77,4 @@
     }
   ],
   "semanticCommits": true
-}
+}
\ No newline at end of file
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index 94727651..0f274f99 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.3.0</version>
+        <version>4.4.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
diff --git a/synth.metadata b/synth.metadata
index 66cd387f..1a8f7a39 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -1,11 +1,11 @@
 {
-  "updateTime": "2020-03-17T18:53:43.239577Z",
+  "updateTime": "2020-03-30T22:54:24.805818Z",
   "sources": [
     {
-      "template": {
-        "name": "java_library",
-        "origin": "synthtool.gcp",
-        "version": "2020.2.4"
+      "git": {
+        "name": "synthtool",
+        "remote": "https://github.com/googleapis/synthtool.git",
+        "sha": "a003d8655d3ebec2bbbd5fc3898e91e152265c67"
       }
     }
   ]


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
index 6f91f968..51d606c2 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
@@ -32,6 +32,7 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import com.google.api.core.ApiClock;
 import com.google.api.gax.retrying.RetrySettings;
@@ -585,17 +586,22 @@ public class BlobTest {
     assertTrue(blob.isDirectory());
   }
 
-  @Test
-  public void testDownload() throws Exception {
-    final byte[] expected = {1, 2};
+  private StorageRpc prepareForDownload() {
     StorageRpc mockStorageRpc = createNiceMock(StorageRpc.class);
-    expect(storage.getOptions()).andReturn(mockOptions).times(1);
+    expect(storage.getOptions()).andReturn(mockOptions);
     replay(storage);
     expect(mockOptions.getStorageRpcV1()).andReturn(mockStorageRpc);
     expect(mockOptions.getRetrySettings()).andReturn(RETRY_SETTINGS);
     expect(mockOptions.getClock()).andReturn(API_CLOCK);
     replay(mockOptions);
     blob = new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
+    return mockStorageRpc;
+  }
+
+  @Test
+  public void testDownloadTo() throws Exception {
+    final byte[] expected = {1, 2};
+    StorageRpc mockStorageRpc = prepareForDownload();
     expect(
             mockStorageRpc.read(
                 anyObject(StorageObject.class),
@@ -618,16 +624,9 @@ public class BlobTest {
   }
 
   @Test
-  public void testDownloadWithRetries() throws Exception {
+  public void testDownloadToWithRetries() throws Exception {
     final byte[] expected = {1, 2};
-    StorageRpc mockStorageRpc = createNiceMock(StorageRpc.class);
-    expect(storage.getOptions()).andReturn(mockOptions);
-    replay(storage);
-    expect(mockOptions.getStorageRpcV1()).andReturn(mockStorageRpc);
-    expect(mockOptions.getRetrySettings()).andReturn(RETRY_SETTINGS);
-    expect(mockOptions.getClock()).andReturn(API_CLOCK);
-    replay(mockOptions);
-    blob = new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
+    StorageRpc mockStorageRpc = prepareForDownload();
     expect(
             mockStorageRpc.read(
                 anyObject(StorageObject.class),
@@ -662,4 +661,25 @@ public class BlobTest {
     byte actual[] = Files.readAllBytes(file.toPath());
     assertArrayEquals(expected, actual);
   }
+
+  @Test
+  public void testDownloadToWithException() throws Exception {
+    StorageRpc mockStorageRpc = prepareForDownload();
+    Exception exception = new IllegalStateException("test");
+    expect(
+            mockStorageRpc.read(
+                anyObject(StorageObject.class),
+                anyObject(Map.class),
+                eq(0l),
+                anyObject(OutputStream.class)))
+        .andThrow(exception);
+    replay(mockStorageRpc);
+    File file = File.createTempFile("blob", ".tmp");
+    try {
+      blob.downloadTo(file.toPath());
+      fail();
+    } catch (StorageException e) {
+      assertSame(exception, e.getCause());
+    }
+  }
 }
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageOperationsTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageOperationsTest.java
deleted file mode 100644
index 0651c1ac..00000000
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageOperationsTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2020 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.cloud.storage;
-
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.verify;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.fail;
-
-import com.google.cloud.WriteChannel;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-public class StorageOperationsTest {
-  private Storage storage;
-  private StorageOperations storageOperations;
-
-  private static final BlobInfo BLOB_INFO = BlobInfo.newBuilder("b", "n").build();
-  private static final int DEFAULT_BUFFER_SIZE = 15 * 1024 * 1024;
-  private static final int MIN_BUFFER_SIZE = 256 * 1024;
-
-  @Before
-  public void setUp() {
-    storage = createStrictMock(Storage.class);
-    storageOperations = new StorageOperations(storage);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    verify(storage);
-  }
-
-  @Test
-  public void testUploadFromNonExistentFile() {
-    replay(storage);
-    String fileName = "non_existing_file.txt";
-    try {
-      storageOperations.upload(BLOB_INFO, Paths.get(fileName));
-      storageOperations.upload(BLOB_INFO, Paths.get(fileName), -1);
-      fail();
-    } catch (IOException e) {
-      assertEquals(NoSuchFileException.class, e.getClass());
-      assertEquals(fileName, e.getMessage());
-    }
-  }
-
-  @Test
-  public void testUploadFromDirectory() throws IOException {
-    replay(storage);
-    Path dir = Files.createTempDirectory("unit_");
-    try {
-      storageOperations.upload(BLOB_INFO, dir);
-      storageOperations.upload(BLOB_INFO, dir, -2);
-      fail();
-    } catch (StorageException e) {
-      assertEquals(dir + " is a directory", e.getMessage());
-    }
-  }
-
-  private void prepareForUpload(BlobInfo blobInfo, byte[] bytes, Storage.BlobWriteOption... options)
-      throws Exception {
-    prepareForUpload(blobInfo, bytes, DEFAULT_BUFFER_SIZE, options);
-  }
-
-  private void prepareForUpload(
-      BlobInfo blobInfo, byte[] bytes, int bufferSize, Storage.BlobWriteOption... options)
-      throws Exception {
-    WriteChannel channel = createStrictMock(WriteChannel.class);
-    ByteBuffer expectedByteBuffer = ByteBuffer.wrap(bytes, 0, bytes.length);
-    channel.setChunkSize(bufferSize);
-    expect(channel.write(expectedByteBuffer)).andReturn(bytes.length);
-    channel.close();
-    replay(channel);
-    expect(storage.writer(blobInfo, options)).andReturn(channel);
-    replay(storage);
-  }
-
-  @Test
-  public void testUploadFromFile() throws Exception {
-    byte[] dataToSend = {1, 2, 3};
-    prepareForUpload(BLOB_INFO, dataToSend);
-    Path tempFile = Files.createTempFile("testUpload", ".tmp");
-    Files.write(tempFile, dataToSend);
-    storageOperations.upload(BLOB_INFO, tempFile);
-  }
-
-  @Test
-  public void testUploadFromStream() throws Exception {
-    byte[] dataToSend = {1, 2, 3, 4, 5};
-    Storage.BlobWriteOption[] options =
-        new Storage.BlobWriteOption[] {Storage.BlobWriteOption.crc32cMatch()};
-    prepareForUpload(BLOB_INFO, dataToSend, options);
-    InputStream input = new ByteArrayInputStream(dataToSend);
-    storageOperations.upload(BLOB_INFO, input, options);
-  }
-
-  @Test
-  public void testUploadSmallBufferSize() throws Exception {
-    byte[] dataToSend = new byte[100_000];
-    prepareForUpload(BLOB_INFO, dataToSend, MIN_BUFFER_SIZE);
-    InputStream input = new ByteArrayInputStream(dataToSend);
-    int smallBufferSize = 100;
-    storageOperations.upload(BLOB_INFO, input, smallBufferSize);
-  }
-
-  @Test
-  public void testUploadFromIOException() throws Exception {
-    IOException ioException = new IOException("message");
-    WriteChannel channel = createStrictMock(WriteChannel.class);
-    channel.setChunkSize(DEFAULT_BUFFER_SIZE);
-    expect(channel.write((ByteBuffer) anyObject())).andThrow(ioException);
-    replay(channel);
-    expect(storage.writer(eq(BLOB_INFO))).andReturn(channel);
-    replay(storage);
-    InputStream input = new ByteArrayInputStream(new byte[10]);
-    try {
-      storageOperations.upload(BLOB_INFO, input);
-      fail();
-    } catch (IOException e) {
-      assertSame(e, ioException);
-    }
-  }
-
-  @Test
-  public void testUploadMultiplePortions() throws Exception {
-    int totalSize = 400_000;
-    int bufferSize = 300_000;
-    byte[] dataToSend = new byte[totalSize];
-    dataToSend[0] = 42;
-    dataToSend[bufferSize] = 43;
-
-    WriteChannel channel = createStrictMock(WriteChannel.class);
-    channel.setChunkSize(bufferSize);
-    expect(channel.write(ByteBuffer.wrap(dataToSend, 0, bufferSize))).andReturn(1);
-    expect(channel.write(ByteBuffer.wrap(dataToSend, bufferSize, totalSize - bufferSize)))
-        .andReturn(2);
-    channel.close();
-    replay(channel);
-    expect(storage.writer(BLOB_INFO)).andReturn(channel);
-    replay(storage);
-
-    InputStream input = new ByteArrayInputStream(dataToSend);
-    storageOperations.upload(BLOB_INFO, input, bufferSize);
-  }
-}
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 09411792..6abc233f 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
@@ -76,7 +76,6 @@ import com.google.cloud.storage.StorageBatch;
 import com.google.cloud.storage.StorageBatchResult;
 import com.google.cloud.storage.StorageClass;
 import com.google.cloud.storage.StorageException;
-import com.google.cloud.storage.StorageOperations;
 import com.google.cloud.storage.StorageOptions;
 import com.google.cloud.storage.StorageRoles;
 import com.google.cloud.storage.testing.RemoteStorageHelper;
@@ -104,8 +103,6 @@ import java.io.InputStream;
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.ByteBuffer;
-import java.nio.file.Files;
-import java.nio.file.Path;
 import java.security.Key;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -134,7 +131,6 @@ public class ITStorageTest {
 
   private static RemoteStorageHelper remoteStorageHelper;
   private static Storage storage;
-  private static StorageOperations storageOperations;
   private static String kmsKeyOneResourcePath;
   private static String kmsKeyTwoResourcePath;
   private static Metadata requestParamsHeader = new Metadata();
@@ -179,7 +175,6 @@ public class ITStorageTest {
   public static void beforeClass() throws IOException {
     remoteStorageHelper = RemoteStorageHelper.create();
     storage = remoteStorageHelper.getOptions().getService();
-    storageOperations = new StorageOperations(storage);
 
     storage.create(
         BucketInfo.newBuilder(BUCKET)
@@ -3213,43 +3208,4 @@ public class ITStorageTest {
       RemoteStorageHelper.forceDelete(storage, loggingBucket, 5, TimeUnit.SECONDS);
     }
   }
-
-  @Test
-  public void testUploadFromDownloadTo() throws Exception {
-    String blobName = "test-uploadFrom-downloadTo-blob";
-    BlobId blobId = BlobId.of(BUCKET, blobName);
-    BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
-
-    Path tempFileFrom = Files.createTempFile("ITStorageTest_", ".tmp");
-    Files.write(tempFileFrom, BLOB_BYTE_CONTENT);
-    storageOperations.upload(blobInfo, tempFileFrom);
-
-    Path tempFileTo = Files.createTempFile("ITStorageTest_", ".tmp");
-    storage.get(blobId).downloadTo(tempFileTo);
-    byte[] readBytes = Files.readAllBytes(tempFileTo);
-    assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
-  }
-
-  @Test
-  public void testUploadWithEncryption() throws Exception {
-    String blobName = "test-upload-withEncryption";
-    BlobId blobId = BlobId.of(BUCKET, blobName);
-    BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
-
-    ByteArrayInputStream content = new ByteArrayInputStream(BLOB_BYTE_CONTENT);
-    storageOperations.upload(blobInfo, content, Storage.BlobWriteOption.encryptionKey(KEY));
-
-    Blob blob = storage.get(blobId);
-    try {
-      blob.getContent();
-      fail("StorageException was expected");
-    } catch (StorageException e) {
-      String expectedMessage =
-          "The target object is encrypted by a customer-supplied encryption key.";
-      assertTrue(e.getMessage().contains(expectedMessage));
-      assertEquals(400, e.getCode());
-    }
-    byte[] readBytes = blob.getContent(Blob.BlobSourceOption.decryptionKey(KEY));
-    assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
-  }
 }