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