diff --git a/spring-boot-tests/spring-boot-deployment-tests/build.gradle b/spring-boot-tests/spring-boot-deployment-tests/build.gradle index 738f63fcd1..150b8dc29e 100644 --- a/spring-boot-tests/spring-boot-deployment-tests/build.gradle +++ b/spring-boot-tests/spring-boot-deployment-tests/build.gradle @@ -23,6 +23,7 @@ dependencies { intTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) intTestImplementation("org.apache.httpcomponents:httpasyncclient") intTestImplementation("org.awaitility:awaitility") + intTestImplementation("org.testcontainers:junit-jupiter") intTestImplementation("org.testcontainers:testcontainers") intTestImplementation("org.springframework:spring-web") diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/AbstractDeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/AbstractDeploymentIntegrationTests.java new file mode 100644 index 0000000000..d731fdd805 --- /dev/null +++ b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/AbstractDeploymentIntegrationTests.java @@ -0,0 +1,136 @@ +/* + * 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 java.io.File; +import java.time.Duration; +import java.util.function.Consumer; + +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.StandardHttpRequestRetryHandler; +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionTimeoutException; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.images.builder.ImageFromDockerfile; + +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Abstract class for deployment integration tests. + */ +abstract class AbstractDeploymentIntegrationTests { + + protected static final int DEFAULT_PORT = 8080; + + @Test + void home() { + getDeployedApplication().test((rest) -> { + ResponseEntity response = rest.getForEntity("/", String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo("Hello World"); + }); + } + + @Test + void health() { + getDeployedApplication().test((rest) -> { + ResponseEntity response = rest.getForEntity("/actuator/health", String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo("{\"status\":\"UP\"}"); + }); + } + + @Test + void conditionalOnWarShouldBeTrue() { + getDeployedApplication().test((rest) -> { + ResponseEntity response = rest.getForEntity("/actuator/war", String.class); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo("{\"hello\":\"world\"}"); + }); + } + + private DeployedApplication getDeployedApplication() { + return new DeployedApplication(getContainer(), getPort()); + } + + protected int getPort() { + return DEFAULT_PORT; + } + + abstract WarDeploymentContainer getContainer(); + + static final class DeployedApplication { + + private final WarDeploymentContainer container; + + private final int port; + + DeployedApplication(WarDeploymentContainer container, int port) { + this.container = container; + this.port = port; + } + + private void test(Consumer consumer) { + TestRestTemplate rest = new TestRestTemplate(new RestTemplateBuilder() + .rootUri("http://" + this.container.getHost() + ":" + this.container.getMappedPort(this.port) + + "/spring-boot") + .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom() + .setRetryHandler(new StandardHttpRequestRetryHandler(10, false)).build()))); + try { + Awaitility.await().atMost(Duration.ofMinutes(10)).until(() -> { + try { + consumer.accept(rest); + return true; + } + catch (Throwable ex) { + return false; + } + }); + } + catch (ConditionTimeoutException ex) { + System.out.println(this.container.getLogs()); + throw ex; + } + } + + } + + static final class WarDeploymentContainer extends GenericContainer { + + WarDeploymentContainer(String baseImage, String deploymentLocation, int port) { + super(new ImageFromDockerfile().withFileFromFile("spring-boot.war", findWarToDeploy()) + .withDockerfileFromBuilder((builder) -> builder.from(baseImage) + .add("spring-boot.war", deploymentLocation + "/spring-boot.war").build())); + withExposedPorts(port).withStartupTimeout(Duration.ofMinutes(5)).withStartupAttempts(3); + } + + private static File findWarToDeploy() { + File[] candidates = new File("build/libs").listFiles(); + assertThat(candidates).hasSize(1); + return candidates[0]; + } + + } + +} diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/DeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/DeploymentIntegrationTests.java deleted file mode 100644 index d363e3ee71..0000000000 --- a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/DeploymentIntegrationTests.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2012-2020 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 java.io.File; -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.function.Consumer; - -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.client.StandardHttpRequestRetryHandler; -import org.awaitility.Awaitility; -import org.awaitility.core.ConditionTimeoutException; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.images.builder.ImageFromDockerfile; - -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.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Deployment integration tests. - */ -@DisabledIfDockerUnavailable -class DeploymentIntegrationTests { - - @ParameterizedTest - @MethodSource("deployedApplications") - void home(DeployedApplication app) { - app.test((rest) -> { - ResponseEntity response = rest.getForEntity("/", String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("Hello World"); - }); - } - - @ParameterizedTest - @MethodSource("deployedApplications") - void health(DeployedApplication application) { - application.test((rest) -> { - ResponseEntity response = rest.getForEntity("/actuator/health", String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"status\":\"UP\"}"); - }); - } - - @ParameterizedTest - @MethodSource("deployedApplications") - void conditionalOnWarShouldBeTrue(DeployedApplication application) throws Exception { - application.test((rest) -> { - ResponseEntity response = rest.getForEntity("/actuator/war", String.class); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("{\"hello\":\"world\"}"); - }); - } - - static List deployedApplications() { - return Arrays.asList( - 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), - new DeployedApplication("tomee:8-jre-8.0.2-webprofile", "/usr/local/tomee/webapps", 8080), - new DeployedApplication("jboss/wildfly:20.0.1.Final", "/opt/jboss/wildfly/standalone/deployments", - 8080)); - } - - public static final class DeployedApplication { - - private final String baseImage; - - private final String deploymentLocation; - - private final int port; - - private DeployedApplication(String baseImage, String deploymentLocation, int port) { - this.baseImage = baseImage; - this.deploymentLocation = deploymentLocation; - this.port = port; - } - - private void test(Consumer consumer) { - try (WarDeploymentContainer container = new WarDeploymentContainer(this.baseImage, this.deploymentLocation, - this.port)) { - container.start(); - TestRestTemplate rest = new TestRestTemplate(new RestTemplateBuilder() - .rootUri("http://" + container.getHost() + ":" + container.getMappedPort(this.port) - + "/spring-boot") - .requestFactory(() -> new HttpComponentsClientHttpRequestFactory(HttpClients.custom() - .setRetryHandler(new StandardHttpRequestRetryHandler(10, false)).build()))); - try { - Awaitility.await().atMost(Duration.ofMinutes(10)).until(() -> { - try { - consumer.accept(rest); - return true; - } - catch (Throwable ex) { - return false; - } - }); - } - catch (ConditionTimeoutException ex) { - System.out.println(container.getLogs()); - throw ex; - } - } - } - - @Override - public String toString() { - return this.baseImage; - } - - } - - private static final class WarDeploymentContainer extends GenericContainer { - - private WarDeploymentContainer(String baseImage, String deploymentLocation, int port) { - super(new ImageFromDockerfile().withFileFromFile("spring-boot.war", findWarToDeploy()) - .withDockerfileFromBuilder((builder) -> builder.from(baseImage) - .add("spring-boot.war", deploymentLocation + "/spring-boot.war").build())); - withExposedPorts(port).withStartupTimeout(Duration.ofMinutes(5)).withStartupAttempts(3); - } - - private static File findWarToDeploy() { - File[] candidates = new File("build/libs").listFiles(); - assertThat(candidates).hasSize(1); - return candidates[0]; - } - - } - -} diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/OpenLibertyDeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/OpenLibertyDeploymentIntegrationTests.java new file mode 100644 index 0000000000..3339236074 --- /dev/null +++ b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/OpenLibertyDeploymentIntegrationTests.java @@ -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; + } + +} diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomEEDeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomEEDeploymentIntegrationTests.java new file mode 100644 index 0000000000..f96aaa96a5 --- /dev/null +++ b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomEEDeploymentIntegrationTests.java @@ -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; + } + +} diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomcatDeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomcatDeploymentIntegrationTests.java new file mode 100644 index 0000000000..3957d44a2b --- /dev/null +++ b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/TomcatDeploymentIntegrationTests.java @@ -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; + } + +} diff --git a/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/WildflyDeploymentIntegrationTests.java b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/WildflyDeploymentIntegrationTests.java new file mode 100644 index 0000000000..1f8daebc4a --- /dev/null +++ b/spring-boot-tests/spring-boot-deployment-tests/src/intTest/java/sample/WildflyDeploymentIntegrationTests.java @@ -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; + } + +}