Skip to content
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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 61 additions & 0 deletions docs/modules/databases/awsdynamodb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# AWS DynamoDb Module

Testcontainers module for
[AWS DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html).
The official [amazon/dynamodb-local](https://hub.docker.com/r/amazon/dynamodb-local) Docker image
should be used to instantiate this Testcontainer. You can check Docker Hub for the latest available
tag [here](https://hub.docker.com/r/amazon/dynamodb-local/tags?page=1&ordering=last_updated).

## How to install

To use this
[DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html)
Testcontainer, 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>
```

This library does not leak any AWS dependencies. To use this Testcontainer, make sure you have the
following dependency in your classpath

```groovy tab='Gradle'
testCompile "software.amazon.awssdk:dynamodb"
```

```xml tab='Maven'
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
</dependency>
```

You can check the latest available version
[here](https://mvnrepository.com/artifact/software.amazon.awssdk/dynamodb).

## How to use it

Running the container as a stand-in for DynamoDB in a test:

```java
public class SomeTest {

@Rule
public DynamoDbContainer dynamoDB = new DynamoDbContainer("amazon/dynamodb-local:1.13.5");

@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
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ nav:
- modules/databases/index.md
- modules/databases/jdbc.md
- modules/databases/r2dbc.md
- modules/databases/awsdynamodb.md
- modules/databases/cassandra.md
- modules/databases/cockroachdb.md
- modules/databases/couchbase.md
Expand Down
8 changes: 8 additions & 0 deletions modules/aws-dynamodb/build.gradle
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,72 @@
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 Local.
*/
public class DynamoDbContainer extends GenericContainer<DynamoDbContainer> {

private static final DockerImageName DEFAULT_IMAGE_NAME =
DockerImageName.parse("amazon/dynamodb-local");
private static final int MAPPED_PORT = 8000;

public DynamoDbContainer(String dockerImageName) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This constructor isn't needed. Can you remove it?

Copy link
Author

Choose a reason for hiding this comment

The 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 {@link DynamoDbClient}
*/
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 a {@link URI} pointing to this container
*/
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 {@link StaticCredentialsProvider} to connect to this container
*/
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());
}
}
16 changes: 16 additions & 0 deletions modules/aws-dynamodb/src/test/resources/logback-test.xml
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>