diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPlugin.kt index e505ecb9215..3091227b1bc 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPlugin.kt @@ -28,6 +28,17 @@ class TestJvmConstraintsPlugin : Plugin { } inputs.property("testJvm", testJvmSpec.testJvmProperty).optional(true) + // Gradle tracks the language version, but not the resolved vendor or full JVM versions. + inputs.property("jvmIdentity", javaLauncher.map { launcher -> + with(launcher.metadata) { + mapOf( + "languageVersion" to languageVersion.asInt().toString(), + "vendor" to vendor, + "runtimeVersion" to javaRuntimeVersion, + "vmVersion" to jvmVersion, + ) + } + }) val taskExtension = project.objects.newInstance().also { configureConventions(it, projectExtension) diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmCacheInputsTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmCacheInputsTest.kt new file mode 100644 index 00000000000..e3fbcc90788 --- /dev/null +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmCacheInputsTest.kt @@ -0,0 +1,83 @@ +package datadog.gradle.plugin.testJvmConstraints + +import datadog.gradle.plugin.GradleFixture +import org.assertj.core.api.Assertions.assertThat +import org.gradle.testkit.runner.TaskOutcome.FROM_CACHE +import org.gradle.testkit.runner.TaskOutcome.SUCCESS +import org.gradle.testkit.runner.TaskOutcome.UP_TO_DATE +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource + +class TestJvmCacheInputsTest : GradleFixture() { + @ParameterizedTest + @ValueSource(strings = ["vendor", "runtimeVersion", "vmVersion"]) + fun `test cache follows the selected launcher identity`(changedField: String) { + writeSettings( + """ + rootProject.name = "test-jvm-inputs" + buildCache { local { directory = file("task-cache") } } + """ + ) + writeRootProject( + """ + import org.gradle.jvm.toolchain.JavaInstallationMetadata + import org.gradle.jvm.toolchain.JavaLauncher + + plugins { + id("dd-trace-java.test-jvm-constraints") + } + + repositories { mavenCentral() } + dependencies { + testImplementation("org.junit.jupiter:junit-jupiter:5.14.1") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + } + + // Keep the executable and major version fixed to isolate each additional input. + class SelectedLauncher( + private val delegate: JavaLauncher, + private val changedField: String, + ) : JavaLauncher by delegate { + override fun getMetadata(): JavaInstallationMetadata = + object : JavaInstallationMetadata by delegate.metadata { + override fun getVendor() = + if (changedField == "vendor") "different-vendor" else delegate.metadata.vendor + override fun getJavaRuntimeVersion() = + if (changedField == "runtimeVersion") "different-runtime" else delegate.metadata.javaRuntimeVersion + override fun getJvmVersion() = + if (changedField == "vmVersion") "different-vm" else delegate.metadata.jvmVersion + } + } + + val launcher = javaToolchains.launcherFor {} + val changedField = providers.gradleProperty("changedJvmField").orElse("") + tasks.test { + useJUnitPlatform() + javaLauncher.set(launcher.map { SelectedLauncher(it, changedField.get()) }) + } + """ + ) + writeJavaSource( + "ExampleTest", + """ + public class ExampleTest { + @org.junit.jupiter.api.Test + public void passes() {} + } + """, + sourceSet = "test", + ) + + val first = run("test", "--build-cache") + assertThat(first.task(":test")?.outcome).describedAs(first.output).isEqualTo(SUCCESS) + + val unchanged = run("test", "--build-cache") + assertThat(unchanged.task(":test")?.outcome).describedAs(unchanged.output).isEqualTo(UP_TO_DATE) + + val restored = run("cleanTest", "test", "--build-cache") + assertThat(restored.task(":test")?.outcome).describedAs(restored.output).isEqualTo(FROM_CACHE) + + val changed = run("test", "--build-cache", "-PchangedJvmField=$changedField") + assertThat(changed.task(":test")?.outcome).describedAs(changed.output).isEqualTo(SUCCESS) + } +} diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPluginTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPluginTest.kt index 7e353c61579..be600f0eccd 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPluginTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/testJvmConstraints/TestJvmConstraintsPluginTest.kt @@ -34,6 +34,21 @@ class TestJvmConstraintsPluginTest { assertThat(testTask.extensions.findByName(TEST_JVM_CONSTRAINTS)).isInstanceOf(TestJvmConstraintsExtension::class.java) } + @Test + fun `default test launcher is fingerprinted without testJvm`() { + val project = ProjectBuilder.builder().build() + project.pluginManager.apply("dd-trace-java.test-jvm-constraints") + val testTask = project.tasks.named("test", GradleTest::class.java).get() + val metadata = testTask.javaLauncher.get().metadata + + assertThat(testTask.inputs.properties["jvmIdentity"]).isEqualTo(mapOf( + "languageVersion" to metadata.languageVersion.asInt().toString(), + "vendor" to metadata.vendor, + "runtimeVersion" to metadata.javaRuntimeVersion, + "vmVersion" to metadata.jvmVersion, + )) + } + @Test fun `jacoco is disabled for additional test jvm when coverage is not checked`() { val testTask = testTaskWithJacoco() diff --git a/docs/how_to_work_with_gradle.md b/docs/how_to_work_with_gradle.md index 48ae406577c..87c111eaa22 100644 --- a/docs/how_to_work_with_gradle.md +++ b/docs/how_to_work_with_gradle.md @@ -951,6 +951,9 @@ This project provides several custom Gradle extensions to manage multi-JVM testi Controls which JVM versions are allowed to run tests. Applied via the `dd-trace-java.test-jvm-constraints` plugin. +Each `Test` task also tracks its selected JVM's vendor, full runtime version and VM version as inputs. +Changing these values invalidates up-to-date checks and build-cache entries, even when the Java major version stays the same. + ```Gradle Kotlin DSL plugins { id("dd-trace-java.test-jvm-constraints")