Skip to content

Commit

Permalink
fix(binding/java): fix return value of presign-related method (#3433)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-XD authored Oct 31, 2023
1 parent 508d598 commit 8df75c5
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 3 deletions.
12 changes: 12 additions & 0 deletions bindings/java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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>

Expand Down Expand Up @@ -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>
Expand Down
6 changes: 3 additions & 3 deletions bindings/java/src/main/java/org/apache/opendal/Operator.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,17 +173,17 @@ public CompletableFuture<byte[]> read(String path) {
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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit 8df75c5

Please sign in to comment.