diff --git a/build-logic/common-plugins/src/main/groovy/org.graalvm.build.github-actions-helper.gradle b/build-logic/common-plugins/src/main/groovy/org.graalvm.build.github-actions-helper.gradle index ab1fc4cba..e639bd997 100644 --- a/build-logic/common-plugins/src/main/groovy/org.graalvm.build.github-actions-helper.gradle +++ b/build-logic/common-plugins/src/main/groovy/org.graalvm.build.github-actions-helper.gradle @@ -7,11 +7,11 @@ def matrixDefault = [ // # Following versions are disabled temporarily in order to speed up PR testing "7.3.3", "7.2", "7.1", "6.8.3", def gradleVersions = [ - "gradle-version": ["current", "7.4", "8.13"], + "gradle-version": ["current", "8.4", "8.14.2"], ] def gradleCachedVersions = [ - "gradle-config-cache-version": ["current", "8.0.1"] + "gradle-config-cache-version": ["current", "8.14.2"] ] sourceSets.configureEach { sourceSet -> diff --git a/build-logic/gradle-functional-testing/src/main/groovy/org.graalvm.build.functional-testing.gradle b/build-logic/gradle-functional-testing/src/main/groovy/org.graalvm.build.functional-testing.gradle index dd99fdcfa..3125fc3cb 100644 --- a/build-logic/gradle-functional-testing/src/main/groovy/org.graalvm.build.functional-testing.gradle +++ b/build-logic/gradle-functional-testing/src/main/groovy/org.graalvm.build.functional-testing.gradle @@ -83,8 +83,10 @@ def graalVm = javaToolchains.launcherFor { def fullFunctionalTest = tasks.register("fullFunctionalTest") -['functionalTest', 'configCacheFunctionalTest'].each { baseName -> - ["current", "7.4", "7.6.2", "8.0.1", "8.2.1", "8.13"].each { gradleVersion -> +['functionalTest': ["current", "8.4", "8.14.2"], + 'configCacheFunctionalTest': ['current', "8.14.2"] +].each { baseName, gradleVersions -> + gradleVersions.each { gradleVersion -> String taskName = gradleVersion == 'current' ? baseName : "gradle${gradleVersion}${baseName.capitalize()}" // Add a task to run the functional tests def testTask = tasks.register(taskName, Test) { diff --git a/common/junit-platform-native/build.gradle b/common/junit-platform-native/build.gradle index 6231a8486..e1883575e 100644 --- a/common/junit-platform-native/build.gradle +++ b/common/junit-platform-native/build.gradle @@ -52,12 +52,19 @@ maven { } dependencies { compileOnly libs.graalvm.svm - implementation(platform(libs.test.junit.bom)) - implementation libs.test.junit.platform.console - implementation libs.test.junit.platform.launcher - implementation libs.test.junit.jupiter.core + compileOnly(platform(libs.test.junit.bom)) + compileOnly libs.test.junit.platform.console + compileOnly libs.test.junit.platform.launcher + compileOnly libs.test.junit.jupiter.core testImplementation libs.test.junit.vintage + + testImplementation libs.test.junit.jupiter.core + + testRuntimeOnly(platform(libs.test.junit.bom)) + testCompileOnly(platform(libs.test.junit.bom)) + testRuntimeOnly libs.test.junit.platform.console testRuntimeOnly libs.test.junit.platform.launcher + testRuntimeOnly libs.test.junit.jupiter.core } apply from: "gradle/native-image-testing.gradle" diff --git a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java index 2b0e1738d..757790bc5 100644 --- a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java +++ b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java @@ -226,7 +226,13 @@ private static void initializeClassesForJDK21OrEarlier() { try (InputStream is = JUnitPlatformFeature.class.getResourceAsStream("/initialize-at-buildtime")) { if (is != null) { try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { - br.lines().forEach(RuntimeClassInitialization::initializeAtBuildTime); + br.lines().forEach(cls -> { + try { + RuntimeClassInitialization.initializeAtBuildTime(cls); + } catch (NoClassDefFoundError e) { + // if users use older JUnit versions some classes might not be available + } + }); } } } catch (IOException e) { diff --git a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/NativeImageJUnitLauncher.java b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/NativeImageJUnitLauncher.java index 5829d6f42..4372adc55 100644 --- a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/NativeImageJUnitLauncher.java +++ b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/NativeImageJUnitLauncher.java @@ -123,12 +123,12 @@ public static void main(String... args) { out.println("JUnit Platform on Native Image - report"); out.println("----------------------------------------\n"); out.flush(); - launcher.registerTestExecutionListeners(new PrintTestExecutionListener(out)); + configurePrintTestExecutionListener(launcher, out); } SummaryGeneratingListener summaryListener = new SummaryGeneratingListener(); launcher.registerTestExecutionListeners(summaryListener); - launcher.registerTestExecutionListeners(new LegacyXmlReportGeneratingListener(Paths.get(xmlOutput), out)); + configureLegacyXMLReport(launcher, xmlOutput, out); launcher.execute(testPlan); TestExecutionSummary summary = summaryListener.getSummary(); @@ -271,4 +271,21 @@ private static boolean testIdsDirectoryExists(Path directory) { return directory != null && Files.exists(directory); } + + private static void configurePrintTestExecutionListener(Launcher launcher, PrintWriter out) { + try { + Class.forName("org.junit.platform.reporting.legacy.LegacyReportingUtils"); + launcher.registerTestExecutionListeners(new PrintTestExecutionListener(out)); + } catch (NoClassDefFoundError | ClassNotFoundException e) { + // intentionally ignored + } + } + + private static void configureLegacyXMLReport(Launcher launcher, String xmlOutput, PrintWriter out) { + try { + launcher.registerTestExecutionListeners(new LegacyXmlReportGeneratingListener(Paths.get(xmlOutput), out)); + } catch (NoClassDefFoundError e) { + // intentionally ignored + } + } } diff --git a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java index f666eba56..894099f12 100644 --- a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java +++ b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java @@ -54,8 +54,8 @@ import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.ArgumentsSource; import org.junit.jupiter.params.provider.EnumSource; -import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.FieldSource; +import org.junit.jupiter.params.provider.MethodSource; import java.lang.reflect.Method; import java.util.ArrayList; @@ -86,9 +86,15 @@ public void onTestClassRegistered(Class testClass, NativeImageConfiguration r AnnotationUtils.forEachAnnotatedMethodParameter(testClass, AggregateWith.class, annotation -> registry.registerAllClassMembersForReflection(annotation.value())); AnnotationUtils.forEachAnnotatedMethod(testClass, EnumSource.class, (m, annotation) -> handleEnumSource(m, annotation, registry)); AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, MethodSource.class, JupiterConfigProvider::handleMethodSource); - AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, FieldSource.class, JupiterConfigProvider::handleFieldSource); AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, EnabledIf.class, JupiterConfigProvider::handleEnabledIf); AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, DisabledIf.class, JupiterConfigProvider::handleDisabledIf); + + try { + AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, FieldSource.class, JupiterConfigProvider::handleFieldSource); + } catch (NoClassDefFoundError e) { + // if users use JUnit version older than 5.11, FieldSource class won't be available + } + } private static Class[] handleMethodSource(MethodSource annotation) { diff --git a/common/junit-platform-native/src/main/resources/initialize-at-buildtime b/common/junit-platform-native/src/main/resources/initialize-at-buildtime index 152f4f430..279c3a80b 100644 --- a/common/junit-platform-native/src/main/resources/initialize-at-buildtime +++ b/common/junit-platform-native/src/main/resources/initialize-at-buildtime @@ -46,6 +46,7 @@ org.junit.jupiter.engine.discovery.MethodSelectorResolver$MethodType$3 org.junit.jupiter.engine.discovery.predicates.IsTestClassWithTests org.junit.jupiter.engine.discovery.predicates.IsTestFactoryMethod org.junit.jupiter.engine.execution.ConditionEvaluator +org.junit.jupiter.engine.execution.ExecutableInvoker org.junit.jupiter.engine.execution.InterceptingExecutableInvoker org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall$VoidMethodInterceptorCall @@ -78,6 +79,7 @@ org.junit.platform.launcher.core.DiscoveryIssueNotifier org.junit.platform.launcher.core.EngineDiscoveryOrchestrator org.junit.platform.launcher.core.EngineExecutionOrchestrator org.junit.platform.launcher.core.EngineFilterer +org.junit.platform.launcher.core.EngineIdValidator org.junit.platform.launcher.core.HierarchicalOutputDirectoryProvider org.junit.platform.launcher.core.InternalTestPlan org.junit.platform.launcher.core.LauncherConfig @@ -91,6 +93,8 @@ org.junit.platform.launcher.core.LauncherDiscoveryResult$EngineResultInfo org.junit.platform.launcher.core.LauncherListenerRegistry org.junit.platform.launcher.core.LauncherPhase org.junit.platform.launcher.core.ListenerRegistry +org.junit.platform.launcher.core.ServiceLoaderRegistry +org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry org.junit.platform.launcher.core.SessionPerRequestLauncher org.junit.platform.launcher.EngineDiscoveryResult org.junit.platform.launcher.LauncherSessionListener$1 diff --git a/common/utils/src/main/java/org/graalvm/buildtools/utils/JUnitPlatformNativeDependenciesHelper.java b/common/utils/src/main/java/org/graalvm/buildtools/utils/JUnitPlatformNativeDependenciesHelper.java new file mode 100644 index 000000000..3f41d2286 --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/utils/JUnitPlatformNativeDependenciesHelper.java @@ -0,0 +1,81 @@ +/* + * Copyright 2003-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 org.graalvm.buildtools.utils; + +import java.util.List; + +public abstract class JUnitPlatformNativeDependenciesHelper { + + private static final DependencyNotation JUNIT_PLATFORM_LAUNCHER = new DependencyNotation( + "org.junit.platform", "junit-platform-launcher", "" + ); + private static final DependencyNotation JUNIT_PLATFORM_ENGINE = new DependencyNotation( + "org.junit.platform", "junit-platform-engine", "" + ); + private static final DependencyNotation JUNIT_PLATFORM_CONSOLE = new DependencyNotation( + "org.junit.platform", "junit-platform-console", "" + ); + private static final DependencyNotation JUNIT_PLATFORM_REPORTING = new DependencyNotation( + "org.junit.platform", "junit-platform-reporting", "" + ); + + private static final List JUNIT_PLATFORM_DEPENDENCIES = List.of( + JUNIT_PLATFORM_LAUNCHER, + JUNIT_PLATFORM_CONSOLE, + JUNIT_PLATFORM_REPORTING + ); + + private JUnitPlatformNativeDependenciesHelper() { + + } + + /** + * Returns the list of dependencies which should be added to the + * native test classpath in order for tests to execute. + * @param input the current list of dependencies + * @return a list of dependencies which need to be added + */ + public static List inferMissingDependenciesForTestRuntime( + List input + ) { + var junitPlatformVersion = input.stream() + .filter(d -> d.equalsIgnoreVersion(JUNIT_PLATFORM_ENGINE)) + .findFirst() + .map(DependencyNotation::version) + .orElse(""); + var list = JUNIT_PLATFORM_DEPENDENCIES.stream() + .filter(d -> input.stream().noneMatch(o -> o.equalsIgnoreVersion(d))) + .map(d -> d.withVersion(junitPlatformVersion)) + .toList(); + return list; + } + + + public record DependencyNotation( + String groupId, + String artifactId, + String version + ) { + public boolean equalsIgnoreVersion(DependencyNotation other) { + return other.groupId.equals(groupId) && + other.artifactId.equals(artifactId); + } + + public DependencyNotation withVersion(String version) { + return new DependencyNotation(groupId, artifactId, version); + } + } +} diff --git a/docs/src/docs/asciidoc/changelog.adoc b/docs/src/docs/asciidoc/changelog.adoc index ed9e7f5de..5b8dbee0e 100644 --- a/docs/src/docs/asciidoc/changelog.adoc +++ b/docs/src/docs/asciidoc/changelog.adoc @@ -3,7 +3,7 @@ == Release 0.11.0 -This version introduces a breaking change: the plugin now requires Java 17 to run. +This version introduces a breaking change: the plugin now requires Gradle 8.3+ and Java 17 to run. === Gradle plugin diff --git a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JUnitFunctionalTests.groovy b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JUnitFunctionalTests.groovy index 1b2e2ae92..2a23a0b8f 100644 --- a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JUnitFunctionalTests.groovy +++ b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JUnitFunctionalTests.groovy @@ -44,7 +44,7 @@ package org.graalvm.buildtools.gradle import org.graalvm.buildtools.gradle.fixtures.AbstractFunctionalTest class JUnitFunctionalTests extends AbstractFunctionalTest { - def "test if JUint support works with various annotations, reflection and resources"() { + def "test if JUnit support works with various annotations, reflection and resources"() { debug=true given: withSample("junit-tests") diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java index d2969e3bb..6ef56c9f8 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java @@ -64,6 +64,7 @@ import org.graalvm.buildtools.gradle.tasks.UseLayerOptions; import org.graalvm.buildtools.gradle.tasks.actions.CleanupAgentFilesAction; import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; +import org.graalvm.buildtools.utils.JUnitPlatformNativeDependenciesHelper; import org.graalvm.buildtools.utils.JUnitUtils; import org.graalvm.buildtools.gradle.tasks.scanner.JarAnalyzerTransform; import org.graalvm.buildtools.utils.SharedConstants; @@ -124,9 +125,11 @@ import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Path; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -683,7 +686,7 @@ public void registerTestBinary(Project project, }); // Following ensures that required feature jar is on classpath for every project - injectTestPluginDependencies(project, graalExtension.getTestSupport()); + injectTestPluginDependencies(project, name, graalExtension.getTestSupport()); TaskProvider testImageBuilder = tasks.named(deriveTaskName(name, "native", "Compile"), BuildNativeImageTask.class, task -> { task.setOnlyIf(t -> graalExtension.getTestSupport().get() && testListDirectory.getAsFile().get().exists()); task.getTestListDirectory().set(testListDirectory); @@ -930,11 +933,57 @@ public void execute(@Nonnull Task task) { taskToInstrument.doLast(new CleanupAgentFilesAction(mergeInputDirs, fileOperations)); } - private static void injectTestPluginDependencies(Project project, Property testSupportEnabled) { + private static void injectTestPluginDependencies(Project project, String binaryName, Property testSupportEnabled) { project.afterEvaluate(p -> { if (testSupportEnabled.get()) { - project.getDependencies().add("testImplementation", "org.graalvm.buildtools:junit-platform-native:" - + VersionInfo.JUNIT_PLATFORM_NATIVE_VERSION); + var configurations = project.getConfigurations(); + var inferConfigName = imageClasspathConfigurationNameFor(binaryName) + "Internal"; + var missingDependenciesConfig = configurations.create(compileOnlyClasspathConfigurationNameFor(binaryName) + "Auto", cnf -> { + cnf.setCanBeResolved(false); + cnf.setCanBeConsumed(false); + }); + var imageClasspath = configurations.getByName(imageClasspathConfigurationNameFor(binaryName)); + var inferConfig = configurations.create(inferConfigName, cnf -> { + cnf.setDescription("Infers missing dependencies which are required to run native tests"); + cnf.setExtendsFrom(imageClasspath.getExtendsFrom()); + cnf.setCanBeConsumed(false); + cnf.setCanBeResolved(true); + var attributes = imageClasspath.getAttributes().keySet(); + cnf.attributes(attrs -> { + for (var attribute : attributes) { + var key = (Attribute) attribute; + Object value = imageClasspath.getAttributes().getAttribute(key); + attrs.attribute(key, value); + } + }); + }); + // Do not move this up or resolution will fail because we'll create the infer + // configuration with an unwanted parent config! + imageClasspath.extendsFrom(missingDependenciesConfig); + + project.getDependencies().add(compileOnlyClasspathConfigurationNameFor(binaryName), "org.graalvm.buildtools:junit-platform-native:" + VersionInfo.JUNIT_PLATFORM_NATIVE_VERSION); + missingDependenciesConfig + .getDependencies() + .addAllLater(inferConfig.getIncoming() + .getResolutionResult() + .getRootComponent() + .map(root -> { + var allDependencies = new ArrayList(); + var visited = new HashSet(); + var queue = new ArrayDeque(root.getDependencies()); + while (!queue.isEmpty()) { + var current = queue.pop(); + if (visited.add(current) && current instanceof ResolvedDependencyResult resolved) { + if (resolved.getSelected().getId() instanceof ModuleComponentIdentifier mci) { + allDependencies.add(new JUnitPlatformNativeDependenciesHelper.DependencyNotation(mci.getGroup(), mci.getModule(), mci.getVersion())); + } + } + } + return JUnitPlatformNativeDependenciesHelper.inferMissingDependenciesForTestRuntime(allDependencies) + .stream() + .map(notation -> project.getDependencies().create(notation.groupId() + ":" + notation.artifactId() + ":" + notation.version())) + .toList(); + })); } }); } diff --git a/native-maven-plugin/reproducers/issue-144/pom.xml b/native-maven-plugin/reproducers/issue-144/pom.xml index 84ad1b124..0e98a23fb 100644 --- a/native-maven-plugin/reproducers/issue-144/pom.xml +++ b/native-maven-plugin/reproducers/issue-144/pom.xml @@ -69,7 +69,7 @@ ${junit.jupiter.version} test - + diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java index aa6c365be..bc6cf27e1 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/AbstractNativeImageMojo.java @@ -376,6 +376,10 @@ protected void addDependenciesToClasspath() throws MojoExecutionException { } } + protected void addInferredDependenciesToClasspath() { + + } + @Override protected void maybeAddDependencyMetadata(Artifact dependency, Consumer excludeAction) { if (isExcluded(dependency)) { @@ -425,6 +429,7 @@ protected void populateClasspath() throws MojoExecutionException { populateApplicationClasspath(); addDependenciesToClasspath(); } + addInferredDependenciesToClasspath(); imageClasspath.removeIf(entry -> !entry.toFile().exists()); } diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeTestMojo.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeTestMojo.java index 03de3b9ec..8579abb8a 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeTestMojo.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/NativeTestMojo.java @@ -60,6 +60,7 @@ import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.resolution.DependencyResolutionException; import org.eclipse.aether.resolution.DependencyResult; +import org.graalvm.buildtools.utils.JUnitPlatformNativeDependenciesHelper; import org.graalvm.buildtools.utils.JUnitUtils; import org.graalvm.buildtools.utils.NativeImageConfigurationUtils; @@ -70,12 +71,13 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -121,8 +123,8 @@ protected List getDependencyScopes() { } @Override - protected void addDependenciesToClasspath() throws MojoExecutionException { - super.addDependenciesToClasspath(); + protected void addInferredDependenciesToClasspath() { + super.addInferredDependenciesToClasspath(); Set modules = new HashSet<>(); //noinspection SimplifyStreamApiCallChains pluginArtifacts.stream() @@ -287,36 +289,82 @@ private static Stream findFiles(Path dir, String prefix) throws IOExceptio && path.getFileName().toString().startsWith(prefix))); } - private List findJunitPlatformNativeJars(Set modulesAlreadyOnClasspath) { + private DependencyResult resolveDependencies(Consumer configurer) { RepositorySystemSession repositorySession = mavenSession.getRepositorySession(); DefaultRepositorySystemSession newSession = new DefaultRepositorySystemSession(repositorySession); CollectRequest collectRequest = new CollectRequest(); List repositories = project.getRemoteProjectRepositories(); collectRequest.setRepositories(repositories); - DefaultArtifact artifact = new DefaultArtifact( - RuntimeMetadata.GROUP_ID, - RuntimeMetadata.JUNIT_PLATFORM_NATIVE_ARTIFACT_ID, - null, - "jar", - RuntimeMetadata.VERSION - ); - Dependency dependency = new Dependency(artifact, "runtime"); - collectRequest.addDependency(dependency); + configurer.accept(collectRequest); DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, null); - DependencyResult dependencyResult; try { - dependencyResult = repositorySystem.resolveDependencies(newSession, dependencyRequest); + return repositorySystem.resolveDependencies(newSession, dependencyRequest); } catch (DependencyResolutionException e) { - return Collections.emptyList(); + return e.getResult(); } + } + + private List findJunitPlatformNativeJars(Set modulesAlreadyOnClasspath) { + DependencyResult dependencyResult; + dependencyResult = resolveDependencies(collectRequest -> { + var artifact = new DefaultArtifact( + RuntimeMetadata.GROUP_ID, + RuntimeMetadata.JUNIT_PLATFORM_NATIVE_ARTIFACT_ID, + null, + "jar", + RuntimeMetadata.VERSION + ); + var dependency = new Dependency(artifact, "runtime"); + collectRequest.addDependency(dependency); + addMissingDependencies(collectRequest); + }); return dependencyResult.getArtifactResults() .stream() .map(ArtifactResult::getArtifact) + .filter(Objects::nonNull) .filter(a -> !modulesAlreadyOnClasspath.contains(new Module(a.getGroupId(), a.getArtifactId()))) .map(a -> a.getFile().toPath()) .collect(Collectors.toList()); } + private void addMissingDependencies(CollectRequest collectRequest) { + // it's a chicken-and-egg problem, we need to resolve the dependencies first, in order + // to have the list of dependencies which are present and infer the ones which are missing + var current = resolveDependencies(request -> { + for (var dependency : project.getDependencies()) { + if (!dependency.isOptional()) { + request.addDependency(new Dependency( + new DefaultArtifact( + dependency.getGroupId(), + dependency.getArtifactId(), + dependency.getClassifier(), + "jar", + dependency.getVersion() + ), + "runtime" + )); + } + } + }); + var currentClasspath = current.getArtifactResults().stream() + .map(result -> new JUnitPlatformNativeDependenciesHelper.DependencyNotation( + result.getArtifact().getGroupId(), + result.getArtifact().getArtifactId(), + result.getArtifact().getVersion() + )).toList(); + var deps = JUnitPlatformNativeDependenciesHelper.inferMissingDependenciesForTestRuntime(currentClasspath); + for (var missing : deps) { + var missingDependency = new Dependency(new DefaultArtifact( + missing.groupId(), + missing.artifactId(), + null, + null, + missing.version() + ), "runtime"); + collectRequest.addDependency(missingDependency); + } + } + private static final class Module { private final String groupId; private final String artifactId; diff --git a/samples/java-application-with-custom-tests/build.gradle b/samples/java-application-with-custom-tests/build.gradle index c6e4a8fbe..5fb5e578e 100644 --- a/samples/java-application-with-custom-tests/build.gradle +++ b/samples/java-application-with-custom-tests/build.gradle @@ -62,6 +62,7 @@ sourceSets { configurations { integTestImplementation.extendsFrom(testImplementation) + integTestRuntimeOnly.extendsFrom(testRuntimeOnly) } dependencies { diff --git a/samples/java-application-with-reflection/pom.xml b/samples/java-application-with-reflection/pom.xml index 34e483217..4b8fc6b04 100644 --- a/samples/java-application-with-reflection/pom.xml +++ b/samples/java-application-with-reflection/pom.xml @@ -275,7 +275,9 @@ true Direct - config-output-dir=/tmp,builtin-caller-filter=true,builtin-heuristic-filter=true,experimental-class-define-support=false,experimental-unsafe-allocation-support=false,track-reflection-metadata=true + + config-output-dir=/tmp,builtin-caller-filter=true,builtin-heuristic-filter=true,experimental-class-define-support=false,experimental-unsafe-allocation-support=false,track-reflection-metadata=true + true diff --git a/samples/java-library/build.gradle b/samples/java-library/build.gradle index 0b9c4d818..4b0125057 100644 --- a/samples/java-library/build.gradle +++ b/samples/java-library/build.gradle @@ -48,8 +48,7 @@ repositories { mavenCentral() } -def junitVersion = providers.gradleProperty('junit.jupiter.version') - .get() +def junitVersion = providers.gradleProperty('junit.jupiter.version').get() dependencies { testImplementation(platform("org.junit:junit-bom:${junitVersion}")) diff --git a/samples/junit-tests/build.gradle b/samples/junit-tests/build.gradle index 5ca72fe10..8ffc41d56 100644 --- a/samples/junit-tests/build.gradle +++ b/samples/junit-tests/build.gradle @@ -51,6 +51,7 @@ repositories { dependencies { testImplementation 'org.junit.jupiter:junit-jupiter:5.13.0' testImplementation "org.junit.vintage:junit-vintage-engine:5.13.0" + testRuntimeOnly("org.junit.platform:junit-platform-launcher") } application { diff --git a/samples/kotlin-application-with-tests/build.gradle b/samples/kotlin-application-with-tests/build.gradle index e69823512..8419d4bfb 100644 --- a/samples/kotlin-application-with-tests/build.gradle +++ b/samples/kotlin-application-with-tests/build.gradle @@ -49,11 +49,15 @@ repositories { mavenCentral() } +def junitVersion = providers.gradleProperty('junit.jupiter.version').get() + dependencies { implementation platform('org.jetbrains.kotlin:kotlin-bom') implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' + testImplementation(platform("org.junit:junit-bom:${junitVersion}")) testImplementation 'org.jetbrains.kotlin:kotlin-test' + testRuntimeOnly("org.junit.jupiter:junit-jupiter") } application {