From 3db0453417709b8444cd31eb31c42223ab00ec69 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 21 Oct 2019 13:52:58 -0400 Subject: [PATCH] Rely on EVN variable for Docker host name * Introduce `EnvironmentHostNameResolver` to resolve Docker host name from the environment variable * Make Local Stack tests conditional based on the ENV variable mentioned above * Disable `KinesisIntegrationTests` because of `502 Bad Gateway` for Kinesis service in Local Stack * Disable `DynamoDbLockRegistryLeaderInitiatorTests.testDistributedLeaderElection()` - looks like two instances cannot interaction with table in Local Stack concurrently properly * Fix `DynamoDbLockRegistry` to catch and ignore `ResourceInUseException` instead of re-throwing it without a reason * Remove `junit-vintage-engine` - no JUnit 4 tests any more --- build.gradle | 5 +-- .../aws/lock/DynamoDbLockRegistry.java | 8 +++- .../aws/EnvironmentHostNameResolver.java | 35 +++++++++++++++ .../aws/kinesis/KinesisIntegrationTests.java | 13 +++--- ...amoDbLockRegistryLeaderInitiatorTests.java | 16 ++++--- .../aws/lock/DynamoDbLockRegistryTests.java | 12 ++--- .../metadata/DynamoDbMetadataStoreTests.java | 44 +++++++++++-------- 7 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 src/test/java/org/springframework/integration/aws/EnvironmentHostNameResolver.java diff --git a/build.gradle b/build.gradle index 32091bd..775eb95 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ dependencies { compile("javax.servlet:javax.servlet-api:$servletApiVersion", provided) testCompile ('org.springframework.integration:spring-integration-test') { -// exclude group: 'junit' + exclude group: 'junit' } testCompile "org.assertj:assertj-core:$assertjVersion" @@ -125,9 +125,6 @@ dependencies { testRuntime "org.apache.logging.log4j:log4j-jcl:$log4jVersion" testRuntime 'org.junit.jupiter:junit-jupiter-engine' testRuntime 'org.junit.platform:junit-platform-launcher' - - // To support JUnit 4 tests - testRuntime 'org.junit.vintage:junit-vintage-engine' } eclipse.project.natures += 'org.springframework.ide.eclipse.core.springnature' diff --git a/src/main/java/org/springframework/integration/aws/lock/DynamoDbLockRegistry.java b/src/main/java/org/springframework/integration/aws/lock/DynamoDbLockRegistry.java index 703313a..e18dcf1 100644 --- a/src/main/java/org/springframework/integration/aws/lock/DynamoDbLockRegistry.java +++ b/src/main/java/org/springframework/integration/aws/lock/DynamoDbLockRegistry.java @@ -52,6 +52,7 @@ import com.amazonaws.services.dynamodbv2.CreateDynamoDBTableOptions; import com.amazonaws.services.dynamodbv2.LockItem; import com.amazonaws.services.dynamodbv2.model.LockTableDoesNotExistException; import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; +import com.amazonaws.services.dynamodbv2.model.ResourceInUseException; /** * An {@link ExpirableLockRegistry} implementation for the AWS DynamoDB. The algorithm is @@ -244,7 +245,12 @@ public class DynamoDbLockRegistry implements ExpirableLockRegistry, Initializing this.tableName) .withPartitionKeyName(this.partitionKey).withSortKeyName(this.sortKeyName).build(); - AmazonDynamoDBLockClient.createLockTableInDynamoDB(createDynamoDBTableOptions); + try { + AmazonDynamoDBLockClient.createLockTableInDynamoDB(createDynamoDBTableOptions); + } + catch (ResourceInUseException ex) { + // Swallow an exception and check for table existence + } } int i = 0; diff --git a/src/test/java/org/springframework/integration/aws/EnvironmentHostNameResolver.java b/src/test/java/org/springframework/integration/aws/EnvironmentHostNameResolver.java new file mode 100644 index 0000000..b26b1d2 --- /dev/null +++ b/src/test/java/org/springframework/integration/aws/EnvironmentHostNameResolver.java @@ -0,0 +1,35 @@ +/* + * Copyright 2019 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 + * + * https://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 cloud.localstack.docker.annotation.IHostNameResolver; + +/** + * @author Artem Bilan + * + * @since 2.3 + */ +public class EnvironmentHostNameResolver implements IHostNameResolver { + + public static final String DOCKER_HOST_NAME = "DOCKER_HOST_NAME"; + + @Override + public String getHostName() { + return System.getenv(DOCKER_HOST_NAME); + } + +} diff --git a/src/test/java/org/springframework/integration/aws/kinesis/KinesisIntegrationTests.java b/src/test/java/org/springframework/integration/aws/kinesis/KinesisIntegrationTests.java index a9975d1..e56684a 100644 --- a/src/test/java/org/springframework/integration/aws/kinesis/KinesisIntegrationTests.java +++ b/src/test/java/org/springframework/integration/aws/kinesis/KinesisIntegrationTests.java @@ -27,8 +27,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.DirectFieldAccessor; @@ -37,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.aws.EnvironmentHostNameResolver; import org.springframework.integration.aws.ExtendedDockerTestUtils; import org.springframework.integration.aws.inbound.kinesis.KinesisMessageDrivenChannelAdapter; import org.springframework.integration.aws.inbound.kinesis.KinesisMessageHeaderErrorMessageStrategy; @@ -65,13 +65,16 @@ import com.amazonaws.services.kinesis.AmazonKinesisAsync; /** * @author Artem Bilan + * * @since 1.1 */ -@Disabled -@DisabledOnOs(OS.WINDOWS) +@Disabled("Looks like Kinesis is not supported well in Local Stack") @SpringJUnitConfig +@EnabledIfEnvironmentVariable(named = EnvironmentHostNameResolver.DOCKER_HOST_NAME, matches = ".+") @ExtendWith(LocalstackDockerExtension.class) -@LocalstackDockerProperties(randomizePorts = true, services = "kinesis") +@LocalstackDockerProperties(randomizePorts = true, + hostNameResolver = EnvironmentHostNameResolver.class, + services = "kinesis") @DirtiesContext public class KinesisIntegrationTests { diff --git a/src/test/java/org/springframework/integration/aws/leader/DynamoDbLockRegistryLeaderInitiatorTests.java b/src/test/java/org/springframework/integration/aws/leader/DynamoDbLockRegistryLeaderInitiatorTests.java index 731f2bf..c1da07a 100644 --- a/src/test/java/org/springframework/integration/aws/leader/DynamoDbLockRegistryLeaderInitiatorTests.java +++ b/src/test/java/org/springframework/integration/aws/leader/DynamoDbLockRegistryLeaderInitiatorTests.java @@ -18,6 +18,7 @@ package org.springframework.integration.aws.leader; import static org.assertj.core.api.Assertions.assertThat; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -28,10 +29,10 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.integration.aws.EnvironmentHostNameResolver; import org.springframework.integration.aws.ExtendedDockerTestUtils; import org.springframework.integration.aws.lock.DynamoDbLockRegistry; import org.springframework.integration.leader.Context; @@ -39,6 +40,7 @@ import org.springframework.integration.leader.DefaultCandidate; import org.springframework.integration.leader.event.LeaderEventPublisher; import org.springframework.integration.support.leader.LockRegistryLeaderInitiator; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; +import org.springframework.util.ReflectionUtils; import cloud.localstack.docker.LocalstackDockerExtension; import cloud.localstack.docker.annotation.LocalstackDockerProperties; @@ -55,10 +57,11 @@ import com.amazonaws.waiters.WaiterParameters; * * @since 2.0 */ -@Disabled -@DisabledOnOs(OS.WINDOWS) +@EnabledIfEnvironmentVariable(named = EnvironmentHostNameResolver.DOCKER_HOST_NAME, matches = ".+") @ExtendWith(LocalstackDockerExtension.class) -@LocalstackDockerProperties(randomizePorts = true, services = "dynamodb") +@LocalstackDockerProperties(randomizePorts = true, + hostNameResolver = EnvironmentHostNameResolver.class, + services = "dynamodb") class DynamoDbLockRegistryLeaderInitiatorTests { private static AmazonDynamoDBAsync DYNAMO_DB; @@ -86,6 +89,7 @@ class DynamoDbLockRegistryLeaderInitiatorTests { DYNAMO_DB.deleteTable(DynamoDbLockRegistry.DEFAULT_TABLE_NAME); } + @Disabled("Doesn't work properly against Local Stack when two instances try to lock in table") @Test void testDistributedLeaderElection() throws Exception { CountDownLatch granted = new CountDownLatch(1); @@ -140,7 +144,7 @@ class DynamoDbLockRegistryLeaderInitiatorTests { // It's hard to see round-robin election, so let's make the yielding initiator to // sleep long before restarting - initiator1.setBusyWaitMillis(1000); + initiator1.setBusyWaitMillis(10000); initiator1.getContext().yield(); diff --git a/src/test/java/org/springframework/integration/aws/lock/DynamoDbLockRegistryTests.java b/src/test/java/org/springframework/integration/aws/lock/DynamoDbLockRegistryTests.java index 6ed23ea..d26313f 100644 --- a/src/test/java/org/springframework/integration/aws/lock/DynamoDbLockRegistryTests.java +++ b/src/test/java/org/springframework/integration/aws/lock/DynamoDbLockRegistryTests.java @@ -27,10 +27,8 @@ import java.util.concurrent.locks.Lock; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnOs; -import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +36,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.core.task.SimpleAsyncTaskExecutor; +import org.springframework.integration.aws.EnvironmentHostNameResolver; import org.springframework.integration.aws.ExtendedDockerTestUtils; import org.springframework.integration.test.util.TestUtils; import org.springframework.test.annotation.DirtiesContext; @@ -58,11 +57,12 @@ import com.amazonaws.waiters.WaiterParameters; * * @since 2.0 */ -@Disabled -@DisabledOnOs(OS.WINDOWS) @SpringJUnitConfig +@EnabledIfEnvironmentVariable(named = EnvironmentHostNameResolver.DOCKER_HOST_NAME, matches = ".+") @ExtendWith(LocalstackDockerExtension.class) -@LocalstackDockerProperties(randomizePorts = true, services = "dynamodb") +@LocalstackDockerProperties(randomizePorts = true, + hostNameResolver = EnvironmentHostNameResolver.class, + services = "dynamodb") @DirtiesContext public class DynamoDbLockRegistryTests { diff --git a/src/test/java/org/springframework/integration/aws/metadata/DynamoDbMetadataStoreTests.java b/src/test/java/org/springframework/integration/aws/metadata/DynamoDbMetadataStoreTests.java index 8c0eb16..7acf710 100644 --- a/src/test/java/org/springframework/integration/aws/metadata/DynamoDbMetadataStoreTests.java +++ b/src/test/java/org/springframework/integration/aws/metadata/DynamoDbMetadataStoreTests.java @@ -21,15 +21,17 @@ 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.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.integration.aws.EnvironmentHostNameResolver; import org.springframework.integration.aws.ExtendedDockerTestUtils; import org.springframework.integration.test.util.TestUtils; -import cloud.localstack.docker.LocalstackDockerTestRunner; +import cloud.localstack.docker.LocalstackDockerExtension; import cloud.localstack.docker.annotation.LocalstackDockerProperties; import com.amazonaws.services.dynamodbv2.AmazonDynamoDBAsync; import com.amazonaws.services.dynamodbv2.model.AttributeValue; @@ -45,10 +47,12 @@ import com.amazonaws.waiters.WaiterParameters; * * @since 1.1 */ -//@DisabledOnOs(OS.WINDOWS) -@RunWith(LocalstackDockerTestRunner.class) -@LocalstackDockerProperties(services = "dynamodb") -public class DynamoDbMetadataStoreTests { +@EnabledIfEnvironmentVariable(named = EnvironmentHostNameResolver.DOCKER_HOST_NAME, matches = ".+") +@ExtendWith(LocalstackDockerExtension.class) +@LocalstackDockerProperties(randomizePorts = true, + hostNameResolver = EnvironmentHostNameResolver.class, + services = "dynamodb") +class DynamoDbMetadataStoreTests { private static AmazonDynamoDBAsync DYNAMO_DB; @@ -60,8 +64,8 @@ public class DynamoDbMetadataStoreTests { private final String file1Id = "12345"; - @BeforeClass - public static void setup() { + @BeforeAll + static void setup() { DYNAMO_DB = ExtendedDockerTestUtils.getClientDynamoDbAsync(); try { @@ -69,8 +73,10 @@ public class DynamoDbMetadataStoreTests { Waiter waiter = DYNAMO_DB.waiters().tableNotExists(); - waiter.run(new WaiterParameters<>(new DescribeTableRequest(TEST_TABLE)).withPollingStrategy( - new PollingStrategy(new MaxAttemptsRetryStrategy(25), new FixedDelayStrategy(1)))); + waiter.run(new WaiterParameters<>(new DescribeTableRequest(TEST_TABLE)) + .withPollingStrategy( + new PollingStrategy(new MaxAttemptsRetryStrategy(25), + new FixedDelayStrategy(1)))); } catch (Exception e) { // Ignore @@ -81,8 +87,8 @@ public class DynamoDbMetadataStoreTests { store.afterPropertiesSet(); } - @Before - public void clear() throws InterruptedException { + @BeforeEach + void clear() throws InterruptedException { CountDownLatch createTableLatch = TestUtils.getPropertyValue(store, "createTableLatch", CountDownLatch.class); createTableLatch.await(); @@ -91,7 +97,7 @@ public class DynamoDbMetadataStoreTests { } @Test - public void testGetFromStore() { + void testGetFromStore() { String fileID = store.get(this.file1); assertThat(fileID).isNull(); @@ -103,7 +109,7 @@ public class DynamoDbMetadataStoreTests { } @Test - public void testPutIfAbsent() { + void testPutIfAbsent() { String fileID = store.get(this.file1); assertThat(fileID).describedAs("Get First time, Value must not exist").isNull(); @@ -118,7 +124,7 @@ public class DynamoDbMetadataStoreTests { } @Test - public void testRemove() { + void testRemove() { String fileID = store.remove(this.file1); assertThat(fileID).isNull(); @@ -134,7 +140,7 @@ public class DynamoDbMetadataStoreTests { } @Test - public void testReplace() { + void testReplace() { boolean removedValue = store.replace(this.file1, this.file1Id, "4567"); assertThat(removedValue).isFalse();