test: dump thread stacks when an await times out

The playback/queue wall-clock awaits have flaked on the 4-vCPU GitHub
runner at exactly the 30s limit, a different test each time. That is a
stall, not slowness: the suite finishes ~80s for 795 tests, so no test is
anywhere near 30s normally. The JUnit XML holds the stacks but is not
uploaded, leaving the failures undiagnosable from the CI log. Put every
thread's stack in the failure message, which Gradle prints.
This commit is contained in:
austinried
2026-10-11 06:27:42 +00:00
parent 43ee2d9f27
commit 6f997dceb9
@@ -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" }
}