From 55928388fc64996c7355d6e82bad78e6a657914d Mon Sep 17 00:00:00 2001 From: Vsevolod Tolstopyatov Date: Tue, 25 Apr 2023 18:23:15 +0200 Subject: [PATCH] Filter out "java.util.concurrent" frames from debugging test machinery We do rely on java.util.concurrent primitives for rendezvous in tests, but we cannot rely on their internal stacktraces in tests, thus filtering them out from test data. Otherwise, tests outcome depends on the underlying JDK version Fixes #3700 --- .../test/RunningThreadStackMergeTest.kt | 4 ++-- .../test/StacktraceUtils.kt | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) 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.", "")