From 14fc58baf996c23f5ddf2f568fa9875b19b11daf Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Wed, 31 Jan 2024 14:05:37 +0100 Subject: [PATCH 1/3] Enable code coverage collection --- build.gradle.kts | 11 +++++ gradle/libs.versions.toml | 4 ++ .../kotlin/kotlinx/validation/api/TestDsl.kt | 44 ++++++++++++++++++- .../validation/test/MixedMarkersTest.kt | 2 +- .../validation/test/PublicMarkersTest.kt | 2 +- 5 files changed, 60 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index c70df01c..3b464262 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,6 +14,7 @@ plugins { `maven-publish` `jvm-test-suite` id("org.jetbrains.kotlinx.binary-compatibility-validator") + alias(libs.plugins.kover) } group = "org.jetbrains.kotlinx" @@ -195,3 +196,13 @@ testing { tasks.withType().configureEach { onlyIf("only sign if signatory is present") { signatory?.keyId != null } } + +kover { + koverReport { + filters { + excludes { + packages("kotlinx.validation.test") + } + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a605b9f1..bb028625 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,3 +39,7 @@ gradlePlugin-pluginPublishing = { module = "com.gradle.publish:plugin-publish-pl gradlePlugin-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } gradlePlugin-android = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" } ## endregion + +[plugins] + +kover = { id = "org.jetbrains.kotlinx.kover", version = "0.7.5" } diff --git a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt index 831c1a14..cb77642a 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt @@ -8,10 +8,38 @@ package kotlinx.validation.api import kotlinx.validation.ApiValidationExtension import java.io.* import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.internal.DefaultGradleRunner import org.intellij.lang.annotations.Language +import java.lang.management.ManagementFactory public val API_DIR: String = ApiValidationExtension().apiDumpDirectory +private object KoverInterceptor { + val jvmArgs: List by lazy { + val rtBean = ManagementFactory.getRuntimeMXBean() + val jvmArgs = rtBean.inputArguments + + val agent = jvmArgs.find { it.startsWith("-javaagent") && it.endsWith("kover-agent.args") } + if (agent == null) { + return@lazy emptyList() + } + + val coverageArgs = mutableListOf() + coverageArgs.add(agent) + + jvmArgs.forEach { + when { + it.contains("idea.new.tracing.coverage") -> coverageArgs.add(it) + it.contains("idea.coverage") -> coverageArgs.add(it) + } + } + coverageArgs + } + + val coverageEnabled: Boolean + get() = jvmArgs.isNotEmpty() +} + internal fun BaseKotlinGradleTest.test( gradleVersion: String = "8.5", injectPluginClasspath: Boolean = true, @@ -38,6 +66,9 @@ internal fun BaseKotlinGradleTest.test( .withPluginClasspath() .withArguments(baseKotlinScope.runner.arguments) .withGradleVersion(gradleVersion) + + setupCoverage(runner) + if (injectPluginClasspath) { // The hack dating back to https://docs.gradle.org/6.0/userguide/test_kit.html#sub:test-kit-classpath-injection // Currently, some tests won't work without it because some classes are missing on the classpath. @@ -48,6 +79,12 @@ internal fun BaseKotlinGradleTest.test( // .withDebug(baseKotlinScope.runner.debug) } +private fun setupCoverage(runner: GradleRunner) { + if (!KoverInterceptor.coverageEnabled) return + if (runner !is DefaultGradleRunner) throw IllegalStateException("Can't setup coverage params") + runner.withJvmArguments(KoverInterceptor.jvmArgs) +} + /** * same as [file][FileContainer.file], but prepends "src/${sourceSet}/kotlin" before given `classFileName` */ @@ -165,7 +202,12 @@ internal class AppendableScope(val filePath: String) { } internal class Runner { - val arguments: MutableList = mutableListOf("--configuration-cache") + val arguments: MutableList = mutableListOf().apply { + if (!KoverInterceptor.coverageEnabled) { + // Configuration cache is incompatible with javaagents being enabled for Gradle + add("--configuration-cache") + } + } } internal fun readFileList(@Language("file-reference") fileName: String): String { diff --git a/src/functionalTest/kotlin/kotlinx/validation/test/MixedMarkersTest.kt b/src/functionalTest/kotlin/kotlinx/validation/test/MixedMarkersTest.kt index 0c89f317..e97e664a 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/test/MixedMarkersTest.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/test/MixedMarkersTest.kt @@ -31,7 +31,7 @@ class MixedMarkersTest : BaseKotlinGradleTest() { } } - runner.withDebug(true).build().apply { + runner.build().apply { assertTaskSuccess(":apiCheck") } } diff --git a/src/functionalTest/kotlin/kotlinx/validation/test/PublicMarkersTest.kt b/src/functionalTest/kotlin/kotlinx/validation/test/PublicMarkersTest.kt index cf4963b8..e03ee69e 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/test/PublicMarkersTest.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/test/PublicMarkersTest.kt @@ -41,7 +41,7 @@ class PublicMarkersTest : BaseKotlinGradleTest() { } } - runner.withDebug(true).build().apply { + runner.build().apply { assertTaskSuccess(":apiCheck") } } From 36393b6ac0b88f81651aebab71776bb9db8b6264 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Fri, 2 Feb 2024 14:28:32 +0100 Subject: [PATCH 2/3] Use GradleRunner::withDebug to collect the coverage --- build.gradle.kts | 14 ++++++ .../kotlin/kotlinx/validation/api/TestDsl.kt | 45 ++++--------------- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3b464262..1e18b4e0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,4 @@ +import kotlinx.kover.gradle.plugin.dsl.MetricType import kotlinx.validation.build.mavenCentralMetadata import kotlinx.validation.build.mavenRepositoryPublishing import kotlinx.validation.build.signPublicationIfKeyPresent @@ -108,6 +109,7 @@ tasks.compileTestKotlin { tasks.withType().configureEach { systemProperty("overwrite.output", System.getProperty("overwrite.output", "false")) systemProperty("testCasesClassesDirs", sourceSets.test.get().output.classesDirs.asPath) + systemProperty("kover.enabled", project.findProperty("kover.enabled")?.toString().toBoolean()) jvmArgs("-ea") } @@ -204,5 +206,17 @@ kover { packages("kotlinx.validation.test") } } + verify { + rule { + minBound(80, MetricType.BRANCH) + minBound(90, MetricType.LINE) + } + } + } + // Unfortunately, we can't test both configuration cache use and the test coverage + // simultaneously, so the coverage collection should be enabled explicitly (and that + // will disable configuration cache). + if (!project.findProperty("kover.enabled")?.toString().toBoolean()) { + disable() } } diff --git a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt index cb77642a..d486760c 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt @@ -8,37 +8,11 @@ package kotlinx.validation.api import kotlinx.validation.ApiValidationExtension import java.io.* import org.gradle.testkit.runner.GradleRunner -import org.gradle.testkit.runner.internal.DefaultGradleRunner import org.intellij.lang.annotations.Language -import java.lang.management.ManagementFactory public val API_DIR: String = ApiValidationExtension().apiDumpDirectory -private object KoverInterceptor { - val jvmArgs: List by lazy { - val rtBean = ManagementFactory.getRuntimeMXBean() - val jvmArgs = rtBean.inputArguments - - val agent = jvmArgs.find { it.startsWith("-javaagent") && it.endsWith("kover-agent.args") } - if (agent == null) { - return@lazy emptyList() - } - - val coverageArgs = mutableListOf() - coverageArgs.add(agent) - - jvmArgs.forEach { - when { - it.contains("idea.new.tracing.coverage") -> coverageArgs.add(it) - it.contains("idea.coverage") -> coverageArgs.add(it) - } - } - coverageArgs - } - - val coverageEnabled: Boolean - get() = jvmArgs.isNotEmpty() -} +private val koverEnabled: Boolean = System.getProperty("kover.enabled").toBoolean() internal fun BaseKotlinGradleTest.test( gradleVersion: String = "8.5", @@ -67,7 +41,11 @@ internal fun BaseKotlinGradleTest.test( .withArguments(baseKotlinScope.runner.arguments) .withGradleVersion(gradleVersion) - setupCoverage(runner) + if (koverEnabled) { + // In debug mode, tests will be running inside the same JVM. + // That will allow collection coverage info by the Kover. + runner.withDebug(true) + } if (injectPluginClasspath) { // The hack dating back to https://docs.gradle.org/6.0/userguide/test_kit.html#sub:test-kit-classpath-injection @@ -75,14 +53,6 @@ internal fun BaseKotlinGradleTest.test( runner.addPluginTestRuntimeClasspath() } return runner - // disabled because of: https://github.com/gradle/gradle/issues/6862 - // .withDebug(baseKotlinScope.runner.debug) -} - -private fun setupCoverage(runner: GradleRunner) { - if (!KoverInterceptor.coverageEnabled) return - if (runner !is DefaultGradleRunner) throw IllegalStateException("Can't setup coverage params") - runner.withJvmArguments(KoverInterceptor.jvmArgs) } /** @@ -203,8 +173,9 @@ internal class AppendableScope(val filePath: String) { internal class Runner { val arguments: MutableList = mutableListOf().apply { - if (!KoverInterceptor.coverageEnabled) { + if (!koverEnabled) { // Configuration cache is incompatible with javaagents being enabled for Gradle + // See https://github.com/gradle/gradle/issues/6862 add("--configuration-cache") } } From ed7c78c8e4239f448df675a0cfc402f2e10b35a7 Mon Sep 17 00:00:00 2001 From: Filipp Zhinkin Date: Fri, 2 Feb 2024 18:47:24 +0100 Subject: [PATCH 3/3] Updated the link to Gradle issue on java agents support by the TestKit --- src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt index d486760c..cfa25799 100644 --- a/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt +++ b/src/functionalTest/kotlin/kotlinx/validation/api/TestDsl.kt @@ -175,7 +175,7 @@ internal class Runner { val arguments: MutableList = mutableListOf().apply { if (!koverEnabled) { // Configuration cache is incompatible with javaagents being enabled for Gradle - // See https://github.com/gradle/gradle/issues/6862 + // See https://github.com/gradle/gradle/issues/25979 add("--configuration-cache") } }