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