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

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 8df75c5c9 fix(binding/java): fix return value of presign-related 
method (#3433)
8df75c5c9 is described below

commit 8df75c5c93362a07e8fbc4b78cf830e149479cd3
Author: G-XD <[email protected]>
AuthorDate: Wed Nov 1 00:51:52 2023 +0800

    fix(binding/java): fix return value of presign-related method (#3433)
---
 bindings/java/pom.xml                              |  12 ++
 .../src/main/java/org/apache/opendal/Operator.java |   6 +-
 .../opendal/test/behavior/AsyncPresignTest.java    | 141 +++++++++++++++++++++
 3 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/bindings/java/pom.xml b/bindings/java/pom.xml
index 4eaa70059..5780f735d 100644
--- a/bindings/java/pom.xml
+++ b/bindings/java/pom.xml
@@ -63,6 +63,7 @@
         <dotenv.version>2.3.2</dotenv.version>
         <lombok.version>1.18.30</lombok.version>
         <slf4j.version>2.0.7</slf4j.version>
+        <httpclient.version>5.2</httpclient.version>
 
         <!-- plugins dependencies -->
         <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
@@ -101,6 +102,12 @@
                 <artifactId>dotenv-java</artifactId>
                 <version>${dotenv.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.httpcomponents.client5</groupId>
+                <artifactId>httpclient5</artifactId>
+                <version>${httpclient.version}</version>
+                <scope>test</scope>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
@@ -136,6 +143,11 @@
             <artifactId>dotenv-java</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/bindings/java/src/main/java/org/apache/opendal/Operator.java 
b/bindings/java/src/main/java/org/apache/opendal/Operator.java
index 79f9799e5..e83ea72de 100644
--- a/bindings/java/src/main/java/org/apache/opendal/Operator.java
+++ b/bindings/java/src/main/java/org/apache/opendal/Operator.java
@@ -173,17 +173,17 @@ public class Operator extends NativeObject {
         return AsyncRegistry.take(requestId);
     }
 
-    public CompletableFuture<Void> presignRead(String path, Duration duration) 
{
+    public CompletableFuture<PresignedRequest> presignRead(String path, 
Duration duration) {
         final long requestId = presignRead(nativeHandle, path, 
duration.toNanos());
         return AsyncRegistry.take(requestId);
     }
 
-    public CompletableFuture<Void> presignWrite(String path, Duration 
duration) {
+    public CompletableFuture<PresignedRequest> presignWrite(String path, 
Duration duration) {
         final long requestId = presignWrite(nativeHandle, path, 
duration.toNanos());
         return AsyncRegistry.take(requestId);
     }
 
-    public CompletableFuture<Void> presignStat(String path, Duration duration) 
{
+    public CompletableFuture<PresignedRequest> presignStat(String path, 
Duration duration) {
         final long requestId = presignStat(nativeHandle, path, 
duration.toNanos());
         return AsyncRegistry.take(requestId);
     }
diff --git 
a/bindings/java/src/test/java/org/apache/opendal/test/behavior/AsyncPresignTest.java
 
b/bindings/java/src/test/java/org/apache/opendal/test/behavior/AsyncPresignTest.java
new file mode 100644
index 000000000..05b129b59
--- /dev/null
+++ 
b/bindings/java/src/test/java/org/apache/opendal/test/behavior/AsyncPresignTest.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.opendal.test.behavior;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.time.Duration;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.HttpStatus;
+import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
+import org.apache.opendal.Capability;
+import org.apache.opendal.Metadata;
+import org.apache.opendal.PresignedRequest;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class AsyncPresignTest extends BehaviorTestBase {
+
+    @BeforeAll
+    public void precondition() {
+        final Capability capability = op().info.fullCapability;
+        assumeTrue(capability.list && capability.write && capability.presign);
+    }
+
+    /**
+     * Presign write should succeed.
+     */
+    @Test
+    public void testPresignWrite() throws IOException {
+        final String path = UUID.randomUUID().toString();
+        final byte[] content = generateBytes();
+
+        final PresignedRequest signedReq =
+                op().presignWrite(path, Duration.ofSeconds(3600)).join();
+
+        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
+            final ClassicRequestBuilder builder =
+                    createRequestBuilder(signedReq).setEntity(content, null);
+
+            httpclient.execute(builder.build(), rsp -> rsp);
+        }
+
+        final Metadata meta = op().stat(path).join();
+        assertEquals(content.length, meta.getContentLength());
+
+        op().delete(path).join();
+    }
+
+    /**
+     * Presign stat should succeed.
+     */
+    @Test
+    public void testPresignStat() throws IOException {
+        final String path = UUID.randomUUID().toString();
+        final byte[] content = generateBytes();
+        op().write(path, content).join();
+
+        final PresignedRequest signedReq =
+                op().presignStat(path, Duration.ofSeconds(3600)).join();
+        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
+            final ClassicRequestBuilder builder = 
createRequestBuilder(signedReq);
+
+            final ClassicHttpResponse response = 
httpclient.execute(builder.build(), rsp -> rsp);
+            assertEquals(HttpStatus.SC_OK, response.getCode());
+            assertEquals(
+                    String.valueOf(content.length),
+                    
response.getFirstHeader(HttpHeaders.CONTENT_LENGTH).getValue());
+        }
+
+        op().delete(path).join();
+    }
+
+    /**
+     * Presign read should read content successfully.
+     */
+    @Test
+    public void testPresignRead() throws IOException, NoSuchAlgorithmException 
{
+        final String path = UUID.randomUUID().toString();
+        final byte[] content = generateBytes();
+        op().write(path, content).join();
+
+        final PresignedRequest signedReq =
+                op().presignRead(path, Duration.ofSeconds(3600)).join();
+        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
+            final ClassicRequestBuilder builder = 
createRequestBuilder(signedReq);
+
+            final byte[] responseContent = httpclient.execute(builder.build(), 
rsp -> {
+                return EntityUtils.toByteArray(rsp.getEntity());
+            });
+            assertEquals(content.length, responseContent.length);
+
+            final MessageDigest digest = MessageDigest.getInstance("SHA-256");
+            assertArrayEquals(digest.digest(content), 
digest.digest(responseContent));
+        }
+
+        op().delete(path).join();
+    }
+
+    private ClassicRequestBuilder createRequestBuilder(final PresignedRequest 
signedReq) {
+        final ClassicRequestBuilder builder =
+                
ClassicRequestBuilder.create(signedReq.getMethod()).setUri(signedReq.getUri());
+        for (Map.Entry<String, String> entry : 
signedReq.getHeaders().entrySet()) {
+            // Skip content-length header, which is auto set by the http 
client.
+            // If the header is set, the request will throw exception: 
Content-Length header already present.
+            if (HttpHeaders.CONTENT_LENGTH.equalsIgnoreCase(entry.getKey())) {
+                continue;
+            }
+            builder.addHeader(entry.getKey(), entry.getValue());
+        }
+        return builder;
+    }
+}

Reply via email to