[MPP] Add intel macOS support and create simulators for the test run
^KT-61439
This commit is contained in:
committed by
Space Team
parent
9d00dfd76e
commit
f20cc10660
@@ -3,6 +3,7 @@ import org.jetbrains.kotlin.pill.PillExtension
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm")
|
kotlin("jvm")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
id("jps-compatible")
|
id("jps-compatible")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,6 +86,7 @@ dependencies {
|
|||||||
testImplementation(kotlinStdlib("jdk8"))
|
testImplementation(kotlinStdlib("jdk8"))
|
||||||
testImplementation(project(":kotlin-parcelize-compiler"))
|
testImplementation(project(":kotlin-parcelize-compiler"))
|
||||||
testImplementation(commonDependency("org.jetbrains.intellij.deps", "trove4j"))
|
testImplementation(commonDependency("org.jetbrains.intellij.deps", "trove4j"))
|
||||||
|
testImplementation(commonDependency("org.jetbrains.kotlinx", "kotlinx-serialization-json"))
|
||||||
testImplementation(libs.ktor.client.cio)
|
testImplementation(libs.ktor.client.cio)
|
||||||
testImplementation(libs.ktor.client.mock)
|
testImplementation(libs.ktor.client.mock)
|
||||||
testImplementation(libs.ktor.server.core)
|
testImplementation(libs.ktor.server.core)
|
||||||
|
|||||||
+68
-36
@@ -5,36 +5,34 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.native
|
package org.jetbrains.kotlin.gradle.native
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
|
import org.jetbrains.kotlin.gradle.util.assertProcessRunResult
|
||||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||||
import org.jetbrains.kotlin.gradle.utils.XcodeUtils
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.junit.jupiter.api.AfterAll
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.condition.OS
|
import org.junit.jupiter.api.condition.OS
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.test.assertEquals
|
import java.util.UUID
|
||||||
|
|
||||||
@DisplayName("tests for the K/N XCode simulator test infrastructure")
|
@DisplayName("tests for the K/N XCode simulator test infrastructure")
|
||||||
@NativeGradlePluginTests
|
@NativeGradlePluginTests
|
||||||
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
||||||
class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
|
class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
|
||||||
private val defaultIosSimulator by lazy {
|
|
||||||
XcodeUtils.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")
|
@DisplayName("A user-friendly error message is produced when the standalone mode is disabled and no simulator has booted")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
fun checkNoSimulatorErrorMessage(gradleVersion: GradleVersion) {
|
fun checkNoSimulatorErrorMessage(gradleVersion: GradleVersion) {
|
||||||
shutDownSimulators() // based on the tests order there no simulator should be booted, but anyway to be sure
|
val unbootedSimulator = createSimulator()
|
||||||
// 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) {
|
project("native-test-ios-https-request", gradleVersion) {
|
||||||
buildGradleKts.append(
|
buildGradleKts.append(
|
||||||
"""
|
"""
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
||||||
device.set("$defaultIosSimulator")
|
device.set("${unbootedSimulator.udid}")
|
||||||
standalone.set(false)
|
standalone.set(false)
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
@@ -60,47 +58,81 @@ class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
|
|||||||
@GradleTest
|
@GradleTest
|
||||||
fun checkSimulatorTestDoesNotFailInNonStandaloneMode(gradleVersion: GradleVersion) {
|
fun checkSimulatorTestDoesNotFailInNonStandaloneMode(gradleVersion: GradleVersion) {
|
||||||
project("native-test-ios-https-request", gradleVersion) {
|
project("native-test-ios-https-request", gradleVersion) {
|
||||||
bootXcodeSimulator(defaultIosSimulator)
|
val simulator = createSimulator()
|
||||||
|
simulator.boot()
|
||||||
buildGradleKts.append(
|
buildGradleKts.append(
|
||||||
"""
|
"""
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
||||||
device.set("$defaultIosSimulator")
|
device.set("${simulator.udid}")
|
||||||
standalone.set(false)
|
standalone.set(false)
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
build("check")
|
build("check") {
|
||||||
|
when (HostManager.host) {
|
||||||
|
KonanTarget.MACOS_ARM64 -> assertTasksExecuted(":iosSimulatorArm64Test")
|
||||||
|
KonanTarget.MACOS_X64 -> assertTasksExecuted(":iosX64Test")
|
||||||
|
else -> error("Unexpected host")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class Device(val name: String, val udid: String)
|
||||||
|
@Serializable
|
||||||
|
private data class Simulators(val devices: Map<String, List<Device>>)
|
||||||
|
|
||||||
|
private val deviceIdentifier = "com.apple.CoreSimulator.SimDeviceType.iPhone-12-Pro-Max"
|
||||||
|
private val uuid = UUID.randomUUID()
|
||||||
|
private val testSimulatorName = "NativeXcodeSimulatorTestsIT_${uuid}_simulator"
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
fun shutDownSimulators() {
|
fun removeSimulatorsCreatedForTests() {
|
||||||
synchronized(bootedXcodeSimulators) {
|
simulators().devices.values.toList().flatMap { it }.filter {
|
||||||
for (device in bootedXcodeSimulators) {
|
it.name == testSimulatorName
|
||||||
val command = listOf("/usr/bin/xcrun", "simctl", "shutdown", device)
|
}.forEach {
|
||||||
val processResult = runProcess(command, File("."))
|
processOutput(
|
||||||
assertEquals(0, processResult.exitCode)
|
listOf("/usr/bin/xcrun", "simctl", "delete", it.udid)
|
||||||
bootedXcodeSimulators.remove(device)
|
)
|
||||||
}
|
|
||||||
bootedXcodeSimulators.clear()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val bootedXcodeSimulators: MutableSet<String> = HashSet()
|
private fun simulators(): Simulators {
|
||||||
|
return Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
}.decodeFromString<Simulators>(
|
||||||
|
processOutput(
|
||||||
|
listOf("/usr/bin/xcrun", "simctl", "list", "devices", "-j")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun bootXcodeSimulator(device: String) {
|
private fun createSimulator(): Device {
|
||||||
synchronized(bootedXcodeSimulators) {
|
return Device(
|
||||||
if (device !in bootedXcodeSimulators) {
|
testSimulatorName,
|
||||||
val command = listOf("/usr/bin/xcrun", "simctl", "boot", device)
|
processOutput(
|
||||||
val processResult = runProcess(command, File("."))
|
listOf("/usr/bin/xcrun", "simctl", "create", testSimulatorName, deviceIdentifier)
|
||||||
assert(processResult.exitCode == 0 || "current state: Booted" in processResult.output) {
|
).dropLast(1)
|
||||||
"Failed to boot a simulator $device and it wasn't started before, exit code = ${processResult.exitCode}"
|
)
|
||||||
}
|
}
|
||||||
if (processResult.exitCode == 0) {
|
|
||||||
// if the simulator was booted not by us, we should not shut it down
|
private fun Device.boot() {
|
||||||
bootedXcodeSimulators.add(device)
|
processOutput(
|
||||||
}
|
listOf("/usr/bin/xcrun", "simctl", "bootstatus", udid, "-bd")
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processOutput(arguments: List<String>): String {
|
||||||
|
val result = runProcess(
|
||||||
|
arguments, File("."),
|
||||||
|
redirectErrorStream = false,
|
||||||
|
)
|
||||||
|
assertProcessRunResult(
|
||||||
|
result
|
||||||
|
) {
|
||||||
|
assert(isSuccessful)
|
||||||
}
|
}
|
||||||
|
return result.output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-2
@@ -31,13 +31,14 @@ fun runProcess(
|
|||||||
cmd: List<String>,
|
cmd: List<String>,
|
||||||
workingDir: File,
|
workingDir: File,
|
||||||
environmentVariables: Map<String, String> = mapOf(),
|
environmentVariables: Map<String, String> = mapOf(),
|
||||||
options: BaseGradleIT.BuildOptions? = null
|
options: BaseGradleIT.BuildOptions? = null,
|
||||||
|
redirectErrorStream: Boolean = true,
|
||||||
): ProcessRunResult {
|
): ProcessRunResult {
|
||||||
val builder = ProcessBuilder(cmd)
|
val builder = ProcessBuilder(cmd)
|
||||||
builder.environment().putAll(environmentVariables)
|
builder.environment().putAll(environmentVariables)
|
||||||
builder.directory(workingDir)
|
builder.directory(workingDir)
|
||||||
// redirectErrorStream merges stdout and stderr, so it can be get from process.inputStream
|
// redirectErrorStream merges stdout and stderr, so it can be get from process.inputStream
|
||||||
builder.redirectErrorStream(true)
|
builder.redirectErrorStream(redirectErrorStream)
|
||||||
|
|
||||||
val process = builder.start()
|
val process = builder.start()
|
||||||
// important to read inputStream, otherwise the process may hang on some systems
|
// important to read inputStream, otherwise the process may hang on some systems
|
||||||
|
|||||||
+8
-2
@@ -8,12 +8,18 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
iosSimulatorArm64() {
|
iosSimulatorArm64 {
|
||||||
|
compilations.all() {
|
||||||
|
compilerOptions.options.apply {
|
||||||
|
optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iosX64 {
|
||||||
compilations.all() {
|
compilations.all() {
|
||||||
compilerOptions.options.apply {
|
compilerOptions.options.apply {
|
||||||
optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
|
optIn.add("kotlinx.cinterop.ExperimentalForeignApi")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user