Bug fixed on waitTimeoutOrNull (was flaky testOuterTimeoutTest)
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
index 4e8ada9..afbae4f 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/EventLoop.kt
@@ -154,6 +154,7 @@
private val block: Runnable
) : QueuedTask() {
override fun invoke() { block.run() }
+ override fun toString(): String = block.toString()
}
private abstract inner class DelayedTask(
@@ -176,6 +177,8 @@
}
open fun cancel() {}
+
+ override fun toString(): String = "Delayed[nanos=$nanoTime,seq=$sequence]"
}
private inner class DelayedResumeTask(
@@ -197,5 +200,6 @@
private val block: Runnable
) : DelayedTask(time, timeUnit) {
override fun invoke() { block.run() }
+ override fun toString(): String = super.toString() + block.toString()
}
}
diff --git a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
index 663e14c..54b29dc 100644
--- a/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
+++ b/kotlinx-coroutines-core/src/main/kotlin/kotlinx/coroutines/experimental/Scheduled.kt
@@ -148,7 +148,8 @@
try {
block.startCoroutineUninterceptedOrReturn(completion)
} catch (e: TimeoutException) {
- null // replace inner timeout exception with null result
+ // replace inner timeout exception on our coroutine with null result
+ if (e.coroutine == completion) null else throw e
}
}
}
diff --git a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutOrNullTest.kt b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutOrNullTest.kt
index 66c79a2..0c50eae 100644
--- a/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutOrNullTest.kt
+++ b/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/WithTimeoutOrNullTest.kt
@@ -122,26 +122,35 @@
}
@Test
- fun testOuterTimeoutTest() {
- // stress test this particular case 1000 times
- val nTimes = if (isStressTest) 1000 else 1
- repeat(nTimes) {
- runBlocking {
- var counter = 0
- val result = withTimeoutOrNull(250) {
+ fun testOuterTimeoutTest() = runBlocking {
+ var counter = 0
+ val result = withTimeoutOrNull(250) {
+ while (true) {
+ val inner = withTimeoutOrNull(100) {
while (true) {
- val inner = withTimeoutOrNull(100) {
- while (true) {
- yield()
- }
- }
- assertThat(inner, IsNull())
- counter++
+ yield()
}
}
- assertThat(result, IsNull())
- assertThat(counter, IsEqual(2))
+ assertThat(inner, IsNull())
+ counter++
}
}
+ assertThat(result, IsNull())
+ assertThat(counter, IsEqual(2))
+ }
+
+ @Test
+ fun testOuterTimeoutFiredBeforeInner() = runBlocking<Unit> {
+ val result = withTimeoutOrNull(100) {
+ Thread.sleep(200) // wait enough for outer timeout to fire
+ run(NonCancellable) { yield() } // give an event loop a chance to run and process that cancellation
+ withTimeoutOrNull(100) {
+ yield() // will cancel because of outer timeout
+ expectUnreached()
+ }
+ expectUnreached() // should not be reached, because it is outer timeout
+ }
+ // outer timeout results in null
+ assertThat(result, IsNull())
}
}
\ No newline at end of file