Skip to content

Commit

Permalink
Don't attempt a pretty stacktrace on runTest timeout
Browse files Browse the repository at this point in the history
  • Loading branch information
dkhalanskyjb committed Feb 17, 2023
1 parent 9fd86bb commit 38f3bab
Show file tree
Hide file tree
Showing 5 changed files with 5 additions and 37 deletions.
25 changes: 5 additions & 20 deletions kotlinx-coroutines-test/common/src/TestBuilders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import kotlin.jvm.*
import kotlin.time.*
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.internal.*

/**
* A test result.
Expand Down Expand Up @@ -309,19 +310,13 @@ public fun TestScope.runTest(
it.start(CoroutineStart.UNDISPATCHED, it) {
testBody()
}
/**
* The thread in which the task was last seen executing.
*/
val lastKnownPosition = MutableStateFlow<Any?>(null)

/**
* We run the tasks in the test coroutine using [Dispatchers.Default]. On JS, this does nothing particularly,
* but on the JVM and Native, this means that the timeout can be processed even while the test runner is busy
* doing some synchronous work.
*/
val workRunner = launch(Dispatchers.Default + CoroutineName("kotlinx.coroutines.test runner")) {
while (true) {
lastKnownPosition.value = getLastKnownPosition()
val executedSomething = testScheduler.tryRunNextTaskUnless { !isActive }
if (executedSomething) {
/** yield to check for cancellation. On JS, we can't use [ensureActive] here, as the cancellation
Expand Down Expand Up @@ -355,19 +350,13 @@ public fun TestScope.runTest(
}
timeoutError = UncompletedCoroutinesError(message)
dumpCoroutines()
/**
* There's a race that may lead to the misleading results here, but it's better than nothing.
* The race: `lastKnownPosition` is read, then the task executed in `workRunner` completes,
* then `updateStacktrace` does its thing, but the thread is already busy doing something else.
*/
updateStacktrace(timeoutError, lastKnownPosition.value)
val cancellationException = CancellationException("The test timed out", timeoutError)
val cancellationException = CancellationException("The test timed out")
(it as Job).cancel(cancellationException)
// we can't abandon the work we're doing, so if it hanged, we'll still hang, despite the timeout.
it.join()
it.getCompletionExceptionOrNull()?.let { exception ->
if (exception !== cancellationException)
timeoutError.addSuppressed(exception)
val completion = it.getCompletionExceptionOrNull()
if (completion != null && completion !== cancellationException) {
timeoutError.addSuppressed(completion)
}
workRunner.cancelAndJoin()
} finally {
Expand Down Expand Up @@ -578,8 +567,4 @@ internal fun throwAll(head: Throwable?, other: List<Throwable>) {
}
}

internal expect fun getLastKnownPosition(): Any?

internal expect fun dumpCoroutines()

internal expect fun updateStacktrace(exception: Throwable, lastKnownPosition: Any?): Throwable
1 change: 0 additions & 1 deletion kotlinx-coroutines-test/common/test/RunTestTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ class RunTestTest {
fn()
fail("shouldn't be reached")
} catch (e: Throwable) {
e.printStackTrace()
assertIs<UncompletedCoroutinesError>(e)
}
}) {
Expand Down
4 changes: 0 additions & 4 deletions kotlinx-coroutines-test/js/src/TestBuilders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,4 @@ internal actual fun createTestResult(testProcedure: suspend CoroutineScope.() ->
testProcedure()
}

internal actual fun getLastKnownPosition(): Any? = null

internal actual fun dumpCoroutines() { }

internal actual fun updateStacktrace(exception: Throwable, lastKnownPosition: Any?): Throwable = exception
8 changes: 0 additions & 8 deletions kotlinx-coroutines-test/jvm/src/TestBuildersJvm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ internal actual fun createTestResult(testProcedure: suspend CoroutineScope.() ->
}
}

internal actual fun getLastKnownPosition(): Any? = Thread.currentThread()

internal actual fun dumpCoroutines() {
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
if (DebugProbesImpl.isInstalled) {
Expand All @@ -29,9 +27,3 @@ internal actual fun dumpCoroutines() {
}
}
}

internal actual fun updateStacktrace(exception: Throwable, lastKnownPosition: Any?): Throwable {
val thread = lastKnownPosition as? Thread
thread?.stackTrace?.let { exception.stackTrace = it }
return exception
}
4 changes: 0 additions & 4 deletions kotlinx-coroutines-test/native/src/TestBuilders.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,4 @@ internal actual fun createTestResult(testProcedure: suspend CoroutineScope.() ->
}
}

internal actual fun getLastKnownPosition(): Any? = null

internal actual fun dumpCoroutines() { }

internal actual fun updateStacktrace(exception: Throwable, lastKnownPosition: Any?): Throwable = exception

0 comments on commit 38f3bab

Please sign in to comment.