From d3f1cf1cdde3f95e71b595db80823105383dee93 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Fri, 13 Sep 2019 20:18:11 +0700 Subject: [PATCH] Gradle, native: Don't ignore exit codes of K/N tests Issue #KT-32872 fixed --- .../kotlin/gradle/NewMultiplatformIT.kt | 13 ++++++++++ .../targets/native/tasks/KotlinNativeTest.kt | 26 +++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index d9ac056848e..171ecf75e49 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -1307,6 +1307,19 @@ class NewMultiplatformIT : BaseGradleIT() { } } + @Test + fun kt33750() { + // Check that build fails if a test executable crashes. + with(Project("new-mpp-native-tests", gradleVersion)) { + setupWorkingDir() + projectDir.resolve("src/commonTest/kotlin/test.kt").appendText("\nval fail: Int = error(\"\")\n") + build("check") { + assertFailed() + output.contains("exited with errors \\(exit code: \\d+\\)".toRegex()) + } + } + } + @Test fun testCinterop() { val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt index 6484d2225f7..be87a411d5c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt @@ -13,10 +13,13 @@ import org.gradle.api.tasks.Internal import org.gradle.api.tasks.SkipWhenEmpty import org.gradle.process.ProcessForkOptions import org.gradle.process.internal.DefaultProcessForkOptions +import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm import org.jetbrains.kotlin.gradle.tasks.KotlinTest +import org.jetbrains.kotlin.konan.KonanVersion +import org.jetbrains.kotlin.konan.MetaVersion import java.io.File open class KotlinNativeTest : KotlinTest() { @@ -74,6 +77,12 @@ open class KotlinNativeTest : KotlinTest() { processOptions.environment(name, value) } + // KonanVersion doesn't provide an API to compare versions, + // so we have to transform it to KotlinVersion first. + // Note: this check doesn't take into account the meta version (release, eap, dev). + private fun KonanVersion.isAtLeast(major: Int, minor: Int, patch: Int): Boolean = + KotlinVersion(this.major, this.minor, this.maintenance).isAtLeast(major, minor, patch) + override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec { val extendedForkOptions = DefaultProcessForkOptions(fileResolver) processOptions.copyTo(extendedForkOptions) @@ -87,23 +96,36 @@ open class KotlinNativeTest : KotlinTest() { stackTraceParser = ::parseKotlinNativeStackTraceAsJvm ) - val cliArgs = CliArgs("TEAMCITY", includePatterns, excludePatterns, args) + // The KotlinTest expects that the exit code is zero even if some tests failed. + // In this case it can check exit code and distinguish test failures from crashes. + // But K/N allows forcing a zero exit code only since 1.3 (which was included in Kotlin 1.3.40). + // Thus we check the exit code only for newer versions. + val checkExitCode = project.konanVersion.isAtLeast(1, 3, 0) + + val cliArgs = CliArgs("TEAMCITY", checkExitCode, includePatterns, excludePatterns, args) return TCServiceMessagesTestExecutionSpec( extendedForkOptions, cliArgs.toList(), - false, + checkExitCode, clientSettings ) } private class CliArgs( val testLogger: String? = null, + val checkExitCode: Boolean = true, val testGradleFilter: Set = setOf(), val testNegativeGradleFilter: Set = setOf(), val userArgs: List = emptyList() ) { fun toList() = mutableListOf().also { + + if (checkExitCode) { + // Avoid returning a non-zero exit code in case of failed tests. + it.add("--ktest_no_exit_code") + } + if (testLogger != null) { it.add("--ktest_logger=$testLogger") }