1 /* 2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 package kotlinx.coroutines.debug 5 6 import kotlinx.coroutines.* 7 import org.junit.Test 8 import java.util.concurrent.* 9 import java.util.concurrent.atomic.AtomicBoolean 10 import kotlin.test.* 11 12 class DebugProbesTest : DebugTestBase() { 13 createDeferrednull14 private fun CoroutineScope.createDeferred(): Deferred<*> = async(NonCancellable) { 15 throw ExecutionException(null) 16 } 17 18 @Test <lambda>null19 fun testAsync() = runTest { 20 val deferred = createDeferred() 21 val traces = listOf( 22 "java.util.concurrent.ExecutionException\n" + 23 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:14)\n" + 24 "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" + 25 "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt:49)\n" + 26 "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt:44)\n" + 27 "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsync\$1.invokeSuspend(DebugProbesTest.kt:17)\n", 28 "Caused by: java.util.concurrent.ExecutionException\n" + 29 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:14)\n" + 30 "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)" 31 ) 32 nestedMethod(deferred, traces) 33 deferred.join() 34 } 35 36 @Test <lambda>null37 fun testAsyncWithProbes() = DebugProbes.withDebugProbes { 38 DebugProbes.sanitizeStackTraces = false 39 runTest { 40 val deferred = createDeferred() 41 val traces = listOf( 42 "java.util.concurrent.ExecutionException\n" + 43 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt)\n" + 44 "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" + 45 "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt)\n" + 46 "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt)\n" + 47 "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:62)\n" + 48 "\tat _COROUTINE._CREATION._(CoroutineDebugging.kt)\n" + 49 "\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt)\n" + 50 "\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt)\n" + 51 "\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable\$default(Cancellable.kt)\n" + 52 "\tat kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt)\n" + 53 "\tat kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt)\n" + 54 "\tat kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt)\n" + 55 "\tat kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)\n" + 56 "\tat kotlinx.coroutines.TestBase.runTest(TestBase.kt)\n" + 57 "\tat kotlinx.coroutines.TestBase.runTest\$default(TestBase.kt)\n" + 58 "\tat kotlinx.coroutines.debug.DebugProbesTest.testAsyncWithProbes(DebugProbesTest.kt)", 59 "Caused by: java.util.concurrent.ExecutionException\n" + 60 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt)\n" + 61 "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt)\n") 62 nestedMethod(deferred, traces) 63 deferred.join() 64 } 65 } 66 67 @Test <lambda>null68 fun testAsyncWithSanitizedProbes() = DebugProbes.withDebugProbes { 69 DebugProbes.sanitizeStackTraces = true 70 runTest { 71 val deferred = createDeferred() 72 val traces = listOf( 73 "java.util.concurrent.ExecutionException\n" + 74 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:16)\n" + 75 "\tat _COROUTINE._BOUNDARY._(CoroutineDebugging.kt)\n" + 76 "\tat kotlinx.coroutines.debug.DebugProbesTest.oneMoreNestedMethod(DebugProbesTest.kt:71)\n" + 77 "\tat kotlinx.coroutines.debug.DebugProbesTest.nestedMethod(DebugProbesTest.kt:66)\n" + 78 "\tat kotlinx.coroutines.debug.DebugProbesTest\$testAsyncWithSanitizedProbes\$1\$1.invokeSuspend(DebugProbesTest.kt:87)\n" + 79 "\tat _COROUTINE._CREATION._(CoroutineDebugging.kt)\n" + 80 "\tat kotlin.coroutines.intrinsics.IntrinsicsKt__IntrinsicsJvmKt.createCoroutineUnintercepted(IntrinsicsJvm.kt:116)\n" + 81 "\tat kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:23)\n" + 82 "\tat kotlinx.coroutines.debug.DebugProbesTest.testAsyncWithSanitizedProbes(DebugProbesTest.kt:38)", 83 "Caused by: java.util.concurrent.ExecutionException\n" + 84 "\tat kotlinx.coroutines.debug.DebugProbesTest\$createDeferred\$1.invokeSuspend(DebugProbesTest.kt:16)\n" + 85 "\tat kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)\n") 86 nestedMethod(deferred, traces) 87 deferred.join() 88 } 89 } 90 nestedMethodnull91 private suspend fun nestedMethod(deferred: Deferred<*>, traces: List<String>) { 92 oneMoreNestedMethod(deferred, traces) 93 assertTrue(true) // Prevent tail-call optimization 94 } 95 oneMoreNestedMethodnull96 private suspend fun oneMoreNestedMethod(deferred: Deferred<*>, traces: List<String>) { 97 try { 98 deferred.await() 99 expectUnreached() 100 } catch (e: ExecutionException) { 101 verifyStackTrace(e, traces) 102 } 103 } 104 105 @Test testMultipleConsecutiveProbeResumednull106 fun testMultipleConsecutiveProbeResumed() = runTest { 107 val job = launch { 108 expect(1) 109 foo() 110 expect(4) 111 delay(Long.MAX_VALUE) 112 expectUnreached() 113 } 114 yield() 115 yield() 116 expect(5) 117 val infos = DebugProbes.dumpCoroutinesInfo() 118 assertEquals(2, infos.size) 119 assertEquals(setOf(State.RUNNING, State.SUSPENDED), infos.map { it.state }.toSet()) 120 job.cancel() 121 finish(6) 122 } 123 124 @Test <lambda>null125 fun testMultipleConsecutiveProbeResumedAndLaterRunning() = runTest { 126 val reachedActiveStage = AtomicBoolean(false) 127 val job = launch(Dispatchers.Default) { 128 expect(1) 129 foo() 130 expect(4) 131 yield() 132 reachedActiveStage.set(true) 133 while (isActive) { 134 // Spin until test is done 135 } 136 } 137 while (!reachedActiveStage.get()) { 138 delay(10) 139 } 140 expect(5) 141 val infos = DebugProbes.dumpCoroutinesInfo() 142 assertEquals(2, infos.size) 143 assertEquals(setOf(State.RUNNING, State.RUNNING), infos.map { it.state }.toSet()) 144 job.cancel() 145 finish(6) 146 } 147 foonull148 private suspend fun foo() { 149 bar() 150 // Kill TCO 151 expect(3) 152 } 153 154 barnull155 private suspend fun bar() { 156 yield() 157 expect(2) 158 } 159 } 160