KT-65582 Extract xcode simulator test helpers
This commit is contained in:
committed by
Space Team
parent
6ed6e7ce28
commit
444dc790db
+24
-84
@@ -5,20 +5,12 @@
|
|||||||
|
|
||||||
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.konan.target.HostManager
|
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.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.util.UUID
|
|
||||||
|
|
||||||
@DisplayName("tests for the K/N XCode simulator test infrastructure")
|
@DisplayName("tests for the K/N XCode simulator test infrastructure")
|
||||||
@NativeGradlePluginTests
|
@NativeGradlePluginTests
|
||||||
@@ -27,18 +19,20 @@ class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
|
|||||||
@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) {
|
||||||
val unbootedSimulator = createSimulator()
|
XCTestHelpers().use {
|
||||||
project("native-test-ios-https-request", gradleVersion) {
|
val unbootedSimulator = it.createSimulator()
|
||||||
buildGradleKts.append(
|
project("native-test-ios-https-request", gradleVersion) {
|
||||||
"""
|
buildGradleKts.append(
|
||||||
|
"""
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
||||||
device.set("${unbootedSimulator.udid}")
|
device.set("${unbootedSimulator.udid}")
|
||||||
standalone.set(false)
|
standalone.set(false)
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
buildAndFail("check") {
|
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.")
|
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.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,82 +51,28 @@ class NativeXcodeSimulatorTestsIT : KGPBaseTest() {
|
|||||||
@DisplayName("iOS simulator test with an https request doesn't fail with the standalone mode disabled")
|
@DisplayName("iOS simulator test with an https request doesn't fail with the standalone mode disabled")
|
||||||
@GradleTest
|
@GradleTest
|
||||||
fun checkSimulatorTestDoesNotFailInNonStandaloneMode(gradleVersion: GradleVersion) {
|
fun checkSimulatorTestDoesNotFailInNonStandaloneMode(gradleVersion: GradleVersion) {
|
||||||
project("native-test-ios-https-request", gradleVersion) {
|
XCTestHelpers().use {
|
||||||
val simulator = createSimulator()
|
val simulator = it.createSimulator().apply {
|
||||||
simulator.boot()
|
boot()
|
||||||
buildGradleKts.append(
|
}
|
||||||
"""
|
|
||||||
|
project("native-test-ios-https-request", gradleVersion) {
|
||||||
|
buildGradleKts.append(
|
||||||
|
"""
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest> {
|
||||||
device.set("${simulator.udid}")
|
device.set("${simulator.udid}")
|
||||||
standalone.set(false)
|
standalone.set(false)
|
||||||
}
|
}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
build("check") {
|
build("check") {
|
||||||
when (HostManager.host) {
|
when (HostManager.host) {
|
||||||
KonanTarget.MACOS_ARM64 -> assertTasksExecuted(":iosSimulatorArm64Test")
|
KonanTarget.MACOS_ARM64 -> assertTasksExecuted(":iosSimulatorArm64Test")
|
||||||
KonanTarget.MACOS_X64 -> assertTasksExecuted(":iosX64Test")
|
KonanTarget.MACOS_X64 -> assertTasksExecuted(":iosX64Test")
|
||||||
else -> error("Unexpected host")
|
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
|
|
||||||
fun removeSimulatorsCreatedForTests() {
|
|
||||||
simulators().devices.values.toList().flatMap { it }.filter {
|
|
||||||
it.name == testSimulatorName
|
|
||||||
}.forEach {
|
|
||||||
processOutput(
|
|
||||||
listOf("/usr/bin/xcrun", "simctl", "delete", it.udid)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun simulators(): Simulators {
|
|
||||||
return Json {
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
}.decodeFromString<Simulators>(
|
|
||||||
processOutput(
|
|
||||||
listOf("/usr/bin/xcrun", "simctl", "list", "devices", "-j")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createSimulator(): Device {
|
|
||||||
return Device(
|
|
||||||
testSimulatorName,
|
|
||||||
processOutput(
|
|
||||||
listOf("/usr/bin/xcrun", "simctl", "create", testSimulatorName, deviceIdentifier)
|
|
||||||
).dropLast(1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Device.boot() {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+30
-4
@@ -12,12 +12,19 @@ import java.nio.file.Path
|
|||||||
import kotlin.io.path.exists
|
import kotlin.io.path.exists
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
internal enum class XcodeBuildMode {
|
||||||
|
NORMAL,
|
||||||
|
TEST
|
||||||
|
}
|
||||||
|
|
||||||
fun TestProject.buildXcodeProject(
|
internal fun TestProject.buildXcodeProject(
|
||||||
xcodeproj: Path,
|
xcodeproj: Path,
|
||||||
scheme: String = "iosApp",
|
scheme: String = "iosApp",
|
||||||
configuration: String = "Debug",
|
configuration: String = "Debug",
|
||||||
destination: String = "generic/platform=iOS Simulator"
|
destination: String = "generic/platform=iOS Simulator",
|
||||||
|
sdk: String = "iphonesimulator",
|
||||||
|
buildMode: XcodeBuildMode = XcodeBuildMode.NORMAL,
|
||||||
|
extraArguments: Map<String, Any> = emptyMap(),
|
||||||
) {
|
) {
|
||||||
prepareForXcodebuild()
|
prepareForXcodebuild()
|
||||||
|
|
||||||
@@ -25,11 +32,14 @@ fun TestProject.buildXcodeProject(
|
|||||||
xcodeproj = xcodeproj,
|
xcodeproj = xcodeproj,
|
||||||
scheme = scheme,
|
scheme = scheme,
|
||||||
configuration = configuration,
|
configuration = configuration,
|
||||||
|
sdk = sdk,
|
||||||
destination = destination,
|
destination = destination,
|
||||||
|
buildMode = buildMode,
|
||||||
|
extraArguments = extraArguments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TestProject.xcodebuild(
|
internal fun TestProject.xcodebuild(
|
||||||
workingDir: Path = projectPath,
|
workingDir: Path = projectPath,
|
||||||
xcodeproj: Path? = null,
|
xcodeproj: Path? = null,
|
||||||
workspace: Path? = null,
|
workspace: Path? = null,
|
||||||
@@ -38,6 +48,8 @@ fun TestProject.xcodebuild(
|
|||||||
sdk: String? = null,
|
sdk: String? = null,
|
||||||
arch: String? = null,
|
arch: String? = null,
|
||||||
destination: String? = null,
|
destination: String? = null,
|
||||||
|
buildMode: XcodeBuildMode = XcodeBuildMode.NORMAL,
|
||||||
|
extraArguments: Map<String, Any> = emptyMap(),
|
||||||
derivedDataPath: Path? = projectPath.resolve("xcodeDerivedData"),
|
derivedDataPath: Path? = projectPath.resolve("xcodeDerivedData"),
|
||||||
) {
|
) {
|
||||||
xcodebuild(
|
xcodebuild(
|
||||||
@@ -49,6 +61,12 @@ fun TestProject.xcodebuild(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infix fun String.eq(value: Any?) {
|
||||||
|
if (value != null) {
|
||||||
|
add("${this}=$value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
add("xcodebuild")
|
add("xcodebuild")
|
||||||
"-project" set xcodeproj
|
"-project" set xcodeproj
|
||||||
"-workspace" set workspace
|
"-workspace" set workspace
|
||||||
@@ -58,12 +76,20 @@ fun TestProject.xcodebuild(
|
|||||||
"-arch" set arch
|
"-arch" set arch
|
||||||
"-destination" set destination
|
"-destination" set destination
|
||||||
"-derivedDataPath" set derivedDataPath
|
"-derivedDataPath" set derivedDataPath
|
||||||
|
|
||||||
|
extraArguments.forEach {
|
||||||
|
it.key eq it.value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildMode == XcodeBuildMode.TEST) {
|
||||||
|
add("test")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
workingDir,
|
workingDir,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TestProject.prepareForXcodebuild() {
|
internal fun TestProject.prepareForXcodebuild() {
|
||||||
overrideMavenLocalIfNeeded()
|
overrideMavenLocalIfNeeded()
|
||||||
|
|
||||||
gradleProperties
|
gradleProperties
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.testbase
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import org.jetbrains.kotlin.gradle.util.assertProcessRunResult
|
||||||
|
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||||
|
import java.io.Closeable
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
internal class XCTestHelpers : Closeable {
|
||||||
|
@Serializable
|
||||||
|
data class Device(val name: String, val udid: String)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
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"
|
||||||
|
|
||||||
|
fun createSimulator(): Device {
|
||||||
|
return Device(
|
||||||
|
testSimulatorName,
|
||||||
|
processOutput(
|
||||||
|
listOf("/usr/bin/xcrun", "simctl", "create", testSimulatorName, deviceIdentifier)
|
||||||
|
).dropLast(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val json = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun simulators(): Simulators {
|
||||||
|
return json.decodeFromString<Simulators>(
|
||||||
|
processOutput(
|
||||||
|
listOf("/usr/bin/xcrun", "simctl", "list", "devices", "-j")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
simulators().devices.values.toList().flatten().filter {
|
||||||
|
it.name == testSimulatorName
|
||||||
|
}.forEach {
|
||||||
|
processOutput(
|
||||||
|
listOf("/usr/bin/xcrun", "simctl", "delete", it.udid)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun XCTestHelpers.Device.boot() {
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user