-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for dynamodb-local #3557
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# AWS DynamoDb Module | ||
|
||
Testcontainers module for [AWS DynamoDb](https://hub.docker.com/r/amazon/dynamodb-local) official | ||
Docker image. | ||
|
||
## Usage example | ||
|
||
Running the container as a stand-in for DynamoDB in a test: | ||
|
||
```java | ||
public class SomeTest { | ||
|
||
@Rule | ||
public DynamoDbContainer dynamoDB = new DynamoDbContainer(); | ||
|
||
@Test | ||
public void someTestMethod() { | ||
// getClient() returns a preconfigured DynamoDB client that is connected to the container | ||
final DynamoDbClient client = dynamoDB.getClient(); | ||
|
||
... interact with client as if using DynamoDB normally | ||
``` | ||
|
||
## Adding this module to your project dependencies | ||
|
||
Add the following dependency to your `pom.xml`/`build.gradle` file: | ||
|
||
```groovy tab='Gradle' | ||
testCompile "org.testcontainers:aws-dynamodb:{{latest_version}}" | ||
``` | ||
|
||
```xml tab='Maven' | ||
<dependency> | ||
<groupId>org.testcontainers</groupId> | ||
<artifactId>aws-dynamodb</artifactId> | ||
<version>{{latest_version}}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
``` | ||
|
||
!!! hint | ||
Adding this Testcontainers library JAR will not automatically add an AWS SDK JAR to your project. You should ensure that your project also has a suitable AWS SDK JAR as a dependency. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
description = "Testcontainers :: AWS DynamoDb" | ||
|
||
dependencies { | ||
compile project(':testcontainers') | ||
|
||
compileOnly 'software.amazon.awssdk:dynamodb:2.15.39' | ||
testCompile 'software.amazon.awssdk:dynamodb:2.15.39' | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package org.testcontainers.dynamodb; | ||
|
||
import org.testcontainers.containers.GenericContainer; | ||
import org.testcontainers.utility.DockerImageName; | ||
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.dynamodb.DynamoDbClient; | ||
|
||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
|
||
/** | ||
* Container for official AWS DynamoDB. | ||
*/ | ||
public class DynamoDbContainer extends GenericContainer<DynamoDbContainer> { | ||
|
||
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("amazon/dynamodb-local"); | ||
private static final String DEFAULT_TAG = "1.13.5"; | ||
private static final int MAPPED_PORT = 8000; | ||
|
||
/** | ||
* @deprecated use {@link DynamoDbContainer (DockerImageName)} instead | ||
*/ | ||
@Deprecated | ||
public DynamoDbContainer() { | ||
this(DEFAULT_IMAGE_NAME.withTag(DEFAULT_TAG)); | ||
} | ||
|
||
public DynamoDbContainer(String dockerImageName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constructor isn't needed. Can you remove it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right this contractor is not needed. I added only because I found it in most of the other modules. Is there any convention suggesting I should keep it? |
||
this(DockerImageName.parse(dockerImageName)); | ||
} | ||
|
||
public DynamoDbContainer(final DockerImageName dockerImageName) { | ||
super(dockerImageName); | ||
|
||
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); | ||
|
||
withExposedPorts(MAPPED_PORT); | ||
} | ||
|
||
|
||
/** | ||
* Gets a preconfigured {@link DynamoDbClient} client object for connecting to this | ||
* container. | ||
* | ||
* @return preconfigured client | ||
*/ | ||
public DynamoDbClient getClient() { | ||
return DynamoDbClient.builder() | ||
.region(Region.AWS_GLOBAL) | ||
.credentialsProvider(getCredentials()) | ||
.endpointOverride(getEndpointURI()) | ||
.build(); | ||
} | ||
|
||
/** | ||
* Gets {@link URI} that may be used to connect to this container. | ||
* | ||
* @return endpoint configuration | ||
*/ | ||
public URI getEndpointURI() { | ||
try { | ||
return new URI("http://" + | ||
this.getHost() + ":" + | ||
this.getMappedPort(MAPPED_PORT)); | ||
} catch (URISyntaxException exc) { | ||
throw new IllegalStateException("URI cannot be generated", exc); | ||
} | ||
} | ||
|
||
/** | ||
* Gets an {@link StaticCredentialsProvider} that may be used to connect to this container. | ||
* | ||
* @return dummy AWS credentials | ||
*/ | ||
public StaticCredentialsProvider getCredentials() { | ||
return StaticCredentialsProvider.create( | ||
AwsBasicCredentials.create("dummy", "dummy")); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package org.testcontainers.dynamodb; | ||
|
||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.testcontainers.utility.DockerImageName; | ||
import software.amazon.awssdk.regions.Region; | ||
import software.amazon.awssdk.services.dynamodb.DynamoDbClient; | ||
import software.amazon.awssdk.services.dynamodb.model.AttributeDefinition; | ||
import software.amazon.awssdk.services.dynamodb.model.BillingMode; | ||
import software.amazon.awssdk.services.dynamodb.model.CreateTableRequest; | ||
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest; | ||
import software.amazon.awssdk.services.dynamodb.model.KeySchemaElement; | ||
import software.amazon.awssdk.services.dynamodb.model.KeyType; | ||
import software.amazon.awssdk.services.dynamodb.model.ProvisionedThroughput; | ||
import software.amazon.awssdk.services.dynamodb.model.ScalarAttributeType; | ||
import software.amazon.awssdk.services.dynamodb.model.TableDescription; | ||
|
||
import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; | ||
import static org.rnorth.visibleassertions.VisibleAssertions.assertNotNull; | ||
|
||
public class DynamoDbContainerTest { | ||
|
||
private static final DockerImageName AWS_DYNAMODB_IMAGE = DockerImageName.parse( | ||
"amazon/dynamodb-local:1.13.5"); | ||
|
||
@Rule | ||
public DynamoDbContainer dynamoDB = new DynamoDbContainer(AWS_DYNAMODB_IMAGE); | ||
|
||
@Test | ||
public void simpleTestWithManualClientCreation() { | ||
final DynamoDbClient client = DynamoDbClient.builder() | ||
.region(Region.AWS_GLOBAL) | ||
.credentialsProvider(dynamoDB.getCredentials()) | ||
.endpointOverride(dynamoDB.getEndpointURI()) | ||
.build(); | ||
|
||
runTest(client); | ||
} | ||
|
||
@Test | ||
public void simpleTestWithProvidedClient() { | ||
final DynamoDbClient client = dynamoDB.getClient(); | ||
|
||
runTest(client); | ||
} | ||
|
||
private void runTest(DynamoDbClient client) { | ||
CreateTableRequest request = CreateTableRequest.builder() | ||
.tableName("foo") | ||
.billingMode(BillingMode.PROVISIONED) | ||
.keySchema( | ||
KeySchemaElement.builder().keyType(KeyType.HASH).attributeName("Name").build()) | ||
.attributeDefinitions( | ||
AttributeDefinition.builder() | ||
.attributeName("Name") | ||
.attributeType(ScalarAttributeType.S) | ||
.build()) | ||
.provisionedThroughput( | ||
ProvisionedThroughput.builder() | ||
.readCapacityUnits(10L) | ||
.writeCapacityUnits(10L) | ||
.build()) | ||
.build(); | ||
|
||
client.createTable(request); | ||
|
||
final TableDescription tableDescription = client.describeTable( | ||
DescribeTableRequest.builder().tableName("foo").build()) | ||
.table(); | ||
|
||
assertNotNull("the description is not null", tableDescription); | ||
assertEquals("the table has the right name", | ||
"foo", tableDescription.tableName()); | ||
assertEquals("the name has the right primary key", | ||
"Name", tableDescription.keySchema().get(0).attributeName()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<configuration> | ||
|
||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||
<!-- encoders are assigned the type | ||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> | ||
<encoder> | ||
<pattern>%d{HH:mm:ss.SSS} %-5level %logger - %msg%n</pattern> | ||
</encoder> | ||
</appender> | ||
|
||
<root level="INFO"> | ||
<appender-ref ref="STDOUT"/> | ||
</root> | ||
|
||
<logger name="org.testcontainers" level="DEBUG"/> | ||
</configuration> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this constructor? can it be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, we don't. Fixed!