Merge branch '2.2.x'

Closes gh-19416
pull/19423/head
Andy Wilkinson 5 years ago
commit eeeeaa5edb

@ -30,9 +30,8 @@
<artifactId>spring-boot-starter-undertow</artifactId> <artifactId>spring-boot-starter-undertow</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.docker-java</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>docker-java</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<version>3.1.2</version>
<scope>test</scope> <scope>test</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
@ -54,9 +53,23 @@
<artifactId>jakarta.ws.rs-api</artifactId> <artifactId>jakarta.ws.rs-api</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.testcontainers</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>testcontainers</artifactId>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
<exclusion>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
<profiles> <profiles>

@ -24,7 +24,7 @@ public class LaunchVerificationController {
@RequestMapping("/") @RequestMapping("/")
public String verifyLaunch() { public String verifyLaunch() {
return "Launched"; return "Launched\n";
} }
} }

@ -17,38 +17,19 @@
package org.springframework.boot.launchscript; package org.springframework.boot.launchscript;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.time.Duration;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.DockerCmd;
import com.github.dockerjava.api.exception.DockerClientException;
import com.github.dockerjava.api.model.BuildResponseItem;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.core.command.AttachContainerResultCallback;
import com.github.dockerjava.core.command.BuildImageResultCallback;
import com.github.dockerjava.core.command.WaitContainerResultCallback;
import com.github.dockerjava.core.util.CompressArchiveUtil;
import com.github.dockerjava.jaxrs.AbstrSyncDockerCmdExec;
import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory;
import org.assertj.core.api.Condition; import org.assertj.core.api.Condition;
import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.ToStringConsumer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import org.testcontainers.utility.MountableFile;
import org.springframework.boot.ansi.AnsiColor; import org.springframework.boot.ansi.AnsiColor;
@ -63,8 +44,6 @@ import static org.hamcrest.Matchers.containsString;
*/ */
class SysVinitLaunchScriptIT { class SysVinitLaunchScriptIT {
private final SpringBootDockerCmdExecFactory commandExecFactory = new SpringBootDockerCmdExecFactory();
private static final char ESC = 27; private static final char ESC = 27;
@ParameterizedTest(name = "{0} {1}") @ParameterizedTest(name = "{0} {1}")
@ -313,126 +292,15 @@ class SysVinitLaunchScriptIT {
} }
private String doTest(String os, String version, String script) throws Exception { private String doTest(String os, String version, String script) throws Exception {
DockerClient docker = createClient(); ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false);
String imageId = buildImage(os, version, docker); try (LaunchScriptTestContainer container = new LaunchScriptTestContainer(os, version, script)) {
String container = createContainer(docker, imageId, script); container.withLogConsumer(consumer);
try { container.start();
copyFilesToContainer(docker, container, script); while (container.isRunning()) {
docker.startContainerCmd(container).exec(); Thread.sleep(100);
StringBuilder output = new StringBuilder();
AttachContainerResultCallback resultCallback = docker.attachContainerCmd(container).withStdOut(true)
.withStdErr(true).withFollowStream(true).withLogs(true).exec(new AttachContainerResultCallback() {
@Override
public void onNext(Frame item) {
output.append(new String(item.getPayload()));
super.onNext(item);
}
});
resultCallback.awaitCompletion(60, TimeUnit.SECONDS);
WaitContainerResultCallback waitContainerCallback = new WaitContainerResultCallback();
docker.waitContainerCmd(container).exec(waitContainerCallback);
waitContainerCallback.awaitCompletion(60, TimeUnit.SECONDS);
return output.toString();
}
finally {
try {
docker.removeContainerCmd(container).exec();
}
catch (Exception ex) {
// Continue
} }
} }
} return consumer.toUtf8String();
private DockerClient createClient() {
DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().withApiVersion("1.19")
.build();
return DockerClientBuilder.getInstance(config).withDockerCmdExecFactory(this.commandExecFactory).build();
}
private String buildImage(String os, String version, DockerClient docker) {
String dockerfile = "src/test/resources/conf/" + os + "/" + version + "/Dockerfile";
String tag = "spring-boot-it/" + os.toLowerCase(Locale.ENGLISH) + ":" + version;
BuildImageResultCallback resultCallback = new BuildImageResultCallback() {
private List<BuildResponseItem> items = new ArrayList<>();
@Override
public void onNext(BuildResponseItem item) {
super.onNext(item);
this.items.add(item);
}
@Override
public String awaitImageId() {
try {
awaitCompletion();
}
catch (InterruptedException ex) {
throw new DockerClientException("Interrupted while waiting for image id", ex);
}
return getImageId();
}
@SuppressWarnings("deprecation")
private String getImageId() {
if (this.items.isEmpty()) {
throw new DockerClientException("Could not build image");
}
String imageId = extractImageId();
if (imageId == null) {
throw new DockerClientException(
"Could not build image: " + this.items.get(this.items.size() - 1).getError());
}
return imageId;
}
private String extractImageId() {
Collections.reverse(this.items);
for (BuildResponseItem item : this.items) {
if (item.isErrorIndicated() || item.getStream() == null) {
return null;
}
if (item.getStream().contains("Successfully built")) {
return item.getStream().replace("Successfully built", "").trim();
}
}
return null;
}
};
docker.buildImageCmd(new File(dockerfile)).withTags(new HashSet<>(Arrays.asList(tag))).exec(resultCallback);
String imageId = resultCallback.awaitImageId();
return imageId;
}
private String createContainer(DockerClient docker, String imageId, String testScript) {
return docker.createContainerCmd(imageId).withTty(false)
.withCmd("/bin/bash", "-c", "chmod +x " + testScript + " && ./" + testScript).exec().getId();
}
private void copyFilesToContainer(DockerClient docker, final String container, String script) {
copyToContainer(docker, container, findApplication());
copyToContainer(docker, container, new File("src/test/resources/scripts/test-functions.sh"));
copyToContainer(docker, container, new File("src/test/resources/scripts/" + script));
}
private void copyToContainer(DockerClient docker, final String container, final File file) {
this.commandExecFactory.createCopyToContainerCmdExec().exec(new CopyToContainerCmd(container, file));
}
private File findApplication() {
File targetDir = new File("target");
for (File file : targetDir.listFiles()) {
if (file.getName().startsWith("spring-boot-launch-script-tests") && file.getName().endsWith(".jar")
&& !file.getName().endsWith("-sources.jar")) {
return file;
}
}
throw new IllegalStateException(
"Could not find test application in target directory. Have you built it (mvn package)?");
} }
private Condition<String> coloredString(AnsiColor color, String string) { private Condition<String> coloredString(AnsiColor color, String string) {
@ -460,59 +328,30 @@ class SysVinitLaunchScriptIT {
throw new IllegalArgumentException("Failed to extract " + label + " from output: " + output); throw new IllegalArgumentException("Failed to extract " + label + " from output: " + output);
} }
private static final class CopyToContainerCmdExec extends AbstrSyncDockerCmdExec<CopyToContainerCmd, Void> { private static final class LaunchScriptTestContainer extends GenericContainer<LaunchScriptTestContainer> {
private CopyToContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) { private LaunchScriptTestContainer(String os, String version, String testScript) {
super(baseResource, dockerClientConfig); super(new ImageFromDockerfile("spring-boot-launch-script/" + os.toLowerCase() + "-" + version)
.withFileFromFile("Dockerfile",
new File("src/test/resources/conf/" + os + "/" + version + "/Dockerfile"))
.withFileFromFile("spring-boot-launch-script-tests.jar", findApplication())
.withFileFromFile("test-functions.sh", new File("src/test/resources/scripts/test-functions.sh")));
withCopyFileToContainer(MountableFile.forHostPath("src/test/resources/scripts/" + testScript),
"/" + testScript);
withCommand("/bin/bash", "-c", "chmod +x " + testScript + " && ./" + testScript);
withStartupTimeout(Duration.ofMinutes(5));
} }
@Override private static File findApplication() {
protected Void execute(CopyToContainerCmd command) { File targetDir = new File("target");
try (InputStream streamToUpload = new FileInputStream( for (File file : targetDir.listFiles()) {
CompressArchiveUtil.archiveTARFiles(command.getFile().getParentFile(), if (file.getName().startsWith("spring-boot-launch-script-tests") && file.getName().endsWith(".jar")
Arrays.asList(command.getFile()), command.getFile().getName()))) { && !file.getName().endsWith("-sources.jar")) {
WebTarget webResource = getBaseResource().path("/containers/{id}/archive").resolveTemplate("id", return file;
command.getContainer()); }
webResource.queryParam("path", ".").queryParam("noOverwriteDirNonDir", false).request()
.put(Entity.entity(streamToUpload, "application/x-tar")).close();
return null;
}
catch (Exception ex) {
throw new RuntimeException(ex);
} }
} throw new IllegalStateException(
"Could not find test application in target directory. Have you built it (mvn package)?");
}
private static final class CopyToContainerCmd implements DockerCmd<Void> {
private final String container;
private final File file;
private CopyToContainerCmd(String container, File file) {
this.container = container;
this.file = file;
}
String getContainer() {
return this.container;
}
File getFile() {
return this.file;
}
@Override
public void close() {
}
}
private static final class SpringBootDockerCmdExecFactory extends JerseyDockerCmdExecFactory {
private CopyToContainerCmdExec createCopyToContainerCmdExec() {
return new CopyToContainerCmdExec(getBaseResource(), getDockerClientConfig());
} }
} }

@ -7,3 +7,5 @@ RUN yum install -y wget && \
https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux.x86_64.rpm && \ https://cdn.azul.com/zulu/bin/zulu8.21.0.1-jdk8.0.131-linux.x86_64.rpm && \
yum --nogpg localinstall -y jdk.rpm && \ yum --nogpg localinstall -y jdk.rpm && \
rm -f jdk.rpm rm -f jdk.rpm
ADD spring-boot-launch-script-tests.jar /spring-boot-launch-script-tests.jar
ADD test-functions.sh /test-functions.sh

@ -6,3 +6,5 @@ RUN apt-get update && \
curl -L https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u202-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u202b08.tar.gz | tar zx --strip-components=1 curl -L https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u202-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u202b08.tar.gz | tar zx --strip-components=1
ENV JAVA_HOME /opt/openjdk ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH ENV PATH $JAVA_HOME/bin:$PATH
ADD spring-boot-launch-script-tests.jar /spring-boot-launch-script-tests.jar
ADD test-functions.sh /test-functions.sh

@ -6,3 +6,5 @@ RUN apt-get update && \
curl -L https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u202-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u202b08.tar.gz | tar zx --strip-components=1 curl -L https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u202-b08/OpenJDK8U-jdk_x64_linux_hotspot_8u202b08.tar.gz | tar zx --strip-components=1
ENV JAVA_HOME /opt/openjdk ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH ENV PATH $JAVA_HOME/bin:$PATH
ADD spring-boot-launch-script-tests.jar /spring-boot-launch-script-tests.jar
ADD test-functions.sh /test-functions.sh

@ -1,15 +1,15 @@
install_service() { install_service() {
mkdir /test-service mkdir /test-service
mv /spring-boot-launch-script-tests-*.jar /test-service/spring-boot-app.jar mv /spring-boot-launch-script-tests.jar /test-service/spring-boot-app.jar
chmod +x /test-service/spring-boot-app.jar chmod +x /test-service/spring-boot-app.jar
ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app
} }
install_double_link_service() { install_double_link_service() {
mkdir /test-service mkdir /test-service
mv /spring-boot-launch-script-tests-*.jar /test-service/ mv /spring-boot-launch-script-tests.jar /test-service/
chmod +x /test-service/spring-boot-launch-script-tests-*.jar chmod +x /test-service/spring-boot-launch-script-tests.jar
ln -s /test-service/spring-boot-launch-script-tests-*.jar /test-service/spring-boot-app.jar ln -s /test-service/spring-boot-launch-script-tests.jar /test-service/spring-boot-app.jar
ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app ln -s /test-service/spring-boot-app.jar /etc/init.d/spring-boot-app
} }

Loading…
Cancel
Save