diff --git a/app/src/test/kotlin/com/subtracks/TestSupport.kt b/app/src/test/kotlin/com/subtracks/TestSupport.kt index 943ac7f7..9e680ade 100644 --- a/app/src/test/kotlin/com/subtracks/TestSupport.kt +++ b/app/src/test/kotlin/com/subtracks/TestSupport.kt @@ -4,7 +4,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.runBlocking -import org.junit.Assert.assertTrue +import org.junit.Assert.fail const val TEST_TIMEOUT_MS = 30_000L @@ -18,5 +18,14 @@ fun awaitUntil( ) { val deadline = System.nanoTime() + TEST_TIMEOUT_MS * 1_000_000 while (!predicate() && System.nanoTime() < deadline) Thread.sleep(10) - assertTrue("Timed out after ${TEST_TIMEOUT_MS}ms $message", predicate()) + if (predicate()) return + // A wall-clock wait that expires means something stalled rather than ran slow: the suite + // finishes in milliseconds per test. Print every thread's stack in the failure message so the + // stall is diagnosable from the CI log, which shows exception messages but not the test XML. + fail("Timed out after ${TEST_TIMEOUT_MS}ms $message\n\n${threadDump()}") } + +private fun threadDump(): String = + Thread.getAllStackTraces().entries.joinToString("\n\n") { (thread, frames) -> + "${thread.name} [${thread.state}]\n" + frames.joinToString("\n") { " at $it" } + }