This is an automated email from the ASF dual-hosted git repository.

gaul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jclouds.git


The following commit(s) were added to refs/heads/master by this push:
     new 6e6f8eb  JCLOUDS-912: JCLOUDS-1547: GCS InputStream single-part upload
6e6f8eb is described below

commit 6e6f8ebf779d8edc5cedec687558637d8212ab18
Author: Andrew Gaul <[email protected]>
AuthorDate: Sat May 23 13:25:24 2020 +0900

    JCLOUDS-912: JCLOUDS-1547: GCS InputStream single-part upload
    
    Previously this provider worked around a RestAnnotationProcessor quirk
    by using multi-part uploads for InputStream payloads.  Instead work
    around the quirk another way which allows a single-part upload.  This
    allows inclusion of the Content-MD5 header during object creation.
    Backfill tests with both ByteSource and InputStream inputs.
---
 .../internal/BaseBlobIntegrationTest.java          | 38 +++++++++++++++++-----
 .../http/internal/PayloadEnclosingImpl.java        |  8 +++++
 .../main/java/org/jclouds/io/PayloadEnclosing.java |  1 +
 .../integration/B2BlobIntegrationLiveTest.java     | 14 ++++++--
 .../binders/MultipartUploadBinder.java             |  1 +
 .../blobstore/GoogleCloudStorageBlobStore.java     |  2 +-
 6 files changed, 53 insertions(+), 11 deletions(-)

diff --git 
a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
 
b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
index ef5bd7f..a814c00 100644
--- 
a/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
+++ 
b/blobstore/src/test/java/org/jclouds/blobstore/integration/internal/BaseBlobIntegrationTest.java
@@ -267,7 +267,7 @@ public class BaseBlobIntegrationTest extends 
BaseBlobStoreIntegrationTest {
       }
    }
 
-   private void putBlobWithMd5(byte[] payload, HashCode contentMD5) throws 
InterruptedException, IOException {
+   private void putBlobWithMd5(Payload payload, long contentLength, HashCode 
contentMD5) throws InterruptedException, IOException {
       String container = getContainerName();
       BlobStore blobStore = view.getBlobStore();
       try {
@@ -275,6 +275,7 @@ public class BaseBlobIntegrationTest extends 
BaseBlobStoreIntegrationTest {
          Blob blob = blobStore
             .blobBuilder(blobName)
             .payload(payload)
+            .contentLength(contentLength)
             .contentMD5(contentMD5)
             .build();
          blobStore.putBlob(container, blob);
@@ -288,18 +289,39 @@ public class BaseBlobIntegrationTest extends 
BaseBlobStoreIntegrationTest {
    }
 
    @Test(groups = { "integration", "live" })
-   public void testPutCorrectContentMD5() throws InterruptedException, 
IOException {
-      byte[] payload = createTestInput(1024).read();
-      HashCode contentMD5 = md5().hashBytes(payload);
-      putBlobWithMd5(payload, contentMD5);
+   public void testPutCorrectContentMD5ByteSource() throws 
InterruptedException, IOException {
+      ByteSource payload = createTestInput(1024);
+      HashCode contentMD5 = md5().hashBytes(payload.read());
+      putBlobWithMd5(new ByteSourcePayload(payload), payload.size(), 
contentMD5);
+   }
+
+   @Test(groups = { "integration", "live" })
+   public void testPutIncorrectContentMD5ByteSource() throws 
InterruptedException, IOException {
+      ByteSource payload = createTestInput(1024);
+      HashCode contentMD5 = md5().hashBytes(new byte[0]);
+      try {
+         putBlobWithMd5(new ByteSourcePayload(payload), payload.size(), 
contentMD5);
+         fail();
+      } catch (HttpResponseException hre) {
+         if (hre.getResponse().getStatusCode() != 
getIncorrectContentMD5StatusCode()) {
+            throw hre;
+         }
+      }
    }
 
    @Test(groups = { "integration", "live" })
-   public void testPutIncorrectContentMD5() throws InterruptedException, 
IOException {
-      byte[] payload = createTestInput(1024).read();
+   public void testPutCorrectContentMD5InputStream() throws 
InterruptedException, IOException {
+      ByteSource payload = createTestInput(1024);
+      HashCode contentMD5 = md5().hashBytes(payload.read());
+      putBlobWithMd5(new InputStreamPayload(payload.openStream()), 
payload.size(), contentMD5);
+   }
+
+   @Test(groups = { "integration", "live" })
+   public void testPutIncorrectContentMD5InputStream() throws 
InterruptedException, IOException {
+      ByteSource payload = createTestInput(1024);
       HashCode contentMD5 = md5().hashBytes(new byte[0]);
       try {
-         putBlobWithMd5(payload, contentMD5);
+         putBlobWithMd5(new InputStreamPayload(payload.openStream()), 
payload.size(), contentMD5);
          fail();
       } catch (HttpResponseException hre) {
          if (hre.getResponse().getStatusCode() != 
getIncorrectContentMD5StatusCode()) {
diff --git 
a/core/src/main/java/org/jclouds/http/internal/PayloadEnclosingImpl.java 
b/core/src/main/java/org/jclouds/http/internal/PayloadEnclosingImpl.java
index a8b5196..bff39b6 100644
--- a/core/src/main/java/org/jclouds/http/internal/PayloadEnclosingImpl.java
+++ b/core/src/main/java/org/jclouds/http/internal/PayloadEnclosingImpl.java
@@ -98,6 +98,14 @@ public class PayloadEnclosingImpl implements 
PayloadEnclosing {
    }
 
    @Override
+   public void resetPayload(boolean release) {
+      if (release && payload != null) {
+         payload.release();
+      }
+      payload = null;
+   }
+
+   @Override
    public int hashCode() {
       final int prime = 31;
       int result = 1;
diff --git a/core/src/main/java/org/jclouds/io/PayloadEnclosing.java 
b/core/src/main/java/org/jclouds/io/PayloadEnclosing.java
index 3ed2983..dd3f28b 100644
--- a/core/src/main/java/org/jclouds/io/PayloadEnclosing.java
+++ b/core/src/main/java/org/jclouds/io/PayloadEnclosing.java
@@ -48,4 +48,5 @@ public interface PayloadEnclosing {
    @Nullable
    Payload getPayload();
 
+   void resetPayload(boolean release);
 }
diff --git 
a/providers/b2/src/test/java/org/jclouds/b2/blobstore/integration/B2BlobIntegrationLiveTest.java
 
b/providers/b2/src/test/java/org/jclouds/b2/blobstore/integration/B2BlobIntegrationLiveTest.java
index 0ecb6bd..3f45077 100644
--- 
a/providers/b2/src/test/java/org/jclouds/b2/blobstore/integration/B2BlobIntegrationLiveTest.java
+++ 
b/providers/b2/src/test/java/org/jclouds/b2/blobstore/integration/B2BlobIntegrationLiveTest.java
@@ -80,9 +80,19 @@ public final class B2BlobIntegrationLiveTest extends 
BaseBlobIntegrationTest {
    }
 
    @Override
-   public void testPutIncorrectContentMD5() throws InterruptedException, 
IOException {
+   public void testPutIncorrectContentMD5ByteSource() throws 
InterruptedException, IOException {
       try {
-         super.testPutIncorrectContentMD5();
+         super.testPutIncorrectContentMD5ByteSource();
+         failBecauseExceptionWasNotThrown(AssertionError.class);
+      } catch (AssertionError ae) {
+         throw new SkipException("B2 does not enforce Content-MD5", ae);
+      }
+   }
+
+   @Override
+   public void testPutIncorrectContentMD5InputStream() throws 
InterruptedException, IOException {
+      try {
+         super.testPutIncorrectContentMD5InputStream();
          failBecauseExceptionWasNotThrown(AssertionError.class);
       } catch (AssertionError ae) {
          throw new SkipException("B2 does not enforce Content-MD5", ae);
diff --git 
a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
 
b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
index ca6422b..848b8c6 100644
--- 
a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
+++ 
b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/binders/MultipartUploadBinder.java
@@ -57,6 +57,7 @@ public final class MultipartUploadBinder implements MapBinder 
{
       Part jsonPart = Part.create("Metadata", jsonPayload, new 
Part.PartOptions().contentType(APPLICATION_JSON));
       Part mediaPart = Part.create(template.name(), payload, new 
Part.PartOptions().contentType(contentType));
 
+      request.resetPayload(/*release=*/ false);
       request.setPayload(new MultipartForm(BOUNDARY_HEADER, jsonPart, 
mediaPart));
       // HeaderPart
       request.toBuilder().replaceHeader(CONTENT_TYPE, "Multipart/related; 
boundary= " + BOUNDARY_HEADER).build();
diff --git 
a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
 
b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
index 029ca03..8777643 100644
--- 
a/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
+++ 
b/providers/google-cloud-storage/src/main/java/org/jclouds/googlecloudstorage/blobstore/GoogleCloudStorageBlobStore.java
@@ -211,7 +211,7 @@ public final class GoogleCloudStorageBlobStore extends 
BaseBlobStore {
    public String putBlob(String container, Blob blob, PutOptions options) {
       long length = 
checkNotNull(blob.getPayload().getContentMetadata().getContentLength());
 
-      if (length != 0 && (options.isMultipart() || 
!blob.getPayload().isRepeatable())) {
+      if (length != 0 && options.isMultipart()) {
          // JCLOUDS-912 prevents using single-part uploads with InputStream 
payloads.
          // Work around this with multi-part upload which buffers parts 
in-memory.
          return putMultipartBlob(container, blob, options);

Reply via email to