33 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
44 */
55
6+ @file:OptIn(ExperimentalAtomicApi ::class )
7+
68package org.jetbrains.kotlin.native.executors
79
810import org.jetbrains.kotlin.konan.target.AppleConfigurables
911import org.jetbrains.kotlin.konan.target.HostManager
1012import org.jetbrains.kotlin.konan.target.KonanTarget
1113import org.jetbrains.kotlin.util.removeSuffixIfPresent
1214import java.io.ByteArrayOutputStream
15+ import java.io.PrintStream
1316import java.nio.file.*
1417import java.util.zip.ZipEntry
1518import java.util.zip.ZipOutputStream
19+ import kotlin.concurrent.atomics.AtomicReference
20+ import kotlin.concurrent.atomics.ExperimentalAtomicApi
1621import kotlin.io.path.*
1722import kotlin.time.Duration.Companion.minutes
1823import kotlin.time.Duration.Companion.seconds
@@ -34,13 +39,7 @@ class FirebaseCloudXCTestExecutor(
3439
3540 private val target by configurables::target
3641
37- private enum class State {
38- NORMAL ,
39- FAILED
40- }
41-
42- @Volatile
43- private var state: State = State .NORMAL
42+ private val rememberedFailure = AtomicReference <Throwable ?>(null )
4443
4544 init {
4645 require(HostManager .host.family.isAppleFamily) {
@@ -51,16 +50,29 @@ class FirebaseCloudXCTestExecutor(
5150 }
5251 }
5352
54- @Synchronized
55- private fun checkState () {
56- check(state == State .NORMAL ) {
57- " ${this ::class .java.simpleName} is in the ${state.name} state. Check the executor logs and configuration"
53+ private fun abortWithFailureIfNeeded () {
54+ rememberedFailure.load()?.let { failure ->
55+ // The usual stack trace reporting is too verbose. Produce a compact report as the message instead
56+ fun StringBuilder.appendThrowable (t : Throwable ) {
57+ appendLine(t.toString())
58+ when (val cause = t.cause) {
59+ null -> append(t.stackTraceToString())
60+ else -> {
61+ t.stackTrace.firstOrNull()?.let { appendLine(" \t at $it " ) }
62+ append(" Caused by: " )
63+ appendThrowable(cause)
64+ }
65+ }
66+ }
67+ error(buildString {
68+ appendThrowable(failure)
69+ })
5870 }
5971 }
6072
6173 override fun execute (request : ExecuteRequest ): ExecuteResponse {
6274 // Check the state to understand whether it is possible to build or some config/build failure happened already.
63- checkState ()
75+ abortWithFailureIfNeeded ()
6476
6577 val workDir = request.workingDirectory?.toPath() ? : Paths .get(" ." )
6678 val projectDir = Files .createTempDirectory(workDir, " xctest-firebase-runner" )
@@ -73,8 +85,14 @@ class FirebaseCloudXCTestExecutor(
7385 createZip(bundle.prepareToRun(projectDir))
7486 }
7587 } catch (throwable: Throwable ) {
76- state = State .FAILED
77- throw IllegalStateException (" Failed to prepare a XCTest bundle with Xcode. Check Xcode or project configuration" , throwable)
88+ rememberedFailure.compareAndSet(
89+ null ,
90+ IllegalStateException (
91+ " Failed to prepare a XCTest bundle with Xcode. Check Xcode or project configuration" ,
92+ throwable
93+ )
94+ )
95+ abortWithFailureIfNeeded()
7896 }
7997
8098 // Execute tests in the Firebase
0 commit comments