diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild.native-image-properties.gradle.kts b/gradle/plugins/common/src/main/kotlin/junitbuild.native-image-properties.gradle.kts new file mode 100644 index 000000000000..262535f2083a --- /dev/null +++ b/gradle/plugins/common/src/main/kotlin/junitbuild.native-image-properties.gradle.kts @@ -0,0 +1,55 @@ +import junitbuild.graalvm.NativeImagePropertiesExtension +import java.util.zip.ZipFile + +plugins { + `java-library` +} + +val extension = extensions.create("nativeImageProperties").apply { + val resourceFile: RegularFile = layout.projectDirectory.file("src/nativeImage/initialize-at-build-time") + if (resourceFile.asFile.exists()) { + initializeAtBuildTime.convention(providers.fileContents(resourceFile).asText.map { it.trim().lines() }) + } else { + initializeAtBuildTime.empty() + } + initializeAtBuildTime.finalizeValueOnRead() +} + +val outputDir = layout.buildDirectory.dir("resources/nativeImage") + +val propertyFileTask = tasks.register("nativeImageProperties") { + destinationFile = outputDir.map { it.file("META-INF/native-image/${project.group}/${project.name}/native-image.properties") } + // see https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildConfiguration/#configuration-file-format + property("Args", extension.initializeAtBuildTime.map { + if (it.isEmpty()) { + "" + } else { + "--initialize-at-build-time=${it.joinToString(",")}" + } + }) +} + +val validationTask = tasks.register("validateNativeImageProperties") { + dependsOn(tasks.jar) + doLast { + val zipEntries = ZipFile(tasks.jar.get().archiveFile.get().asFile).use { zipFile -> + zipFile.entries().asSequence().map { it.name }.filter { it.endsWith(".class") }.toSet() + } + val missingClasses = extension.initializeAtBuildTime.get().filter { className -> + !zipEntries.contains("${className.replace('.', '/')}.class") + } + if (missingClasses.isNotEmpty()) { + throw GradleException("The following classes were specified as initialize-at-build-time but do not exist (you should probably remove them from nativeImageProperties.initializeAtBuildTime):\n${missingClasses.joinToString("\n- ", "- ")}") + } + } +} + +tasks.check { + dependsOn(validationTask) +} + +sourceSets { + main { + output.dir(propertyFileTask.map { outputDir }) + } +} diff --git a/gradle/plugins/common/src/main/kotlin/junitbuild/graalvm/NativeImagePropertiesExtension.kt b/gradle/plugins/common/src/main/kotlin/junitbuild/graalvm/NativeImagePropertiesExtension.kt new file mode 100644 index 000000000000..48cb4042c439 --- /dev/null +++ b/gradle/plugins/common/src/main/kotlin/junitbuild/graalvm/NativeImagePropertiesExtension.kt @@ -0,0 +1,7 @@ +package junitbuild.graalvm + +import org.gradle.api.provider.SetProperty + +abstract class NativeImagePropertiesExtension { + abstract val initializeAtBuildTime: SetProperty +} diff --git a/junit-jupiter-api/junit-jupiter-api.gradle.kts b/junit-jupiter-api/junit-jupiter-api.gradle.kts index 402b5323eb57..378fc86a3d5d 100644 --- a/junit-jupiter-api/junit-jupiter-api.gradle.kts +++ b/junit-jupiter-api/junit-jupiter-api.gradle.kts @@ -1,6 +1,7 @@ plugins { id("junitbuild.kotlin-library-conventions") id("junitbuild.code-generator") + id("junitbuild.native-image-properties") `java-test-fixtures` } diff --git a/junit-jupiter-api/src/nativeImage/initialize-at-build-time b/junit-jupiter-api/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..b8fb5c3d7514 --- /dev/null +++ b/junit-jupiter-api/src/nativeImage/initialize-at-build-time @@ -0,0 +1,4 @@ +org.junit.jupiter.api.DisplayNameGenerator$Standard +org.junit.jupiter.api.TestInstance$Lifecycle +org.junit.jupiter.api.condition.OS +org.junit.jupiter.api.extension.ConditionEvaluationResult diff --git a/junit-jupiter-engine/junit-jupiter-engine.gradle.kts b/junit-jupiter-engine/junit-jupiter-engine.gradle.kts index 04d86e5f0da7..819993462c0e 100644 --- a/junit-jupiter-engine/junit-jupiter-engine.gradle.kts +++ b/junit-jupiter-engine/junit-jupiter-engine.gradle.kts @@ -1,5 +1,6 @@ plugins { id("junitbuild.kotlin-library-conventions") + id("junitbuild.native-image-properties") `java-test-fixtures` } diff --git a/junit-jupiter-engine/src/nativeImage/initialize-at-build-time b/junit-jupiter-engine/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..05880451fb5a --- /dev/null +++ b/junit-jupiter-engine/src/nativeImage/initialize-at-build-time @@ -0,0 +1,22 @@ +org.junit.jupiter.engine.JupiterTestEngine +org.junit.jupiter.engine.config.CachingJupiterConfiguration +org.junit.jupiter.engine.config.DefaultJupiterConfiguration +org.junit.jupiter.engine.config.EnumConfigurationParameterConverter +org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter +org.junit.jupiter.engine.descriptor.ClassTestDescriptor +org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor +org.junit.jupiter.engine.descriptor.DynamicDescendantFilter +org.junit.jupiter.engine.descriptor.ExclusiveResourceCollector$1 +org.junit.jupiter.engine.descriptor.JupiterEngineDescriptor +org.junit.jupiter.engine.descriptor.JupiterTestDescriptor +org.junit.jupiter.engine.descriptor.JupiterTestDescriptor$1 +org.junit.jupiter.engine.descriptor.MethodBasedTestDescriptor +org.junit.jupiter.engine.descriptor.NestedClassTestDescriptor +org.junit.jupiter.engine.descriptor.TestFactoryTestDescriptor +org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor +org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor +org.junit.jupiter.engine.execution.ConditionEvaluator +org.junit.jupiter.engine.execution.InterceptingExecutableInvoker +org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall +org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall$VoidMethodInterceptorCall +org.junit.jupiter.engine.execution.InvocationInterceptorChain diff --git a/junit-jupiter-params/junit-jupiter-params.gradle.kts b/junit-jupiter-params/junit-jupiter-params.gradle.kts index d05a3b72e3e4..e481fdd13674 100644 --- a/junit-jupiter-params/junit-jupiter-params.gradle.kts +++ b/junit-jupiter-params/junit-jupiter-params.gradle.kts @@ -2,6 +2,7 @@ plugins { id("junitbuild.kotlin-library-conventions") id("junitbuild.shadow-conventions") id("junitbuild.jmh-conventions") + id("junitbuild.native-image-properties") } description = "JUnit Jupiter Params" diff --git a/junit-jupiter-params/src/nativeImage/initialize-at-build-time b/junit-jupiter-params/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..44ca7ffbd8ad --- /dev/null +++ b/junit-jupiter-params/src/nativeImage/initialize-at-build-time @@ -0,0 +1,2 @@ +org.junit.jupiter.params.provider.EnumSource$Mode +org.junit.jupiter.params.provider.EnumSource$Mode$Validator diff --git a/junit-platform-commons/junit-platform-commons.gradle.kts b/junit-platform-commons/junit-platform-commons.gradle.kts index 3465b0078020..3de45a7edfee 100644 --- a/junit-platform-commons/junit-platform-commons.gradle.kts +++ b/junit-platform-commons/junit-platform-commons.gradle.kts @@ -3,6 +3,7 @@ import junitbuild.java.UpdateJarAction plugins { id("junitbuild.java-library-conventions") id("junitbuild.java-multi-release-sources") + id("junitbuild.native-image-properties") `java-test-fixtures` } diff --git a/junit-platform-commons/src/nativeImage/initialize-at-build-time b/junit-platform-commons/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..a6c384232123 --- /dev/null +++ b/junit-platform-commons/src/nativeImage/initialize-at-build-time @@ -0,0 +1,5 @@ +org.junit.platform.commons.util.StringUtils +org.junit.platform.commons.logging.LoggerFactory$DelegatingLogger +org.junit.platform.commons.logging.LoggerFactory +org.junit.platform.commons.util.ReflectionUtils +org.junit.platform.commons.util.LruCache diff --git a/junit-platform-engine/junit-platform-engine.gradle.kts b/junit-platform-engine/junit-platform-engine.gradle.kts index 416b227b00c1..ef73763146a5 100644 --- a/junit-platform-engine/junit-platform-engine.gradle.kts +++ b/junit-platform-engine/junit-platform-engine.gradle.kts @@ -1,5 +1,6 @@ plugins { id("junitbuild.java-library-conventions") + id("junitbuild.native-image-properties") `java-test-fixtures` } diff --git a/junit-platform-engine/src/nativeImage/initialize-at-build-time b/junit-platform-engine/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..5b1168bb74a6 --- /dev/null +++ b/junit-platform-engine/src/nativeImage/initialize-at-build-time @@ -0,0 +1,7 @@ +org.junit.platform.engine.TestDescriptor$Type +org.junit.platform.engine.UniqueId +org.junit.platform.engine.UniqueId$Segment +org.junit.platform.engine.UniqueIdFormat +org.junit.platform.engine.support.descriptor.ClassSource +org.junit.platform.engine.support.descriptor.MethodSource +org.junit.platform.engine.support.hierarchical.Node$ExecutionMode diff --git a/junit-platform-launcher/junit-platform-launcher.gradle.kts b/junit-platform-launcher/junit-platform-launcher.gradle.kts index a9b3630762c8..acda6a79436f 100644 --- a/junit-platform-launcher/junit-platform-launcher.gradle.kts +++ b/junit-platform-launcher/junit-platform-launcher.gradle.kts @@ -1,5 +1,6 @@ plugins { id("junitbuild.java-library-conventions") + id("junitbuild.native-image-properties") `java-test-fixtures` } diff --git a/junit-platform-launcher/src/nativeImage/initialize-at-build-time b/junit-platform-launcher/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..4b3770ab5fb1 --- /dev/null +++ b/junit-platform-launcher/src/nativeImage/initialize-at-build-time @@ -0,0 +1,19 @@ +org.junit.platform.launcher.LauncherSessionListener$1 +org.junit.platform.launcher.TestIdentifier +org.junit.platform.launcher.core.DefaultLauncher +org.junit.platform.launcher.core.DefaultLauncherConfig +org.junit.platform.launcher.core.EngineDiscoveryOrchestrator +org.junit.platform.launcher.core.EngineExecutionOrchestrator +org.junit.platform.launcher.core.HierarchicalOutputDirectoryProvider +org.junit.platform.launcher.core.InternalTestPlan +org.junit.platform.launcher.core.LauncherConfig +org.junit.platform.launcher.core.LauncherConfigurationParameters +org.junit.platform.launcher.core.LauncherConfigurationParameters$ParameterProvider$1 +org.junit.platform.launcher.core.LauncherConfigurationParameters$ParameterProvider$2 +org.junit.platform.launcher.core.LauncherConfigurationParameters$ParameterProvider$3 +org.junit.platform.launcher.core.LauncherConfigurationParameters$ParameterProvider$4 +org.junit.platform.launcher.core.LauncherDiscoveryResult +org.junit.platform.launcher.core.LauncherListenerRegistry +org.junit.platform.launcher.core.ListenerRegistry +org.junit.platform.launcher.core.SessionPerRequestLauncher +org.junit.platform.launcher.listeners.UniqueIdTrackingListener diff --git a/junit-platform-reporting/junit-platform-reporting.gradle.kts b/junit-platform-reporting/junit-platform-reporting.gradle.kts index f1dede61555d..e9094c04f2e1 100644 --- a/junit-platform-reporting/junit-platform-reporting.gradle.kts +++ b/junit-platform-reporting/junit-platform-reporting.gradle.kts @@ -1,5 +1,6 @@ plugins { id("junitbuild.java-library-conventions") + id("junitbuild.native-image-properties") id("junitbuild.shadow-conventions") `java-test-fixtures` } diff --git a/junit-platform-reporting/src/nativeImage/initialize-at-build-time b/junit-platform-reporting/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..1b4f355f53cf --- /dev/null +++ b/junit-platform-reporting/src/nativeImage/initialize-at-build-time @@ -0,0 +1,2 @@ +org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener +org.junit.platform.reporting.shadow.org.opentest4j.reporting.events.api.DocumentWriter$1 diff --git a/junit-platform-suite-engine/junit-platform-suite-engine.gradle.kts b/junit-platform-suite-engine/junit-platform-suite-engine.gradle.kts index 36abcdbc088d..72f90de35321 100644 --- a/junit-platform-suite-engine/junit-platform-suite-engine.gradle.kts +++ b/junit-platform-suite-engine/junit-platform-suite-engine.gradle.kts @@ -1,5 +1,6 @@ plugins { id("junitbuild.java-library-conventions") + id("junitbuild.native-image-properties") } description = "JUnit Platform Suite Engine" diff --git a/junit-platform-suite-engine/src/nativeImage/initialize-at-build-time b/junit-platform-suite-engine/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..a6d7d06046b1 --- /dev/null +++ b/junit-platform-suite-engine/src/nativeImage/initialize-at-build-time @@ -0,0 +1,4 @@ +org.junit.platform.suite.engine.SuiteEngineDescriptor +org.junit.platform.suite.engine.SuiteLauncher +org.junit.platform.suite.engine.SuiteTestDescriptor +org.junit.platform.suite.engine.SuiteTestEngine diff --git a/junit-vintage-engine/junit-vintage-engine.gradle.kts b/junit-vintage-engine/junit-vintage-engine.gradle.kts index 9390bdcd3b4e..d2b22d6b711f 100644 --- a/junit-vintage-engine/junit-vintage-engine.gradle.kts +++ b/junit-vintage-engine/junit-vintage-engine.gradle.kts @@ -1,6 +1,7 @@ plugins { id("junitbuild.java-library-conventions") id("junitbuild.junit4-compatibility") + id("junitbuild.native-image-properties") id("junitbuild.testing-conventions") `java-test-fixtures` groovy diff --git a/junit-vintage-engine/src/nativeImage/initialize-at-build-time b/junit-vintage-engine/src/nativeImage/initialize-at-build-time new file mode 100644 index 000000000000..75ff3d41de5a --- /dev/null +++ b/junit-vintage-engine/src/nativeImage/initialize-at-build-time @@ -0,0 +1,5 @@ +org.junit.vintage.engine.VintageTestEngine +org.junit.vintage.engine.descriptor.RunnerTestDescriptor +org.junit.vintage.engine.descriptor.VintageEngineDescriptor +org.junit.vintage.engine.support.UniqueIdReader +org.junit.vintage.engine.support.UniqueIdStringifier diff --git a/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts b/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts index 77a7a5053c65..6203c65fdcac 100644 --- a/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts +++ b/platform-tooling-support-tests/projects/graalvm-starter/build.gradle.kts @@ -5,6 +5,7 @@ plugins { val jupiterVersion: String by project val platformVersion: String by project +val vintageVersion: String by project repositories { maven { url = uri(file(System.getProperty("maven.repo"))) } @@ -13,11 +14,16 @@ repositories { dependencies { testImplementation("org.junit.jupiter:junit-jupiter:$jupiterVersion") + testImplementation("junit:junit:4.13.2") + testImplementation("org.junit.platform:junit-platform-suite:$platformVersion") + testRuntimeOnly("org.junit.vintage:junit-vintage-engine:$vintageVersion") testRuntimeOnly("org.junit.platform:junit-platform-reporting:$platformVersion") } tasks.test { - useJUnitPlatform() + useJUnitPlatform { + includeEngines("junit-platform-suite") + } val outputDir = reports.junitXml.outputLocation jvmArgumentProviders += CommandLineArgumentProvider { @@ -31,8 +37,7 @@ tasks.test { graalvmNative { binaries { named("test") { - // TODO #3040 Add to native-image.properties - buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.HierarchicalOutputDirectoryProvider") + buildArgs.add("--strict-image-heap") buildArgs.add("-H:+ReportExceptionStackTraces") } } diff --git a/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java b/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java new file mode 100644 index 000000000000..82796513068d --- /dev/null +++ b/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/GraalvmSuite.java @@ -0,0 +1,18 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import org.junit.platform.suite.api.*; + +@Suite +@SelectPackages("com.example.project") +public class GraalvmSuite { +} diff --git a/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java b/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java new file mode 100644 index 000000000000..3ce117dea75b --- /dev/null +++ b/platform-tooling-support-tests/projects/graalvm-starter/src/test/java/com/example/project/VintageTests.java @@ -0,0 +1,19 @@ +/* + * Copyright 2015-2024 the original author or authors. + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v2.0 which + * accompanies this distribution and is available at + * + * https://www.eclipse.org/legal/epl-v20.html + */ + +package com.example.project; + +import org.junit.Test; + +public class VintageTests { + @Test + public void test() { + } +} diff --git a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java index 9376899354f1..1a36ff86d129 100644 --- a/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java +++ b/platform-tooling-support-tests/src/test/java/platform/tooling/support/tests/GraalVmStarterTests.java @@ -53,6 +53,7 @@ void runsTestsInNativeImage(@TempDir Path workspace, @FilePrefix("gradle") Outpu .anyMatch(line -> line.contains("CalculatorTests > 1 + 1 = 2 SUCCESSFUL")) // .anyMatch(line -> line.contains("CalculatorTests > 1 + 100 = 101 SUCCESSFUL")) // .anyMatch(line -> line.contains("ClassLevelAnnotationTests$Inner > test() SUCCESSFUL")) // + .anyMatch(line -> line.contains("com.example.project.VintageTests > test SUCCESSFUL")) // .anyMatch(line -> line.contains("BUILD SUCCESSFUL")); } }