From 04b6b9eabf90b96b43b54a61eef3fe2f57091008 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Thu, 19 May 2022 11:34:10 -0400 Subject: [PATCH] Really reuse Testcontainers The `withReuse(true)` and `testcontainers.reuse.enable=true` don't work together with `@Container`. The JUnit extension gathers those containers and stop them in the end of test class unconditionally. * Remove `@Container` annotation usage * Use `@BeforeAll` and `GenericContainer.start()` manually This way the container ensures to reuse existing running container and don't start a fresh one. Since the container instance is stored in a `static` property, it is really started only once. The rest tests in a suite just reuse that existing container. Ryuk container will take care about their stopping and removal eventually after JVM exit. --- .../aws/LocalstackContainerTest.java | 24 ++++++++++++------- .../aws/kinesis/KplKclIntegrationTests.java | 10 ++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/test/java/org/springframework/integration/aws/LocalstackContainerTest.java b/src/test/java/org/springframework/integration/aws/LocalstackContainerTest.java index da763fb..1275c60 100644 --- a/src/test/java/org/springframework/integration/aws/LocalstackContainerTest.java +++ b/src/test/java/org/springframework/integration/aws/LocalstackContainerTest.java @@ -16,8 +16,8 @@ package org.springframework.integration.aws; +import org.junit.jupiter.api.BeforeAll; import org.testcontainers.containers.localstack.LocalStackContainer; -import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; @@ -30,6 +30,11 @@ import com.amazonaws.services.kinesis.AmazonKinesisAsync; import com.amazonaws.services.kinesis.AmazonKinesisAsyncClientBuilder; /** + * The base contract for JUnit tests based on the container for Localstack. + * The Testcontainers 'reuse' option must be disabled,so, Ryuk container is started + * and will clean all the containers up from this test suite after JVM exit. + * Since the Localstack container instance is shared via static property, it is going to be + * started only once per JVM, therefore the target Docker container is reused automatically. * * @author Artem Bilan * @@ -38,17 +43,18 @@ import com.amazonaws.services.kinesis.AmazonKinesisAsyncClientBuilder; @Testcontainers(disabledWithoutDocker = true) public interface LocalstackContainerTest { - @Container - LocalStackContainer localStack = + LocalStackContainer LOCAL_STACK_CONTAINER = new LocalStackContainer( - DockerImageName.parse("localstack/localstack:0.14.2") - .asCompatibleSubstituteFor("localstack/localstack")) + DockerImageName.parse("localstack/localstack:0.14.2")) .withServices( LocalStackContainer.Service.DYNAMODB, LocalStackContainer.Service.KINESIS, - LocalStackContainer.Service.CLOUDWATCH) - .withReuse(true); + LocalStackContainer.Service.CLOUDWATCH); + @BeforeAll + static void startContainer() { + LOCAL_STACK_CONTAINER.start(); + } static AmazonDynamoDBAsync dynamoDbClient() { return applyAwsClientOptions(AmazonDynamoDBAsyncClientBuilder.standard(), LocalStackContainer.Service.DYNAMODB); @@ -65,8 +71,8 @@ public interface LocalstackContainerTest { private static , T> T applyAwsClientOptions(B clientBuilder, LocalStackContainer.Service serviceToBuild) { - return clientBuilder.withEndpointConfiguration(localStack.getEndpointConfiguration(serviceToBuild)) - .withCredentials(localStack.getDefaultCredentialsProvider()) + return clientBuilder.withEndpointConfiguration(LOCAL_STACK_CONTAINER.getEndpointConfiguration(serviceToBuild)) + .withCredentials(LOCAL_STACK_CONTAINER.getDefaultCredentialsProvider()) .build(); } diff --git a/src/test/java/org/springframework/integration/aws/kinesis/KplKclIntegrationTests.java b/src/test/java/org/springframework/integration/aws/kinesis/KplKclIntegrationTests.java index 619426d..65d4a1d 100644 --- a/src/test/java/org/springframework/integration/aws/kinesis/KplKclIntegrationTests.java +++ b/src/test/java/org/springframework/integration/aws/kinesis/KplKclIntegrationTests.java @@ -147,13 +147,13 @@ public class KplKclIntegrationTests implements LocalstackContainerTest { @Bean public KinesisProducerConfiguration kinesisProducerConfiguration() throws URISyntaxException { URI kinesisUri = - LocalstackContainerTest.localStack.getEndpointOverride(LocalStackContainer.Service.KINESIS); + LocalstackContainerTest.LOCAL_STACK_CONTAINER.getEndpointOverride(LocalStackContainer.Service.KINESIS); URI cloudWatchUri = - LocalstackContainerTest.localStack.getEndpointOverride(LocalStackContainer.Service.CLOUDWATCH); + LocalstackContainerTest.LOCAL_STACK_CONTAINER.getEndpointOverride(LocalStackContainer.Service.CLOUDWATCH); return new KinesisProducerConfiguration() - .setCredentialsProvider(LocalstackContainerTest.localStack.getDefaultCredentialsProvider()) - .setRegion(LocalstackContainerTest.localStack.getRegion()) + .setCredentialsProvider(LocalstackContainerTest.LOCAL_STACK_CONTAINER.getDefaultCredentialsProvider()) + .setRegion(LocalstackContainerTest.LOCAL_STACK_CONTAINER.getRegion()) .setKinesisEndpoint(kinesisUri.getHost()) .setKinesisPort(kinesisUri.getPort()) .setCloudwatchEndpoint(cloudWatchUri.getHost()) @@ -176,7 +176,7 @@ public class KplKclIntegrationTests implements LocalstackContainerTest { KclMessageDrivenChannelAdapter adapter = new KclMessageDrivenChannelAdapter( TEST_STREAM, AMAZON_KINESIS, CLOUD_WATCH, DYNAMO_DB, - LocalstackContainerTest.localStack.getDefaultCredentialsProvider()); + LocalstackContainerTest.LOCAL_STACK_CONTAINER.getDefaultCredentialsProvider()); adapter.setOutputChannel(kinesisReceiveChannel()); adapter.setErrorChannel(errorChannel()); adapter.setErrorMessageStrategy(new KinesisMessageHeaderErrorMessageStrategy());