diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/build.gradle b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/build.gradle index e287ed0a16..aa88c046b4 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/build.gradle +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/build.gradle @@ -18,6 +18,8 @@ dependencies { app project(path: ":spring-boot-project:spring-boot-dependencies", configuration: "mavenRepository") app project(path: ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin", configuration: "mavenRepository") app project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-web", configuration: "mavenRepository") + app project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter", configuration: "mavenRepository") + app("org.bouncycastle:bcprov-jdk18on:1.76") intTestImplementation(enforcedPlatform(project(":spring-boot-project:spring-boot-parent"))) intTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) @@ -43,6 +45,18 @@ task buildApp(type: GradleBuild) { tasks = ["build"] } +task syncSignedJarAppSource(type: org.springframework.boot.build.SyncAppSource) { + sourceDirectory = file("spring-boot-loader-tests-signed-jar") + destinationDirectory = file("${buildDir}/spring-boot-loader-tests-signed-jar") +} + +task buildSignedJarApp(type: GradleBuild) { + dependsOn syncSignedJarAppSource, syncMavenRepository + dir = "${buildDir}/spring-boot-loader-tests-signed-jar" + startParameter.buildCacheEnabled = false + tasks = ["build"] +} + task downloadJdk(type: Download) { def destFolder = new File(rootProject.buildDir, "downloads/jdk/oracle") destFolder.mkdirs() @@ -64,5 +78,5 @@ processIntTestResources { } intTest { - dependsOn buildApp + dependsOn buildApp, buildSignedJarApp } diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/build.gradle b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/build.gradle new file mode 100644 index 0000000000..7ca8a27124 --- /dev/null +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/build.gradle @@ -0,0 +1,30 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id "java" + id "org.springframework.boot" +} + +apply plugin: "io.spring.dependency-management" + +repositories { + maven { url "file:${rootDir}/../int-test-maven-repository"} + mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter") + implementation("org.bouncycastle:bcprov-jdk18on:1.76") +} + +tasks.register("bootJarUnpack", BootJar.class) { + mainClass = "org.springframework.boot.loaderapp.LoaderSignedJarTestApplication" + classpath = bootJar.classpath + requiresUnpack '**/bcprov-jdk18on-*.jar' + archiveClassifier.set("unpack") + targetJavaVersion = targetCompatibility +} + +build.dependsOn bootJarUnpack \ No newline at end of file diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/settings.gradle b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/settings.gradle new file mode 100644 index 0000000000..06d9554ad0 --- /dev/null +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/settings.gradle @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + maven { url "file:${rootDir}/../int-test-maven-repository"} + mavenCentral() + maven { url "https://repo.spring.io/snapshot" } + maven { url "https://repo.spring.io/milestone" } + } + resolutionStrategy { + eachPlugin { + if (requested.id.id == "org.springframework.boot") { + useModule "org.springframework.boot:spring-boot-gradle-plugin:${requested.version}" + } + } + } +} \ No newline at end of file diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/src/main/java/org/springframework/boot/loaderapp/LoaderSignedJarTestApplication.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/src/main/java/org/springframework/boot/loaderapp/LoaderSignedJarTestApplication.java new file mode 100644 index 0000000000..627a6c3996 --- /dev/null +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/spring-boot-loader-tests-signed-jar/src/main/java/org/springframework/boot/loaderapp/LoaderSignedJarTestApplication.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2023 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.boot.loaderapp; + +import java.security.Security; +import javax.crypto.Cipher; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LoaderSignedJarTestApplication { + + public static void main(String[] args) throws Exception { + Security.addProvider(new BouncyCastleProvider()); + Cipher.getInstance("AES/CBC/PKCS5Padding","BC"); + System.out.println("Legion of the Bouncy Castle"); + SpringApplication.run(LoaderSignedJarTestApplication.class, args); + } + +} diff --git a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/intTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/intTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java index 3e5c2f023e..ac6592bc9d 100644 --- a/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/intTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java +++ b/spring-boot-tests/spring-boot-integration-tests/spring-boot-loader-tests/src/intTest/java/org/springframework/boot/loader/LoaderIntegrationTests.java @@ -37,6 +37,7 @@ import org.springframework.boot.testsupport.testcontainers.DisabledIfDockerUnava import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; /** * Integration tests loader that supports fat jars. @@ -52,7 +53,7 @@ class LoaderIntegrationTests { @ParameterizedTest @MethodSource("javaRuntimes") void readUrlsWithoutWarning(JavaRuntime javaRuntime) { - try (GenericContainer container = createContainer(javaRuntime)) { + try (GenericContainer container = createContainer(javaRuntime, "spring-boot-loader-tests-app", null)) { container.start(); System.out.println(this.output.toUtf8String()); assertThat(this.output.toUtf8String()).contains(">>>>> 287649 BYTES from") @@ -62,18 +63,46 @@ class LoaderIntegrationTests { } } - private GenericContainer createContainer(JavaRuntime javaRuntime) { + @ParameterizedTest + @MethodSource("javaRuntimes") + void runSignedJar(JavaRuntime javaRuntime) { + assumeThat(javaRuntime.toString()).isNotEqualTo("Oracle JDK 17"); // gh-28837 + try (GenericContainer container = createContainer(javaRuntime, "spring-boot-loader-tests-signed-jar", + null)) { + container.start(); + System.out.println(this.output.toUtf8String()); + assertThat(this.output.toUtf8String()).contains("Legion of the Bouncy Castle"); + } + } + + @ParameterizedTest + @MethodSource("javaRuntimes") + void runSignedJarWhenUnpack(JavaRuntime javaRuntime) { + try (GenericContainer container = createContainer(javaRuntime, "spring-boot-loader-tests-signed-jar", + "unpack")) { + container.start(); + System.out.println(this.output.toUtf8String()); + assertThat(this.output.toUtf8String()).contains("Legion of the Bouncy Castle"); + } + } + + private GenericContainer createContainer(JavaRuntime javaRuntime, String name, String classifier) { return javaRuntime.getContainer() .withLogConsumer(this.output) - .withCopyFileToContainer(MountableFile.forHostPath(findApplication().toPath()), "/app.jar") + .withCopyFileToContainer(findApplication(name, classifier), "/app.jar") .withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofMinutes(5))) .withCommand("java", "-jar", "app.jar"); } - private File findApplication() { - String name = String.format("build/%1$s/build/libs/%1$s.jar", "spring-boot-loader-tests-app"); - File jar = new File(name); - Assert.state(jar.isFile(), () -> "Could not find " + name + ". Have you built it?"); + private MountableFile findApplication(String name, String classifier) { + return MountableFile.forHostPath(findJarFile(name, classifier).toPath()); + } + + private File findJarFile(String name, String classifier) { + classifier = (classifier != null) ? "-" + classifier : ""; + String path = String.format("build/%1$s/build/libs/%1$s%2$s.jar", name, classifier); + File jar = new File(path); + Assert.state(jar.isFile(), () -> "Could not find " + path + ". Have you built it?"); return jar; }