Skip to content

Commit

Permalink
Reproduce symbolic link dSYM output in archive task
Browse files Browse the repository at this point in the history
^KT-71423
  • Loading branch information
timofey-solonin authored and qodana-bot committed Sep 25, 2024
1 parent 2e3370f commit 6b28b52
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ package org.jetbrains.kotlin.gradle.apple

import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.replaceText
import org.jetbrains.kotlin.gradle.util.runProcess
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.condition.OS
import org.junit.jupiter.api.extension.ExtensionContext
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.Arguments
import org.junit.jupiter.params.provider.ArgumentsSource
import java.io.File
import java.util.stream.Stream
import kotlin.io.path.isSymbolicLink
import kotlin.test.assertEquals

@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
@DisplayName("Tests for Xcode <-> Kotlin direct integration")
Expand All @@ -22,33 +27,99 @@ class XcodeDirectIntegrationIT : KGPBaseTest() {

@DisplayName("Xcode direct integration")
@ParameterizedTest(name = "{displayName} with {1}, {0} and isStatic={2}")
@ArgumentsSource(XcodeArgumentsProvider::class)
@ArgumentsSource(DirectIntegrationTestArgumentsProvider::class)
fun test(
gradleVersion: GradleVersion,
iosApp: String,
isStatic: Boolean,
) {

project("xcodeDirectIntegration", gradleVersion) {

projectPath.resolve("shared/build.gradle.kts")
.modify { it.replace(".framework {", ".framework {\n isStatic = $isStatic") }

buildXcodeProject(xcodeproj = projectPath.resolve("iosApp$iosApp/iosApp.xcodeproj"))
projectPath
.resolve("shared/build.gradle.kts")
.replaceText("<is_static>", if (isStatic) "true" else "false")
buildXcodeProject(
xcodeproj = projectPath.resolve("iosApp$iosApp/iosApp.xcodeproj"),
)
}
}


internal class XcodeArgumentsProvider : GradleArgumentsProvider() {
internal class DirectIntegrationTestArgumentsProvider : GradleArgumentsProvider() {
override fun provideArguments(context: ExtensionContext): Stream<out Arguments> {
return super.provideArguments(context).flatMap { arguments ->
val gradleVersion = arguments.get().first()
Stream.of("BuildPhase", "SchemePreAction", "SchemePreActionSpm").flatMap { iosApp ->
Stream.of(BuildPhase, SchemePreAction, SchemePreActionSpm).flatMap { iosApp ->
Stream.of(true, false).map { isStatic ->
Arguments.of(gradleVersion, iosApp, isStatic)
}
}
}
}
}

@DisplayName("Xcode archiving")
@ParameterizedTest(name = "{displayName} with {0} and isStatic={1}")
@ArgumentsSource(ArchivingTestArgumentsProvider::class)
fun testArchiving(
gradleVersion: GradleVersion,
isStatic: Boolean,
) {
project("xcodeDirectIntegration", gradleVersion) {
projectPath.resolve("shared/build.gradle.kts")
.replaceText("<is_static>", if (isStatic) "true" else "false")

val archivePath = projectPath.resolve("archive.xcarchive")
buildXcodeProject(
xcodeproj = projectPath.resolve("iosApp$BuildPhase/iosApp.xcodeproj"),
action = XcodeBuildAction.Archive(archivePath.toFile().path),
)

// Sanity check
assertFileExists(archivePath.resolve("Products/Applications/iosApp.app/iosApp"))
assertDirectoryExists(archivePath.resolve("dSYMs/iosApp.app.dSYM"))

val frameworkPath = archivePath.resolve("Products/Applications/iosApp.app/Frameworks/shared.framework")
val dsymPath = archivePath.resolve("dSYMs/shared.framework.dSYM")

if (isStatic) {
assertDirectoryDoesNotExist(frameworkPath)
assertDirectoryDoesNotExist(dsymPath)
} else {
assertDirectoryExists(frameworkPath)
assert(!frameworkPath.isSymbolicLink()) { "${frameworkPath} is a symbolic link" }
assertDirectoryExists(dsymPath)
assert(dsymPath.isSymbolicLink()) { "${dsymPath} is a symbolic link" }

fun dumpUuid(binary: File): List<String> {
return runProcess(listOf("otool", "-l", binary.path), projectPath.toFile())
.output.lines().filter { it.contains("uuid") }
}

val frameworkUuids = dumpUuid(frameworkPath.resolve("shared").toFile())
val dsymUuids = dumpUuid(dsymPath.resolve("Contents/Resources/DWARF/shared").toFile())

assert(!frameworkUuids.isEmpty())
assertEquals(frameworkUuids, dsymUuids)
}
}
}

internal class ArchivingTestArgumentsProvider : GradleArgumentsProvider() {
override fun provideArguments(context: ExtensionContext): Stream<out Arguments> {
return super.provideArguments(context).flatMap { arguments ->
val gradleVersion = arguments.get().first()
Stream.of(
// true,
false,
).map { isStatic ->
Arguments.of(gradleVersion, isStatic)
}
}
}
}

private companion object {
val BuildPhase = "BuildPhase"
val SchemePreAction = "SchemePreAction"
val SchemePreActionSpm = "SchemePreActionSpm"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class XcodeDirectIntegrationUpgradeSequenceIT : KGPBaseTest() {
xcodeproj = projectPath.resolve("iosApp/iosApp.xcodeproj"),
scheme = "iosAppTests",
destination = "id=${simulatorUdid}",
buildMode = XcodeBuildMode.TEST,
action = XcodeBuildAction.Test,
testRunEnvironment = mapOf(
"EXPECTED_TEST_VALUE" to expectedValue
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class SwiftExportXCIT : KGPBaseTest() {
buildXcodeProject(
xcodeproj = projectPath.resolve("iosApp/iosApp.xcodeproj"),
destination = "platform=iOS Simulator,id=${simulator.udid}",
buildMode = XcodeBuildMode.TEST,
action = XcodeBuildAction.Test,
appendToProperties = { "kotlin.experimental.swift-export.enabled=true" }
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@
package org.jetbrains.kotlin.gradle.testbase

import org.jetbrains.kotlin.gradle.KOTLIN_VERSION
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinDefaultHierarchyFallbackDependsOnUsageDetected.onlyIf
import org.jetbrains.kotlin.gradle.util.assertProcessRunResult
import org.jetbrains.kotlin.gradle.util.modify
import org.jetbrains.kotlin.gradle.util.runProcess
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.test.assertEquals

internal enum class XcodeBuildMode {
BUILD,
TEST
internal sealed class XcodeBuildAction(
val action: String,
) {
object Build : XcodeBuildAction("build")
object Test : XcodeBuildAction("test")
class Archive(val archivePath: String) : XcodeBuildAction("archive")
}

internal fun TestProject.buildXcodeProject(
Expand All @@ -25,7 +27,7 @@ internal fun TestProject.buildXcodeProject(
configuration: String = "Debug",
destination: String = "generic/platform=iOS Simulator",
sdk: String = "iphonesimulator",
buildMode: XcodeBuildMode = XcodeBuildMode.BUILD,
action: XcodeBuildAction = XcodeBuildAction.Build,
testRunEnvironment: Map<String, String> = emptyMap(),
buildSettingOverrides: Map<String, String> = emptyMap(),
appendToProperties: () -> String = { "" },
Expand All @@ -39,7 +41,7 @@ internal fun TestProject.buildXcodeProject(
configuration = configuration,
sdk = sdk,
destination = destination,
buildMode = buildMode,
action = action,
buildSettingOverrides = buildSettingOverrides,
testRunEnvironment = testRunEnvironment,
expectedExitCode = expectedExitCode,
Expand All @@ -55,7 +57,7 @@ internal fun TestProject.xcodebuild(
sdk: String? = null,
arch: String? = null,
destination: String? = null,
buildMode: XcodeBuildMode = XcodeBuildMode.BUILD,
action: XcodeBuildAction = XcodeBuildAction.Build,
testRunEnvironment: Map<String, String> = emptyMap(),
buildSettingOverrides: Map<String, String> = emptyMap(),
derivedDataPath: Path? = projectPath.resolve("xcodeDerivedData"),
Expand All @@ -77,6 +79,7 @@ internal fun TestProject.xcodebuild(
}

add("xcodebuild")
add(action.action)
"-project" set xcodeproj
"-workspace" set workspace
"-scheme" set scheme
Expand All @@ -86,15 +89,21 @@ internal fun TestProject.xcodebuild(
"-destination" set destination
"-derivedDataPath" set derivedDataPath

buildSettingOverrides.forEach {
it.key eq it.value
when (action) {
is XcodeBuildAction.Build -> {}
is XcodeBuildAction.Test -> {
// Disable parallel testing to output stdout/stderr from tests to xcodebuild
add("-parallel-testing-enabled")
add("NO")
}
is XcodeBuildAction.Archive -> {
add("-archivePath")
add(action.archivePath)
}
}

if (buildMode == XcodeBuildMode.TEST) {
// Disable parallel testing to output stdout/stderr from tests to xcodebuild
add("-parallel-testing-enabled")
add("NO")
add("test")
buildSettingOverrides.forEach {
it.key eq it.value
}
},
workingDir = workingDir,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ kotlin {
iosSimulatorArm64()
).forEach {
it.binaries.framework {
isStatic = <is_static>
baseName = "shared"
}
}
Expand Down

0 comments on commit 6b28b52

Please sign in to comment.