diff --git a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt index 965f17883f..89dd914879 100644 --- a/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt +++ b/kotlinx-coroutines-debug/test/RunningThreadStackMergeTest.kt @@ -1,7 +1,6 @@ /* * Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. */ -@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") package kotlinx.coroutines.debug import kotlinx.coroutines.* @@ -170,7 +169,8 @@ class RunningThreadStackMergeTest : DebugTestBase() { assertTrue(true) } - @Test + @Test // IDEA-specific debugger API test + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") fun testActiveThread() = runBlocking { launchCoroutine() awaitCoroutineStarted() diff --git a/kotlinx-coroutines-debug/test/StacktraceUtils.kt b/kotlinx-coroutines-debug/test/StacktraceUtils.kt index 55bdd7e0b0..869e29751c 100644 --- a/kotlinx-coroutines-debug/test/StacktraceUtils.kt +++ b/kotlinx-coroutines-debug/test/StacktraceUtils.kt @@ -74,6 +74,18 @@ private fun cleanBlockHoundTraces(frames: List): List { return result } +/** + * Removes all frames that contain "java.util.concurrent" in it. + * + * We do leverage Java's locks for proper rendezvous and to fix the coroutine stack's state, + * but this API doesn't have (nor expected to) stable stacktrace, so we are filtering all such + * frames out. + * + * See https://github.com/Kotlin/kotlinx.coroutines/issues/3700 for the example of failure + */ +private fun removeJavaUtilConcurrentTraces(frames: List): List = + frames.filter { !it.contains("java.util.concurrent") } + private data class CoroutineDump( val header: CoroutineDumpHeader, val coroutineStackTrace: List, @@ -185,7 +197,9 @@ public fun verifyDump(vararg expectedTraces: String, ignoredCoroutine: String? = .drop(1) // Parse dumps and filter out ignored coroutines .mapNotNull { trace -> - val dump = CoroutineDump.parse(trace, traceCleaner = ::cleanBlockHoundTraces) + val dump = CoroutineDump.parse(trace, { + removeJavaUtilConcurrentTraces(cleanBlockHoundTraces(it)) + }) if (dump.header.className == ignoredCoroutine) { null } else { @@ -194,9 +208,10 @@ public fun verifyDump(vararg expectedTraces: String, ignoredCoroutine: String? = } assertEquals(expectedTraces.size, dumps.size) - dumps.zip(expectedTraces.map(CoroutineDump::parse)).forEach { (dump, expectedDump) -> - dump.verify(expectedDump) - } + dumps.zip(expectedTraces.map { CoroutineDump.parse(it, ::removeJavaUtilConcurrentTraces) }) + .forEach { (dump, expectedDump) -> + dump.verify(expectedDump) + } } public fun String.trimPackage() = replace("kotlinx.coroutines.debug.", "")