Skip to content

Commit 77e646f

Browse files
committed
Generalize exceptions thrown from 'runWithTimeoutDumpingCoroutines'
1 parent 531d6a1 commit 77e646f

File tree

4 files changed

+22
-22
lines changed

4 files changed

+22
-22
lines changed

kotlinx-coroutines-debug/src/junit/CoroutinesTimeoutImpl.kt

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
package kotlinx.coroutines.debug
66

7-
import org.junit.runners.model.*
87
import java.util.concurrent.*
98

109
/**
@@ -17,6 +16,7 @@ internal inline fun <T : Any?> runWithTimeoutDumpingCoroutines(
1716
methodName: String,
1817
testTimeoutMs: Long,
1918
cancelOnTimeout: Boolean,
19+
initCancellationException: () -> Throwable,
2020
crossinline invocation: () -> T
2121
): T {
2222
val testStartedLatch = CountDownLatch(1)
@@ -35,13 +35,14 @@ internal inline fun <T : Any?> runWithTimeoutDumpingCoroutines(
3535
testStartedLatch.await()
3636
return testResult.get(testTimeoutMs, TimeUnit.MILLISECONDS)
3737
} catch (e: TimeoutException) {
38-
handleTimeout(testThread, methodName, testTimeoutMs, cancelOnTimeout)
38+
handleTimeout(testThread, methodName, testTimeoutMs, cancelOnTimeout, initCancellationException())
3939
} catch (e: ExecutionException) {
4040
throw e.cause ?: e
4141
}
4242
}
4343

44-
private fun handleTimeout(testThread: Thread, methodName: String, testTimeoutMs: Long, cancelOnTimeout: Boolean): Nothing {
44+
private fun handleTimeout(testThread: Thread, methodName: String, testTimeoutMs: Long, cancelOnTimeout: Boolean,
45+
cancellationException: Throwable): Nothing {
4546
val units =
4647
if (testTimeoutMs % 1000 == 0L)
4748
"${testTimeoutMs / 1000} seconds"
@@ -59,10 +60,11 @@ private fun handleTimeout(testThread: Thread, methodName: String, testTimeoutMs:
5960
* 2) Cancel all coroutines via debug agent API (changing system state!)
6061
* 3) Throw created exception
6162
*/
62-
val exception = createTimeoutException(testThread, testTimeoutMs)
63+
cancellationException.attachStacktraceFrom(testThread)
64+
testThread.interrupt()
6365
cancelIfNecessary(cancelOnTimeout)
6466
// If timed out test throws an exception, we can't do much except ignoring it
65-
throw exception
67+
throw cancellationException
6668
}
6769

6870
private fun cancelIfNecessary(cancelOnTimeout: Boolean) {
@@ -73,10 +75,7 @@ private fun cancelIfNecessary(cancelOnTimeout: Boolean) {
7375
}
7476
}
7577

76-
private fun createTimeoutException(thread: Thread, testTimeoutMs: Long): Exception {
78+
private fun Throwable.attachStacktraceFrom(thread: Thread) {
7779
val stackTrace = thread.stackTrace
78-
val exception = TestTimedOutException(testTimeoutMs, TimeUnit.MILLISECONDS)
79-
exception.stackTrace = stackTrace
80-
thread.interrupt()
81-
return exception
80+
this.stackTrace = stackTrace
8281
}

kotlinx-coroutines-debug/src/junit/junit4/CoroutinesTimeoutStatement.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package kotlinx.coroutines.debug.junit4
77
import kotlinx.coroutines.debug.*
88
import org.junit.runner.*
99
import org.junit.runners.model.*
10+
import java.util.concurrent.*
1011

1112
internal class CoroutinesTimeoutStatement(
1213
private val testStatement: Statement,
@@ -17,7 +18,9 @@ internal class CoroutinesTimeoutStatement(
1718

1819
override fun evaluate() {
1920
try {
20-
runWithTimeoutDumpingCoroutines(testDescription.methodName, testTimeoutMs, cancelOnTimeout) {
21+
runWithTimeoutDumpingCoroutines(testDescription.methodName, testTimeoutMs, cancelOnTimeout,
22+
{ TestTimedOutException(testTimeoutMs, TimeUnit.MILLISECONDS) })
23+
{
2124
testStatement.evaluate()
2225
}
2326
} finally {

kotlinx-coroutines-debug/src/junit/junit5/CoroutinesTimeoutExtension.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,9 @@ import org.junit.jupiter.api.extension.ExtensionContext
1010
import org.junit.jupiter.api.extension.InvocationInterceptor
1111
import org.junit.jupiter.api.extension.ReflectiveInvocationContext
1212
import org.junit.platform.commons.support.AnnotationSupport
13-
import org.junit.runners.model.*
1413
import java.lang.reflect.Method
15-
import java.util.concurrent.CountDownLatch
16-
import java.util.concurrent.ExecutionException
17-
import java.util.concurrent.FutureTask
18-
import java.util.concurrent.TimeUnit
19-
import java.util.concurrent.TimeoutException
14+
15+
public class CoroutinesTimeoutException(public val timeoutMs: Long): Exception("test timed out ofter $timeoutMs ms")
2016

2117
public class CoroutinesTimeoutExtension: InvocationInterceptor {
2218

@@ -107,7 +103,9 @@ public class CoroutinesTimeoutExtension: InvocationInterceptor {
107103
DebugProbes.enableCreationStackTraces = annotation.enableCoroutineCreationStackTraces
108104
DebugProbes.install()
109105
return try {
110-
runWithTimeoutDumpingCoroutines(methodName, annotation.testTimeoutMs, annotation.cancelOnTimeout) {
106+
runWithTimeoutDumpingCoroutines(methodName, annotation.testTimeoutMs, annotation.cancelOnTimeout,
107+
{ CoroutinesTimeoutException(annotation.testTimeoutMs) }
108+
) {
111109
invocation.proceed()
112110
}
113111
} finally {

kotlinx-coroutines-debug/test/junit5/CoroutinesTimeoutTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
package junit5
66

7+
import kotlinx.coroutines.debug.junit5.*
78
import org.assertj.core.api.*
89
import org.junit.*
910
import org.junit.platform.engine.discovery.DiscoverySelectors.*
@@ -36,10 +37,9 @@ private fun ListAssert<Event>.testFinishedSuccessfully(testName: String): ListAs
3637
finishedSuccessfully()
3738
))
3839

39-
private fun ListAssert<Event>.testTimedOut(testName: String, after: Int): ListAssert<Event> =
40+
private fun ListAssert<Event>.testTimedOut(testName: String, after: Long): ListAssert<Event> =
4041
haveExactly(1, event(
4142
test(testName),
42-
finishedWithFailure(instanceOf(TestTimedOutException::class.java), message {
43-
it.contains(Regex("\\b$after\\b"))
44-
})
43+
finishedWithFailure(Condition({ it is CoroutinesTimeoutException && it.timeoutMs == after },
44+
"is CoroutinesTimeoutException($after)"))
4545
))

0 commit comments

Comments
 (0)