[Gradle, K/N] Improve message when a simulator for test is not booted
If a simulator test task is configured to disable standalone mode and the simulator isn't booted, the default error message might sound cryptic, so we can give a more user-friendly error message
#KT-38317 Fixed
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeXcodeSimulatorTestsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeXcodeSimulatorTestsIT.kt
index ec255e83a..ad57d3a 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeXcodeSimulatorTestsIT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeXcodeSimulatorTestsIT.kt
@@ -21,6 +21,32 @@
@NativeGradlePluginTests
@EnabledOnOs(OS.MAC)
class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
+ private val defaultIosSimulator by lazy {
+ val xcode = Xcode ?: error("XCode is expected to be defined")
+ xcode.getDefaultTestDeviceId(KonanTarget.IOS_SIMULATOR_ARM64) ?: error("No simulator found for iOS ARM64")
+ }
+
+ @DisplayName("A user-friendly error message is produced when the standalone mode is disabled and no simulator has booted")
+ @GradleTest
+ fun checkNoSimulatorErrorMessage(gradleVersion: GradleVersion) {
+ shutDownSimulators() // based on the tests order there no simulator should be booted, but anyway to be sure
+ // Note the test still may fail if you have booted the required simulator manually before running the test
+ // We don't shut down such simulators in the tests
+ project("native-test-ios-https-request", gradleVersion) {
+ buildGradleKts.append(
+ """
+ tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
+ device.set("$defaultIosSimulator")
+ standalone.set(false)
+ }
+ """.trimIndent()
+ )
+ buildAndFail("check") {
+ assertOutputContains("The problem can be that you have not booted the required device or have configured the task to a different simulator. Please check the task output and its device configuration.")
+ }
+ }
+ }
+
@DisplayName("iOS simulator test with an https request fails with default settings")
@GradleTest
fun checkSimulatorTestFailsInStandaloneMode(gradleVersion: GradleVersion) {
@@ -36,13 +62,11 @@
@GradleTest
fun checkSimulatorTestFailsInNonStandaloneMode(gradleVersion: GradleVersion) {
project("native-test-ios-https-request", gradleVersion) {
- val xcode = Xcode ?: error("XCode is expected to be defined")
- val device = xcode.getDefaultTestDeviceId(KonanTarget.IOS_SIMULATOR_ARM64) ?: error("No simulator found for iOS ARM64")
- bootXcodeSimulator(device)
+ bootXcodeSimulator(defaultIosSimulator)
buildGradleKts.append(
"""
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
- device.set("$device")
+ device.set("$defaultIosSimulator")
standalone.set(false)
}
""".trimIndent()
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeAppleSimulatorTCServiceMessagesClient.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeAppleSimulatorTCServiceMessagesClient.kt
new file mode 100644
index 0000000..6f0bad0
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/NativeAppleSimulatorTCServiceMessagesClient.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle.targets.native.internal
+
+import org.gradle.api.internal.tasks.testing.TestResultProcessor
+import org.gradle.api.provider.Provider
+import org.gradle.process.ProcessForkOptions
+import org.gradle.process.internal.ExecHandle
+import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClient
+import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
+import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
+import org.jetbrains.kotlin.gradle.plugin.internal.MppTestReportHelper
+import org.slf4j.Logger
+
+internal class NativeAppleSimulatorTCServiceMessagesTestExecutionSpec(
+ forkOptions: ProcessForkOptions,
+ args: List<String>,
+ checkExitCode: Boolean,
+ clientSettings: TCServiceMessagesClientSettings,
+ dryRunArgs: List<String>?,
+ private val standaloneMode: Provider<Boolean>,
+) : TCServiceMessagesTestExecutionSpec(forkOptions, args, checkExitCode, clientSettings, dryRunArgs) {
+ override fun createClient(
+ testResultProcessor: TestResultProcessor,
+ log: Logger,
+ testReporter: MppTestReportHelper
+ ): TCServiceMessagesClient {
+ return NativeAppleSimulatorTCServiceMessagesClient(testResultProcessor, clientSettings, log, testReporter, standaloneMode)
+ }
+}
+
+internal class NativeAppleSimulatorTCServiceMessagesClient(
+ results: TestResultProcessor,
+ settings: TCServiceMessagesClientSettings,
+ log: Logger,
+ testReporter: MppTestReportHelper,
+ private val standaloneMode: Provider<Boolean>
+) : TCServiceMessagesClient(results, settings, log, testReporter) {
+ override fun testFailedMessage(execHandle: ExecHandle, exitValue: Int) = when {
+ !standaloneMode.get() && exitValue == 149 -> """
+ You have standalone simulator tests run mode disabled and tests have failed to run.
+ The problem can be that you have not booted the required device or have configured the task to a different simulator. Please check the task output and its device configuration.
+ If you are sure that your setup is correct, please file an issue: https://kotl.in/issue
+ """.trimIndent()
+ else -> super.testFailedMessage(execHandle, exitValue)
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt
index 5862a9f..b929f7d 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTest.kt
@@ -16,17 +16,17 @@
import org.gradle.process.ProcessForkOptions
import org.gradle.process.internal.DefaultProcessForkOptions
import org.gradle.work.NormalizeLineEndings
-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.internal.testing.TCServiceMessagesTestExecutor.Companion.TC_PROJECT_PROPERTY
+import org.jetbrains.kotlin.gradle.targets.native.internal.NativeAppleSimulatorTCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
import java.io.File
import java.util.concurrent.Callable
import javax.inject.Inject
-abstract class KotlinNativeTest: KotlinTest() {
+abstract class KotlinNativeTest : KotlinTest() {
@get:Inject
abstract val providerFactory: ProviderFactory
@@ -80,8 +80,6 @@
private val trackedEnvironmentVariablesKeys = mutableSetOf<String>()
- private val konanVersion = project.konanVersion
-
@Suppress("unused")
@get:Input
val trackedEnvironment
@@ -261,4 +259,16 @@
) +
testArgs(testLogger, checkExitCode, testGradleFilter, testNegativeGradleFilter, userArgs)
}
+
+ override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
+ val origin = super.createTestExecutionSpec()
+ return NativeAppleSimulatorTCServiceMessagesTestExecutionSpec(
+ origin.forkOptions,
+ origin.args,
+ origin.checkExitCode,
+ origin.clientSettings,
+ origin.dryRunArgs,
+ standalone,
+ )
+ }
}
\ No newline at end of file