GH-64: Add DynamoDbMetaDataStore implementation

Fixes spring-projects/spring-integration-aws#64

* Add `DynamoDbRunning` for testing against locally ran DynamoDB
* Upgrade to Gradle 4.0.1, SI-4.3.11
* Switch on some Checkstyle rules for tests
This commit is contained in:
Artem Bilan
2017-08-01 12:33:40 -04:00
parent d187c838b6
commit 638d5e6f75
10 changed files with 554 additions and 7 deletions

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed 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.springframework.integration.aws;
import static org.junit.Assume.assumeNoException;
import static org.junit.Assume.assumeTrue;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsyncClientBuilder;
/**
* @author Artem Bilan
*
* @since 1.1
*/
public final class DynamoDbRunning extends TestWatcher {
private static Log logger = LogFactory.getLog(DynamoDbRunning.class);
// Static so that we only test once on failure: speeds up test suite
private static Map<Integer, Boolean> dynamoDbOnline = new HashMap<>();
private final int port;
private AmazonDynamoDBAsync amazonDynamoDB;
private DynamoDbRunning(int port) {
this.port = port;
dynamoDbOnline.put(port, true);
}
public AmazonDynamoDBAsync getDynamoDB() {
return this.amazonDynamoDB;
}
@Override
public Statement apply(Statement base, Description description) {
assumeTrue(dynamoDbOnline.get(this.port));
String url = "http://localhost:" + this.port;
this.amazonDynamoDB = AmazonDynamoDBAsyncClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("", "")))
.withClientConfiguration(
new ClientConfiguration()
.withMaxErrorRetry(0)
.withConnectionTimeout(1000))
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(url, Regions.DEFAULT_REGION.getName()))
.build();
try {
this.amazonDynamoDB.listTables();
}
catch (SdkClientException e) {
logger.warn("Tests not running because no DynamoDb on " + url, e);
assumeNoException(e);
}
return super.apply(base, description);
}
public static DynamoDbRunning isRunning(int port) {
return new DynamoDbRunning(port);
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed 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.springframework.integration.aws.metadata;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.integration.aws.DynamoDbRunning;
import org.springframework.integration.test.util.TestUtils;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
import com.amazonaws.waiters.FixedDelayStrategy;
import com.amazonaws.waiters.MaxAttemptsRetryStrategy;
import com.amazonaws.waiters.PollingStrategy;
import com.amazonaws.waiters.Waiter;
import com.amazonaws.waiters.WaiterParameters;
/**
* @author Artem Bilan
*
* @since 1.1
*
*/
public class DynamoDbMetadataStoreTests {
@ClassRule
public static final DynamoDbRunning DYNAMO_DB_RUNNING = DynamoDbRunning.isRunning(4567);
private static final String TEST_TABLE = "testMetadataStore";
private static DynamoDbMetaDataStore store;
private final String file1 = "/remotepath/filesTodownload/file-1.txt";
private final String file1Id = "12345";
@BeforeClass
public static void setup() throws Exception {
AmazonDynamoDBAsync dynamoDB = DYNAMO_DB_RUNNING.getDynamoDB();
try {
dynamoDB.deleteTableAsync(TEST_TABLE);
Waiter<DescribeTableRequest> waiter =
dynamoDB.waiters()
.tableNotExists();
waiter.run(new WaiterParameters<>(new DescribeTableRequest(TEST_TABLE))
.withPollingStrategy(new PollingStrategy(new MaxAttemptsRetryStrategy(25),
new FixedDelayStrategy(1))));
}
catch (Exception e) {
}
store = new DynamoDbMetaDataStore(dynamoDB, TEST_TABLE);
store.afterPropertiesSet();
}
@Before
public void clear() throws InterruptedException {
CountDownLatch createTableLatch = TestUtils.getPropertyValue(store, "createTableLatch", CountDownLatch.class);
createTableLatch.await();
DYNAMO_DB_RUNNING.getDynamoDB()
.deleteItem(TEST_TABLE,
Collections.singletonMap("KEY",
new AttributeValue()
.withS(this.file1)));
}
@Test
public void testGetFromStore() {
String fileID = store.get(this.file1);
assertThat(fileID).isNull();
store.put(this.file1, this.file1Id);
fileID = store.get(this.file1);
assertThat(fileID).isNotNull();
assertThat(fileID).isEqualTo(this.file1Id);
}
@Test
public void testPutIfAbsent() throws Exception {
String fileID = store.get(file1);
assertThat(fileID).describedAs("Get First time, Value must not exist").isNull();
fileID = store.putIfAbsent(file1, file1Id);
assertThat(fileID).describedAs("Insert First time, Value must return null").isNull();
fileID = store.putIfAbsent(file1, "56789");
assertThat(fileID).describedAs("Key Already Exists - Insertion Failed, ol value must be returned").isNotNull();
assertThat(fileID).describedAs("The Old Value must be equal to returned").isEqualTo(this.file1Id);
assertThat(store.get(this.file1)).describedAs("The Old Value must return").isEqualTo(this.file1Id);
}
@Test
public void testRemove() throws Exception {
String fileID = store.remove(this.file1);
assertThat(fileID).isNull();
fileID = store.putIfAbsent(this.file1, this.file1Id);
assertThat(fileID).isNull();
fileID = store.remove(this.file1);
assertThat(fileID).isNotNull();
assertThat(fileID).isEqualTo(this.file1Id);
fileID = store.get(this.file1);
assertThat(fileID).isNull();
}
@Test
public void testReplace() throws Exception {
boolean removedValue = store.replace(file1, file1Id, "4567");
assertThat(removedValue).isFalse();
String fileID = store.get(this.file1);
assertThat(fileID).isNull();
fileID = store.putIfAbsent(this.file1, file1Id);
assertThat(fileID).isNull();
removedValue = store.replace(this.file1, file1Id, "4567");
assertThat(removedValue).isTrue();
fileID = store.get(this.file1);
assertThat(fileID).isNotNull();
assertThat(fileID).isEqualTo("4567");
}
}