diff --git a/docs/modules/localstack.md b/docs/modules/localstack.md index bf520b1fac6..4ff46233b05 100644 --- a/docs/modules/localstack.md +++ b/docs/modules/localstack.md @@ -13,6 +13,7 @@ public LocalStackContainer localstack = new LocalStackContainer() @Test public void someTestMethod() { + // AWS SDK v1 AmazonS3 s3 = AmazonS3ClientBuilder .standard() .withEndpointConfiguration(localstack.getEndpointConfiguration(S3)) @@ -21,6 +22,19 @@ public void someTestMethod() { s3.createBucket("foo"); s3.putObject("foo", "bar", "baz"); + + // AWS SDK v2 + S3Client s3 = S3Client + .builder() + .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3)) + .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create( + localstack.getAccessKey(), localstack.getSecretKey() + ))) + .region(Region.of(localstack.getRegion())) + .build(); + + s3.createBucket(b -> b.bucket("foo")); + s3.putObject(b -> b.bucket("foo").key("bar"), RequestBody.fromBytes("baz".getBytes())); ``` Environment variables listed in [Localstack's README](https://github.com/localstack/localstack#configurations) may be used to customize Localstack's configuration. diff --git a/modules/localstack/build.gradle b/modules/localstack/build.gradle index c8bf561b6d1..cd6f3d9f86c 100644 --- a/modules/localstack/build.gradle +++ b/modules/localstack/build.gradle @@ -7,4 +7,5 @@ dependencies { testCompile 'com.amazonaws:aws-java-sdk-s3:1.11.683' testCompile 'com.amazonaws:aws-java-sdk-sqs:1.11.636' testCompile 'com.amazonaws:aws-java-sdk-logs:1.11.762' + testCompile 'software.amazon.awssdk:s3:2.11.10' } diff --git a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java index 0d8c3627f6c..c649d322ead 100644 --- a/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java +++ b/modules/localstack/src/main/java/org/testcontainers/containers/localstack/LocalStackContainer.java @@ -13,6 +13,8 @@ import org.testcontainers.utility.TestcontainersConfiguration; import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -90,7 +92,16 @@ public LocalStackContainer withServices(Service... services) { .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); - * + * or for AWS SDK v2 + *
S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
* Please note that this method is only intended to be used for configuring AWS SDK clients * that are running on the test host. If other containers need to call this one, they should be configured * specifically to do so using a Docker network and appropriate addressing.
@@ -99,20 +110,41 @@ public LocalStackContainer withServices(Service... services) { * @return an {@link AwsClientBuilder.EndpointConfiguration} */ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service service) { - final String address = getContainerIpAddress(); - String ipAddress = address; + return new AwsClientBuilder.EndpointConfiguration(getEndpointOverride(service).toString(), getRegion()); + } + + /** + * Provides an endpoint override that is preconfigured to communicate with a given simulated service. + * The provided endpoint override should be set in the AWS Java SDK v2 when building a client, e.g.: + *S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
+ * Please note that this method is only intended to be used for configuring AWS SDK clients + * that are running on the test host. If other containers need to call this one, they should be configured + * specifically to do so using a Docker network and appropriate addressing.
+ * + * @param service the service that is to be accessed + * @return an {@link URI} endpoint override + */ + public URI getEndpointOverride(Service service) { try { + final String address = getContainerIpAddress(); + String ipAddress = address; // resolve IP address and use that as the endpoint so that path-style access is automatically used for S3 ipAddress = InetAddress.getByName(address).getHostAddress(); - } catch (UnknownHostException ignored) { - - } - - return new AwsClientBuilder.EndpointConfiguration( - "http://" + + return new URI("http://" + ipAddress + ":" + - getMappedPort(service.getPort()), "us-east-1"); + getMappedPort(service.getPort())); + } catch (UnknownHostException | URISyntaxException e) { + throw new IllegalStateException("Cannot obtain endpoint URL", e); + } } /** @@ -124,10 +156,74 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s .withCredentials(localstack.getDefaultCredentialsProvider()) .build(); + * or for AWS SDK v2 you can use {@link #getAccessKey()}, {@link #getSecretKey()} directly: + *S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
* @return an {@link AWSCredentialsProvider}
*/
public AWSCredentialsProvider getDefaultCredentialsProvider() {
- return new AWSStaticCredentialsProvider(new BasicAWSCredentials("accesskey", "secretkey"));
+ return new AWSStaticCredentialsProvider(new BasicAWSCredentials(getAccessKey(), getSecretKey()));
+ }
+
+ /**
+ * Provides a default access key that is preconfigured to communicate with a given simulated service.
+ * The access key can be used to construct AWS SDK v2 clients:
+ * S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
+ * @return a default access key
+ */
+ public String getAccessKey() {
+ return "accesskey";
+ }
+
+ /**
+ * Provides a default secret key that is preconfigured to communicate with a given simulated service.
+ * The secret key can be used to construct AWS SDK v2 clients:
+ * S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
+ * @return a default secret key
+ */
+ public String getSecretKey() {
+ return "secretkey";
+ }
+
+ /**
+ * Provides a default region that is preconfigured to communicate with a given simulated service.
+ * The region can be used to construct AWS SDK v2 clients:
+ * S3Client s3 = S3Client
+ .builder()
+ .endpointOverride(localstack.getEndpointOverride(LocalStackContainer.Service.S3))
+ .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(
+ localstack.getAccessKey(), localstack.getSecretKey()
+ )))
+ .region(Region.of(localstack.getRegion()))
+ .build()
+
+ * @return a default region
+ */
+ public String getRegion() {
+ return "us-east-1";
}
@RequiredArgsConstructor
diff --git a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
index 034ff2f0914..ee5945d0aff 100644
--- a/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
+++ b/modules/localstack/src/test/java/org/testcontainers/containers/localstack/LocalstackContainerTest.java
@@ -4,8 +4,6 @@
import com.amazonaws.services.logs.AWSLogs;
import com.amazonaws.services.logs.AWSLogsClientBuilder;
import com.amazonaws.services.logs.model.CreateLogGroupRequest;
-import com.amazonaws.services.logs.model.CreateLogGroupResult;
-import com.amazonaws.services.logs.model.DescribeLogGroupsRequest;
import com.amazonaws.services.logs.model.LogGroup;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
@@ -19,7 +17,6 @@
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.ClassRule;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
@@ -27,10 +24,15 @@
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.s3.S3Client;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
+import java.util.Optional;
import static org.hamcrest.CoreMatchers.containsString;
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals;
@@ -67,24 +69,41 @@ public void s3TestOverBridgeNetwork() throws IOException {
.withCredentials(localstack.getDefaultCredentialsProvider())
.build();
- s3.createBucket("foo");
- s3.putObject("foo", "bar", "baz");
+ final String bucketName = "foo";
+ s3.createBucket(bucketName);
+ s3.putObject(bucketName, "bar", "baz");
final List