package kotlinx.coroutines import kotlinx.coroutines.testing.* import org.junit.Test import java.util.concurrent.CountDownLatch import java.util.concurrent.atomic.AtomicReference import kotlin.coroutines.* // Stresses scenario from #3613 class ReusableCancellableContinuationInvariantStressTest : TestBase() { // Tests have a timeout 10 sec because the bug they catch leads to an infinite spin-loop @Test(timeout = 10_000) fun testExceptionFromSuspendReusable() = doTest { /* nothing */ } @Test(timeout = 10_000) fun testExceptionFromCancelledSuspendReusable() = doTest { it.cancel() } @Suppress("SuspendFunctionOnCoroutineScope") private inline fun doTest(crossinline block: (Job) -> Unit) { runTest { repeat(10_000) { val latch = CountDownLatch(1) val continuationToResume = AtomicReference?>(null) val j1 = launch(Dispatchers.Default) { latch.await() suspendCancellableCoroutineReusable { continuationToResume.set(it) block(coroutineContext.job) throw CancellationException() // Don't let getResult() chance to execute } } val j2 = launch(Dispatchers.Default) { latch.await() while (continuationToResume.get() == null) { // spin } continuationToResume.get()!!.resume(Unit) } latch.countDown() joinAll(j1, j2) } } } }