1 package kotlinx.coroutines 2 3 import kotlinx.coroutines.testing.* 4 import org.junit.Test 5 import java.util.concurrent.CountDownLatch 6 import java.util.concurrent.atomic.AtomicReference 7 import kotlin.coroutines.* 8 9 // Stresses scenario from #3613 10 class ReusableCancellableContinuationInvariantStressTest : TestBase() { 11 12 // Tests have a timeout 10 sec because the bug they catch leads to an infinite spin-loop 13 14 @Test(timeout = 10_000) <lambda>null15 fun testExceptionFromSuspendReusable() = doTest { /* nothing */ } 16 17 18 @Test(timeout = 10_000) <lambda>null19 fun testExceptionFromCancelledSuspendReusable() = doTest { it.cancel() } 20 21 22 @Suppress("SuspendFunctionOnCoroutineScope") doTestnull23 private inline fun doTest(crossinline block: (Job) -> Unit) { 24 runTest { 25 repeat(10_000) { 26 val latch = CountDownLatch(1) 27 val continuationToResume = AtomicReference<Continuation<Unit>?>(null) 28 val j1 = launch(Dispatchers.Default) { 29 latch.await() 30 suspendCancellableCoroutineReusable { 31 continuationToResume.set(it) 32 block(coroutineContext.job) 33 throw CancellationException() // Don't let getResult() chance to execute 34 } 35 } 36 37 val j2 = launch(Dispatchers.Default) { 38 latch.await() 39 while (continuationToResume.get() == null) { 40 // spin 41 } 42 continuationToResume.get()!!.resume(Unit) 43 } 44 45 latch.countDown() 46 joinAll(j1, j2) 47 } 48 } 49 } 50 } 51