xref: /aosp_15_r20/external/kotlinx.coroutines/kotlinx-coroutines-debug/test/DebugProbesTest.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)
1 package kotlinx.coroutines.debug
2 
3 import kotlinx.coroutines.testing.*
4 import kotlinx.coroutines.*
5 import org.junit.Test
6 import java.util.concurrent.*
7 import java.util.concurrent.atomic.AtomicBoolean
8 import kotlin.test.*
9 
10 class DebugProbesTest : DebugTestBase() {
11 
createDeferrednull12     private fun CoroutineScope.createDeferred(): Deferred<*> = async(NonCancellable) {
13         throw ExecutionException(null)
14     }
15 
16     @Test
<lambda>null17     fun testAsync() = runTest {
18         val deferred = createDeferred()
19         val traces = listOf(
20             "java.util.concurrent.ExecutionException\n" +
21                 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:14)\n" +
22                 "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" +
23                 "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt:49)\n" +
24                 "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt:44)\n" +
25                 "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsync\$1.invokeSuspend(DebugProbesTest.kt:17)\n",
26             "Caused by: java.util.concurrent.ExecutionException\n" +
27                 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:14)\n" +
28                 "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)"
29         )
30         nestedMethod(deferred, traces)
31         deferred.join()
32     }
33 
34     @Test
<lambda>null35     fun testAsyncWithProbes() = DebugProbes.withDebugProbes {
36         DebugProbes.sanitizeStackTraces = false
37         runTest {
38             val deferred = createDeferred()
39             val traces = listOf(
40                 "java.util.concurrent.ExecutionException\n" +
41                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt)\n" +
42                     "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" +
43                     "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt)\n" +
44                     "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt)\n" +
45                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:62)",
46                 "Caused by: java.util.concurrent.ExecutionException\n" +
47                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt)\n" +
48                     "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt)\n"
49             )
50             nestedMethod(deferred, traces)
51             deferred.join()
52         }
53     }
54 
55     @Test
<lambda>null56     fun testAsyncWithSanitizedProbes() = DebugProbes.withDebugProbes {
57         DebugProbes.sanitizeStackTraces = true
58         runTest {
59             val deferred = createDeferred()
60             val traces = listOf(
61                 "java.util.concurrent.ExecutionException\n" +
62                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:16)\n" +
63                     "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" +
64                     "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt:71)\n" +
65                     "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt:66)\n" +
66                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithSanitizedProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:87)",
67                 "Caused by: java.util.concurrent.ExecutionException\n" +
68                     "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:16)\n" +
69                     "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)\n"
70             )
71             nestedMethod(deferred, traces)
72             deferred.join()
73         }
74     }
75 
nestedMethodnull76     private suspend fun nestedMethod(deferred: Deferred<*>, traces: List<String>) {
77         oneMoreNestedMethod(deferred, traces)
78         assertTrue(true) // Prevent tail-call optimization
79     }
80 
oneMoreNestedMethodnull81     private suspend fun oneMoreNestedMethod(deferred: Deferred<*>, traces: List<String>) {
82         try {
83             deferred.await()
84             expectUnreached()
85         } catch (e: ExecutionException) {
86             verifyStackTrace(e, traces)
87         }
88     }
89 
90     @Test
testMultipleConsecutiveProbeResumednull91     fun testMultipleConsecutiveProbeResumed() = runTest {
92         val job = launch {
93             expect(1)
94             foo()
95             expect(4)
96             delay(Long.MAX_VALUE)
97             expectUnreached()
98         }
99         yield()
100         yield()
101         expect(5)
102         val infos = DebugProbes.dumpCoroutinesInfo()
103         assertEquals(2, infos.size)
104         assertEquals(setOf(State.RUNNING, State.SUSPENDED), infos.map { it.state }.toSet())
105         job.cancel()
106         finish(6)
107     }
108 
109     @Test
<lambda>null110     fun testMultipleConsecutiveProbeResumedAndLaterRunning() = runTest {
111         val reachedActiveStage = AtomicBoolean(false)
112         val job = launch(Dispatchers.Default) {
113             expect(1)
114             foo()
115             expect(4)
116             yield()
117             reachedActiveStage.set(true)
118             while (isActive) {
119                 // Spin until test is done
120             }
121         }
122         while (!reachedActiveStage.get()) {
123             delay(10)
124         }
125         expect(5)
126         val infos = DebugProbes.dumpCoroutinesInfo()
127         assertEquals(2, infos.size)
128         assertEquals(setOf(State.RUNNING, State.RUNNING), infos.map { it.state }.toSet())
129         job.cancel()
130         finish(6)
131     }
132 
foonull133     private suspend fun foo() {
134         bar()
135         // Kill TCO
136         expect(3)
137     }
138 
139 
barnull140     private suspend fun bar() {
141         yield()
142         expect(2)
143     }
144 }
145