Split DeploymentIntegrationTests by container

Prior to this commit, every test started a new testcontainer. By splitting the
tests apart we can make use of static containers that are only instantiated once
per application (TomEE, Wildfly etc.)

See gh-25446
pull/25486/head
dreis2211 4 years ago committed by Andy Wilkinson
parent d55d8d6b19
commit 4ff9e5edaa

@ -23,6 +23,7 @@ dependencies {
intTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) intTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
intTestImplementation("org.apache.httpcomponents:httpasyncclient") intTestImplementation("org.apache.httpcomponents:httpasyncclient")
intTestImplementation("org.awaitility:awaitility") intTestImplementation("org.awaitility:awaitility")
intTestImplementation("org.testcontainers:junit-jupiter")
intTestImplementation("org.testcontainers:testcontainers") intTestImplementation("org.testcontainers:testcontainers")
intTestImplementation("org.springframework:spring-web") intTestImplementation("org.springframework:spring-web")

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2020 the original author or authors. * Copyright 2012-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,21 +18,17 @@ package sample;
import java.io.File; import java.io.File;
import java.time.Duration; import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler; import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.awaitility.Awaitility; import org.awaitility.Awaitility;
import org.awaitility.core.ConditionTimeoutException; import org.awaitility.core.ConditionTimeoutException;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.ImageFromDockerfile; import org.testcontainers.images.builder.ImageFromDockerfile;
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.testsupport.testcontainers.DisabledIfDockerUnavailable;
import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -41,102 +37,88 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Deployment integration tests. * Abstract class for deployment integration tests.
*/ */
@DisabledIfDockerUnavailable abstract class AbstractDeploymentIntegrationTests {
class AbstractDeploymentIntegrationTests {
@ParameterizedTest protected static final int DEFAULT_PORT = 8080;
@MethodSource("deployedApplications")
void home(DeployedApplication app) { @Test
app.test((rest) -> { void home() {
getDeployedApplication().test((rest) -> {
ResponseEntity<String> response = rest.getForEntity("/", String.class); ResponseEntity<String> response = rest.getForEntity("/", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("Hello World"); assertThat(response.getBody()).isEqualTo("Hello World");
}); });
} }
@ParameterizedTest @Test
@MethodSource("deployedApplications") void health() {
void health(DeployedApplication application) { getDeployedApplication().test((rest) -> {
application.test((rest) -> {
ResponseEntity<String> response = rest.getForEntity("/actuator/health", String.class); ResponseEntity<String> response = rest.getForEntity("/actuator/health", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"status\":\"UP\"}"); assertThat(response.getBody()).isEqualTo("{\"status\":\"UP\"}");
}); });
} }
@ParameterizedTest @Test
@MethodSource("deployedApplications") void conditionalOnWarShouldBeTrue() {
void conditionalOnWarShouldBeTrue(DeployedApplication application) throws Exception { getDeployedApplication().test((rest) -> {
application.test((rest) -> {
ResponseEntity<String> response = rest.getForEntity("/actuator/war", String.class); ResponseEntity<String> response = rest.getForEntity("/actuator/war", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isEqualTo("{\"hello\":\"world\"}"); assertThat(response.getBody()).isEqualTo("{\"hello\":\"world\"}");
}); });
} }
static List<DeployedApplication> deployedApplications() { private DeployedApplication getDeployedApplication() {
return Arrays.asList( return new DeployedApplication(getContainer(), getPort());
new DeployedApplication("openliberty/open-liberty:20.0.0.9-kernel-java8-openj9-ubi", "/config/dropins", }
9080),
new DeployedApplication("tomcat:9.0.37-jdk8-openjdk", "/usr/local/tomcat/webapps", 8080), protected int getPort() {
new DeployedApplication("tomee:8-jre-8.0.2-webprofile", "/usr/local/tomee/webapps", 8080), return DEFAULT_PORT;
new DeployedApplication("jboss/wildfly:20.0.1.Final", "/opt/jboss/wildfly/standalone/deployments",
8080));
} }
public static final class DeployedApplication { abstract WarDeploymentContainer getContainer();
private final String baseImage; static final class DeployedApplication {
private final String deploymentLocation; private final WarDeploymentContainer container;
private final int port; private final int port;
private DeployedApplication(String baseImage, String deploymentLocation, int port) { DeployedApplication(WarDeploymentContainer container, int port) {
this.baseImage = baseImage; this.container = container;
this.deploymentLocation = deploymentLocation;
this.port = port; this.port = port;
} }
private void test(Consumer<TestRestTemplate> consumer) { private void test(Consumer<TestRestTemplate> consumer) {
try (WarDeploymentContainer container = new WarDeploymentContainer(this.baseImage, this.deploymentLocation, TestRestTemplate rest = new TestRestTemplate(new RestTemplateBuilder()
this.port)) { .rootUri("http://" + this.container.getHost() + ":" + this.container.getMappedPort(this.port)
container.start(); + "/spring-boot")
TestRestTemplate rest = new TestRestTemplate(new RestTemplateBuilder() .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom()
.rootUri("http://" + container.getHost() + ":" + container.getMappedPort(this.port) .setRetryHandler(new StandardHttpRequestRetryHandler(10, false)).build())));
+ "/spring-boot") try {
.requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom() Awaitility.await().atMost(Duration.ofMinutes(10)).until(() -> {
.setRetryHandler(new StandardHttpRequestRetryHandler(10, false)).build()))); try {
try { consumer.accept(rest);
Awaitility.await().atMost(Duration.ofMinutes(10)).until(() -> { return true;
try { }
consumer.accept(rest); catch (Throwable ex) {
return true; return false;
} }
catch (Throwable ex) { });
return false; }
} catch (ConditionTimeoutException ex) {
}); System.out.println(this.container.getLogs());
} throw ex;
catch (ConditionTimeoutException ex) {
System.out.println(container.getLogs());
throw ex;
}
} }
}
@Override
public String toString() {
return this.baseImage;
} }
} }
private static final class WarDeploymentContainer extends GenericContainer<WarDeploymentContainer> { static final class WarDeploymentContainer extends GenericContainer<WarDeploymentContainer> {
private WarDeploymentContainer(String baseImage, String deploymentLocation, int port) { WarDeploymentContainer(String baseImage, String deploymentLocation, int port) {
super(new ImageFromDockerfile().withFileFromFile("spring-boot.war", findWarToDeploy()) super(new ImageFromDockerfile().withFileFromFile("spring-boot.war", findWarToDeploy())
.withDockerfileFromBuilder((builder) -> builder.from(baseImage) .withDockerfileFromBuilder((builder) -> builder.from(baseImage)
.add("spring-boot.war", deploymentLocation + "/spring-boot.war").build())); .add("spring-boot.war", deploymentLocation + "/spring-boot.war").build()));

@ -0,0 +1,46 @@
/*
* Copyright 2012-2021 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 sample;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Deployment integration tests for Open Liberty.
*
* @author Christoph Dreis
*/
@Testcontainers(disabledWithoutDocker = true)
class OpenLibertyDeploymentIntegrationTests extends AbstractDeploymentIntegrationTests {
private static final int PORT = 9080;
@Container
static WarDeploymentContainer container = new WarDeploymentContainer(
"openliberty/open-liberty:20.0.0.9-kernel-java8-openj9-ubi", "/config/dropins", PORT);
@Override
WarDeploymentContainer getContainer() {
return container;
}
@Override
protected int getPort() {
return PORT;
}
}

@ -0,0 +1,39 @@
/*
* Copyright 2012-2021 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 sample;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Deployment integration tests for TomEE.
*
* @author Christoph Dreis
*/
@Testcontainers(disabledWithoutDocker = true)
public class TomEEDeploymentIntegrationTests extends AbstractDeploymentIntegrationTests {
@Container
static WarDeploymentContainer container = new WarDeploymentContainer("tomee:8-jre-8.0.2-webprofile",
"/usr/local/tomee/webapps", DEFAULT_PORT);
@Override
WarDeploymentContainer getContainer() {
return container;
}
}

@ -0,0 +1,39 @@
/*
* Copyright 2012-2021 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 sample;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Deployment integration tests for Tomcat.
*
* @author Christoph Dreis
*/
@Testcontainers(disabledWithoutDocker = true)
public class TomcatDeploymentIntegrationTests extends AbstractDeploymentIntegrationTests {
@Container
static WarDeploymentContainer container = new WarDeploymentContainer("tomcat:9.0.37-jdk8-openjdk",
"/usr/local/tomcat/webapps", DEFAULT_PORT);
@Override
WarDeploymentContainer getContainer() {
return container;
}
}

@ -0,0 +1,39 @@
/*
* Copyright 2012-2021 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 sample;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Deployment integration tests for Wildfly.
*
* @author Christoph Dreis
*/
@Testcontainers(disabledWithoutDocker = true)
public class WildflyDeploymentIntegrationTests extends AbstractDeploymentIntegrationTests {
@Container
static WarDeploymentContainer container = new WarDeploymentContainer("jboss/wildfly:20.0.1.Final",
"/opt/jboss/wildfly/standalone/deployments", DEFAULT_PORT);
@Override
WarDeploymentContainer getContainer() {
return container;
}
}
Loading…
Cancel
Save