1 @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") 2 package kotlinx.coroutines.debug 3 4 import kotlinx.coroutines.testing.* 5 import com.google.gson.* 6 import kotlinx.coroutines.* 7 import kotlinx.coroutines.debug.internal.* 8 import org.junit.Test 9 import kotlin.coroutines.* 10 import kotlin.test.* 11 12 @ExperimentalStdlibApi 13 class DumpCoroutineInfoAsJsonAndReferencesTest : DebugTestBase() { 14 private data class CoroutineInfoFromJson( 15 val name: String?, 16 val id: Long?, 17 val dispatcher: String?, 18 val sequenceNumber: Long?, 19 val state: String? 20 ) 21 22 @Test testDumpOfUnnamedCoroutinenull23 fun testDumpOfUnnamedCoroutine() = 24 runTestWithNamedDeferred(name = null) 25 26 @Test 27 fun testDumpOfNamedCoroutine() = 28 runTestWithNamedDeferred("Name") 29 30 @Test 31 fun testDumpOfNamedCoroutineWithSpecialCharacters() = 32 runTestWithNamedDeferred("Name with\n \"special\" characters\\/\t\b") 33 34 @Test 35 fun testDumpWithNoCoroutines() { 36 val dumpResult = DebugProbesImpl.dumpCoroutinesInfoAsJsonAndReferences() 37 assertEquals(dumpResult.size, 4) 38 assertIsEmptyArray(dumpResult[1]) 39 assertIsEmptyArray(dumpResult[2]) 40 assertIsEmptyArray(dumpResult[3]) 41 } 42 assertIsEmptyArraynull43 private fun assertIsEmptyArray(obj: Any) = 44 assertTrue(obj is Array<*> && obj.isEmpty()) 45 46 private fun runTestWithNamedDeferred(name: String?) = runTest { 47 val context = if (name == null) EmptyCoroutineContext else CoroutineName(name) 48 val deferred = async(context) { 49 suspendingMethod() 50 assertTrue(true) 51 } 52 yield() 53 verifyDump() 54 deferred.cancelAndJoin() 55 } 56 suspendingMethodnull57 private suspend fun suspendingMethod() { 58 delay(Long.MAX_VALUE) 59 } 60 verifyDumpnull61 private fun verifyDump() { 62 val dumpResult = DebugProbesImpl.dumpCoroutinesInfoAsJsonAndReferences() 63 64 assertEquals(dumpResult.size, 4) 65 66 val coroutinesInfoAsJsonString = dumpResult[0] 67 val lastObservedThreads = dumpResult[1] 68 val lastObservedFrames = dumpResult[2] 69 val coroutinesInfo = dumpResult[3] 70 71 assertIs<String>(coroutinesInfoAsJsonString) 72 assertIs<Array<*>>(lastObservedThreads) 73 assertIs<Array<*>>(lastObservedFrames) 74 assertIs<Array<*>>(coroutinesInfo) 75 76 val coroutinesInfoFromJson = 77 Gson().fromJson(coroutinesInfoAsJsonString, Array<CoroutineInfoFromJson>::class.java) 78 79 val size = coroutinesInfo.size 80 assertTrue(size != 0) 81 assertEquals(size, coroutinesInfoFromJson.size) 82 assertEquals(size, lastObservedFrames.size) 83 assertEquals(size, lastObservedThreads.size) 84 85 for (i in 0 until size) { 86 val info = coroutinesInfo[i] 87 val infoFromJson = coroutinesInfoFromJson[i] 88 assertIs<DebugCoroutineInfo>(info) 89 assertEquals(info.lastObservedThread, lastObservedThreads[i]) 90 assertEquals(info.lastObservedFrame, lastObservedFrames[i]) 91 assertEquals(info.sequenceNumber, infoFromJson.sequenceNumber) 92 assertEquals(info.state, infoFromJson.state) 93 val context = info.context 94 assertEquals(context[CoroutineName.Key]?.name, infoFromJson.name) 95 assertEquals(context[CoroutineId.Key]?.id, infoFromJson.id) 96 assertEquals(context[CoroutineDispatcher.Key]?.toString(), infoFromJson.dispatcher) 97 } 98 } 99 } 100