Gradle, native: Don't ignore exit codes of K/N tests

Issue #KT-32872 fixed
This commit is contained in:
Ilya Matveev
2019-09-13 20:18:11 +07:00
parent 9d257a1ed8
commit d3f1cf1cdd
2 changed files with 37 additions and 2 deletions
@@ -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 @Test
fun testCinterop() { fun testCinterop() {
val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app") val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
@@ -13,10 +13,13 @@ import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.SkipWhenEmpty import org.gradle.api.tasks.SkipWhenEmpty
import org.gradle.process.ProcessForkOptions import org.gradle.process.ProcessForkOptions
import org.gradle.process.internal.DefaultProcessForkOptions 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.TCServiceMessagesClientSettings
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm
import org.jetbrains.kotlin.gradle.tasks.KotlinTest import org.jetbrains.kotlin.gradle.tasks.KotlinTest
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.MetaVersion
import java.io.File import java.io.File
open class KotlinNativeTest : KotlinTest() { open class KotlinNativeTest : KotlinTest() {
@@ -74,6 +77,12 @@ open class KotlinNativeTest : KotlinTest() {
processOptions.environment(name, value) 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 { override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
val extendedForkOptions = DefaultProcessForkOptions(fileResolver) val extendedForkOptions = DefaultProcessForkOptions(fileResolver)
processOptions.copyTo(extendedForkOptions) processOptions.copyTo(extendedForkOptions)
@@ -87,23 +96,36 @@ open class KotlinNativeTest : KotlinTest() {
stackTraceParser = ::parseKotlinNativeStackTraceAsJvm 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( return TCServiceMessagesTestExecutionSpec(
extendedForkOptions, extendedForkOptions,
cliArgs.toList(), cliArgs.toList(),
false, checkExitCode,
clientSettings clientSettings
) )
} }
private class CliArgs( private class CliArgs(
val testLogger: String? = null, val testLogger: String? = null,
val checkExitCode: Boolean = true,
val testGradleFilter: Set<String> = setOf(), val testGradleFilter: Set<String> = setOf(),
val testNegativeGradleFilter: Set<String> = setOf(), val testNegativeGradleFilter: Set<String> = setOf(),
val userArgs: List<String> = emptyList() val userArgs: List<String> = emptyList()
) { ) {
fun toList() = mutableListOf<String>().also { fun toList() = mutableListOf<String>().also {
if (checkExitCode) {
// Avoid returning a non-zero exit code in case of failed tests.
it.add("--ktest_no_exit_code")
}
if (testLogger != null) { if (testLogger != null) {
it.add("--ktest_logger=$testLogger") it.add("--ktest_logger=$testLogger")
} }