Skip to content

Commit 917c660

Browse files
committed
Local Unit testing with real DynamoDB
Provides `@Configurable` annotation for JUnit tests to bootstrap a (in-memory) DynamoDB database for real-life testing of AWS SDK calls. By no means should this replace the TI tests that aim for the standalon DynamoDB integration testing!
1 parent 500b5fa commit 917c660

File tree

8 files changed

+223
-12
lines changed

8 files changed

+223
-12
lines changed

pom.xml

+118
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
<cdi.version>1.2</cdi.version>
4848
<slf4j-test.version>1.2.0</slf4j-test.version>
49+
<sqlite4java.version>1.0.392</sqlite4java.version>
4950

5051
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
5152
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -97,6 +98,12 @@
9798
<scope>import</scope>
9899
</dependency>
99100

101+
<dependency>
102+
<groupId>com.amazonaws</groupId>
103+
<artifactId>DynamoDBLocal</artifactId>
104+
<version>[1.11,2.0)</version>
105+
</dependency>
106+
100107
<dependency>
101108
<groupId>uk.org.lidalia</groupId>
102109
<artifactId>slf4j-test</artifactId>
@@ -153,6 +160,11 @@
153160
<artifactId>spring-test</artifactId>
154161
<scope>test</scope>
155162
</dependency>
163+
<dependency>
164+
<groupId>com.amazonaws</groupId>
165+
<artifactId>DynamoDBLocal</artifactId>
166+
<scope>test</scope>
167+
</dependency>
156168
<dependency>
157169
<groupId>junit</groupId>
158170
<artifactId>junit</artifactId>
@@ -411,6 +423,43 @@
411423
</execution>
412424
</executions>
413425
</plugin>
426+
<plugin>
427+
<groupId>org.apache.maven.plugins</groupId>
428+
<artifactId>maven-dependency-plugin</artifactId>
429+
<executions>
430+
<execution>
431+
<id>copy</id>
432+
<phase>test-compile</phase>
433+
<goals>
434+
<goal>copy</goal>
435+
</goals>
436+
<configuration>
437+
<artifactItems>
438+
<artifactItem>
439+
<groupId>com.almworks.sqlite4java</groupId>
440+
<artifactId>${sqlite4java.artifactId}</artifactId>
441+
<version>${sqlite4java.version}</version>
442+
<type>${sqlite4java.type}</type>
443+
<overWrite>true</overWrite>
444+
<outputDirectory>${project.build.directory}/lib</outputDirectory>
445+
</artifactItem>
446+
</artifactItems>
447+
</configuration>
448+
</execution>
449+
</executions>
450+
</plugin>
451+
<plugin>
452+
<groupId>org.apache.maven.plugins</groupId>
453+
<artifactId>maven-surefire-plugin</artifactId>
454+
<configuration>
455+
<systemProperties>
456+
<property>
457+
<name>sqlite4java.library.path</name>
458+
<value>${project.build.directory}/lib</value>
459+
</property>
460+
</systemProperties>
461+
</configuration>
462+
</plugin>
414463
<plugin>
415464
<groupId>org.apache.maven.plugins</groupId>
416465
<artifactId>maven-failsafe-plugin</artifactId>
@@ -444,6 +493,11 @@
444493
<id>spring-libs-snapshot</id>
445494
<url>http://repo.springsource.org/libs-snapshot</url>
446495
</repository>
496+
<repository>
497+
<id>dynamodb-local-oregon</id>
498+
<name>DynamoDB Local Release Repository</name>
499+
<url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</url>
500+
</repository>
447501
</repositories>
448502

449503
<pluginRepositories>
@@ -457,6 +511,70 @@
457511
</pluginRepositories>
458512

459513
<profiles>
514+
<profile>
515+
<id>mac</id>
516+
<activation>
517+
<os>
518+
<family>mac</family>
519+
</os>
520+
</activation>
521+
<properties>
522+
<sqlite4java.artifactId>libsqlite4java-osx</sqlite4java.artifactId>
523+
<sqlite4java.type>dylib</sqlite4java.type>
524+
</properties>
525+
</profile>
526+
<profile>
527+
<id>linux-x32</id>
528+
<activation>
529+
<os>
530+
<family>unix</family>
531+
<arch>i386</arch>
532+
</os>
533+
</activation>
534+
<properties>
535+
<sqlite4java.artifactId>libsqlite4java-linux-i386</sqlite4java.artifactId>
536+
<sqlite4java.type>so</sqlite4java.type>
537+
</properties>
538+
</profile>
539+
<profile>
540+
<id>linux-x64</id>
541+
<activation>
542+
<os>
543+
<family>unix</family>
544+
<arch>amd64</arch>
545+
</os>
546+
</activation>
547+
<properties>
548+
<sqlite4java.artifactId>libsqlite4java-linux-amd64</sqlite4java.artifactId>
549+
<sqlite4java.type>so</sqlite4java.type>
550+
</properties>
551+
</profile>
552+
<profile>
553+
<id>windows-x86</id>
554+
<activation>
555+
<os>
556+
<family>windows</family>
557+
<arch>x86</arch>
558+
</os>
559+
</activation>
560+
<properties>
561+
<sqlite4java.artifactId>libsqlite4java-win32-x86</sqlite4java.artifactId>
562+
<sqlite4java.type>dll</sqlite4java.type>
563+
</properties>
564+
</profile>
565+
<profile>
566+
<id>windows-x64</id>
567+
<activation>
568+
<os>
569+
<family>windows</family>
570+
<arch>x64</arch>
571+
</os>
572+
</activation>
573+
<properties>
574+
<sqlite4java.artifactId>libsqlite4java-win32-x64</sqlite4java.artifactId>
575+
<sqlite4java.type>dll</sqlite4java.type>
576+
</properties>
577+
</profile>
460578
<profile>
461579
<id>release</id>
462580
<build>

src/test/java/org/socialsignin/spring/data/dynamodb/core/CustomerHistoryIT.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.socialsignin.spring.data.dynamodb.domain.sample.CustomerHistory;
2121
import org.socialsignin.spring.data.dynamodb.domain.sample.CustomerHistoryRepository;
2222
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
23+
import org.socialsignin.spring.data.dynamodb.utils.DynamoDBResource;
2324
import org.springframework.beans.factory.annotation.Autowired;
2425
import org.springframework.context.annotation.Configuration;
2526
import org.springframework.test.context.ContextConfiguration;
@@ -29,7 +30,7 @@
2930

3031

3132
@RunWith(SpringJUnit4ClassRunner.class)
32-
@ContextConfiguration(classes={CustomerHistoryIT.TestAppConfig.class, ConfigurationTI.class})
33+
@ContextConfiguration(classes={CustomerHistoryIT.TestAppConfig.class, DynamoDBResource.class})
3334
public class CustomerHistoryIT {
3435

3536
@Configuration

src/test/java/org/socialsignin/spring/data/dynamodb/core/DynamoDBTemplateIT.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.junit.Test;
2121
import org.junit.runner.RunWith;
2222
import org.socialsignin.spring.data.dynamodb.domain.sample.User;
23+
import org.socialsignin.spring.data.dynamodb.utils.DynamoDBResource;
2324
import org.springframework.beans.factory.annotation.Autowired;
2425
import org.springframework.test.context.ContextConfiguration;
2526
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -30,7 +31,7 @@
3031
* Integration test that interacts with DynamoDB Local instance.
3132
*/
3233
@RunWith(SpringJUnit4ClassRunner.class)
33-
@ContextConfiguration(classes={ConfigurationTI.class})
34+
@ContextConfiguration(classes={DynamoDBResource.class})
3435
public class DynamoDBTemplateIT {
3536

3637
@Autowired

src/test/java/org/socialsignin/spring/data/dynamodb/core/FeedUserIT.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.junit.runner.RunWith;
2020
import org.socialsignin.spring.data.dynamodb.domain.sample.FeedUserRepository;
2121
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
22+
import org.socialsignin.spring.data.dynamodb.utils.DynamoDBResource;
2223
import org.springframework.beans.factory.annotation.Autowired;
2324
import org.springframework.context.annotation.Configuration;
2425
import org.springframework.data.domain.PageRequest;
@@ -28,7 +29,7 @@
2829
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
2930

3031
@RunWith(SpringJUnit4ClassRunner.class)
31-
@ContextConfiguration(classes={FeedUserIT.TestAppConfig.class, ConfigurationTI.class})
32+
@ContextConfiguration(classes={FeedUserIT.TestAppConfig.class, DynamoDBResource.class})
3233
public class FeedUserIT {
3334

3435
@Configuration

src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/GlobalSecondaryIndexWithRangeKeyIT.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
import org.junit.Test;
1919
import org.junit.runner.RunWith;
20-
import org.socialsignin.spring.data.dynamodb.core.ConfigurationTI;
2120
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
21+
import org.socialsignin.spring.data.dynamodb.utils.DynamoDBResource;
2222
import org.springframework.beans.factory.annotation.Autowired;
2323
import org.springframework.context.annotation.Configuration;
2424
import org.springframework.test.context.ContextConfiguration;
@@ -38,7 +38,7 @@
3838
* Shows the usage of Hash+Range key combinations with global secondary indexes.
3939
*/
4040
@RunWith(SpringJUnit4ClassRunner.class)
41-
@ContextConfiguration(classes = {ConfigurationTI.class, GlobalSecondaryIndexWithRangeKeyIT.TestAppConfig.class})
41+
@ContextConfiguration(classes = {DynamoDBResource.class, GlobalSecondaryIndexWithRangeKeyIT.TestAppConfig.class})
4242
public class GlobalSecondaryIndexWithRangeKeyIT {
4343

4444
@Configuration

src/test/java/org/socialsignin/spring/data/dynamodb/domain/sample/Jdk8IT.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
import org.junit.Test;
1919
import org.junit.runner.RunWith;
20-
import org.socialsignin.spring.data.dynamodb.core.ConfigurationTI;
2120
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
21+
import org.socialsignin.spring.data.dynamodb.utils.DynamoDBResource;
2222
import org.springframework.beans.factory.annotation.Autowired;
2323
import org.springframework.context.annotation.Configuration;
2424
import org.springframework.test.context.ContextConfiguration;
@@ -39,7 +39,7 @@
3939
* github.com/spring-projects/spring-data-examples/master/jpa/java8</a>
4040
*/
4141
@RunWith(SpringJUnit4ClassRunner.class)
42-
@ContextConfiguration(classes = {ConfigurationTI.class, Jdk8IT.TestAppConfig.class})
42+
@ContextConfiguration(classes = {DynamoDBResource.class, Jdk8IT.TestAppConfig.class})
4343
public class Jdk8IT {
4444

4545
@Configuration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* Copyright © 2013 spring-data-dynamodb (https://github.com/derjust/spring-data-dynamodb)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.socialsignin.spring.data.dynamodb.utils;
17+
18+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
19+
import com.amazonaws.services.dynamodbv2.local.embedded.DynamoDBEmbedded;
20+
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
21+
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
22+
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
23+
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
24+
import com.amazonaws.services.dynamodbv2.model.KeyType;
25+
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
26+
import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType;
27+
import org.junit.rules.ExternalResource;
28+
import org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBEntityMetadataSupport;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
35+
@Configuration
36+
public class DynamoDBLocalResource extends ExternalResource {
37+
38+
private AmazonDynamoDB ddb;
39+
40+
@Bean
41+
public AmazonDynamoDB amazonDynamoDB() {
42+
ddb = DynamoDBEmbedded.create().amazonDynamoDB();
43+
return ddb;
44+
}
45+
46+
public CreateTableResult createTable(Class<?> domainType) {
47+
DynamoDBEntityMetadataSupport support = new DynamoDBEntityMetadataSupport(domainType);
48+
49+
String tableName = support.getDynamoDBTableName();
50+
String hashKey = support.getHashKeyPropertyName();
51+
String rangeKey = support.getHashKeyPropertyName();
52+
53+
return createTable(tableName, hashKey, rangeKey);
54+
}
55+
56+
private CreateTableResult createTable(String tableName, String hashKeyName, String rangeKeyName) {
57+
List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
58+
attributeDefinitions.add(new AttributeDefinition(hashKeyName, ScalarAttributeType.S));
59+
60+
List<KeySchemaElement> ks = new ArrayList<>();
61+
ks.add(new KeySchemaElement(hashKeyName, KeyType.HASH));
62+
63+
if (rangeKeyName != null) {
64+
attributeDefinitions.add(new AttributeDefinition(rangeKeyName, ScalarAttributeType.S));
65+
66+
ks.add(new KeySchemaElement(rangeKeyName, KeyType.RANGE));
67+
}
68+
69+
ProvisionedThroughput provisionedthroughput = new ProvisionedThroughput(10L, 10L);
70+
71+
CreateTableRequest request =
72+
new CreateTableRequest()
73+
.withTableName(tableName)
74+
.withAttributeDefinitions(attributeDefinitions)
75+
.withKeySchema(ks)
76+
.withProvisionedThroughput(provisionedthroughput);
77+
78+
return ddb.createTable(request);
79+
}
80+
81+
@Override
82+
protected void after() {
83+
ddb.shutdown();
84+
};
85+
}

src/test/java/org/socialsignin/spring/data/dynamodb/core/ConfigurationTI.java src/test/java/org/socialsignin/spring/data/dynamodb/utils/DynamoDBResource.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.socialsignin.spring.data.dynamodb.core;
16+
package org.socialsignin.spring.data.dynamodb.utils;
1717

18+
import com.amazonaws.auth.AWSStaticCredentialsProvider;
1819
import com.amazonaws.auth.BasicAWSCredentials;
20+
import com.amazonaws.client.builder.AwsClientBuilder;
1921
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
2022
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
23+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
2124
import org.springframework.context.annotation.Bean;
2225
import org.springframework.context.annotation.Configuration;
2326
import org.springframework.util.Assert;
@@ -28,17 +31,19 @@
2831
* launched local DynamoDB by Maven's integration-test.
2932
*/
3033
@Configuration
31-
public class ConfigurationTI {
34+
public class DynamoDBResource {
3235
private static final String DYNAMODB_PORT_PROPERTY = "dynamodb.port";
3336
private static final String PORT = System.getProperty(DYNAMODB_PORT_PROPERTY);
3437

3538
@Bean
3639
public AmazonDynamoDB amazonDynamoDB() {
3740
Assert.notNull(PORT, "System property '" + DYNAMODB_PORT_PROPERTY + " not set!");
3841

39-
AmazonDynamoDB dynamoDB = new AmazonDynamoDBClient(new BasicAWSCredentials("AWS-Key", ""));
40-
dynamoDB.setEndpoint(String.format("http://localhost:%s", PORT));
42+
AmazonDynamoDBClientBuilder builder = AmazonDynamoDBClientBuilder.standard();
43+
builder.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("AWS-Key", "")));
44+
builder.withEndpointConfiguration(
45+
new AwsClientBuilder.EndpointConfiguration(String.format("http://localhost:%s", PORT), "us-east-1"));
4146

42-
return dynamoDB;
47+
return builder.build();
4348
}
4449
}

0 commit comments

Comments
 (0)