• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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