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 ad792764f41..0db37164519 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 @@ import kotlin.test.assertEquals @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 { + 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 @@ class NativeXcodeSimulatorTestsIT : KGPBaseTest() { @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 { - 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 00000000000..6f0bad0acfc --- /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, + checkExitCode: Boolean, + clientSettings: TCServiceMessagesClientSettings, + dryRunArgs: List?, + private val standaloneMode: Provider, +) : 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 +) : 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 5862a9f5b8d..b929f7d5066 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.api.tasks.options.Option 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 @@ abstract class KotlinNativeTest: KotlinTest() { private val trackedEnvironmentVariablesKeys = mutableSetOf() - private val konanVersion = project.konanVersion - @Suppress("unused") @get:Input val trackedEnvironment @@ -261,4 +259,16 @@ abstract class KotlinNativeSimulatorTest : KotlinNativeTest() { ) + 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