From d47701d7f1ca2abd3d6bdf09766b65daa5bfadb4 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Fri, 13 Nov 2026 10:27:22 +0100 Subject: [PATCH] test(okhttp): Wait until the reader is blocked before closing the body The concurrent close test signaled right after the reader got the first chunk, before it entered the next read(). When close() landed in that gap, the reader's next read() threw Okio's "closed" IllegalStateException, the thread died, and the test timed out waiting for it. ParkingSource now signals right before it blocks, so close() always lands while the reader is inside read(). Co-Authored-By: Claude Fable 5.1 --- .../java/io/sentry/okhttp/CapturedResponseBodyTest.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sentry-okhttp/src/test/java/io/sentry/okhttp/CapturedResponseBodyTest.kt b/sentry-okhttp/src/test/java/io/sentry/okhttp/CapturedResponseBodyTest.kt index 0a5829d9c5..719eb4b0e1 100644 --- a/sentry-okhttp/src/test/java/io/sentry/okhttp/CapturedResponseBodyTest.kt +++ b/sentry-okhttp/src/test/java/io/sentry/okhttp/CapturedResponseBodyTest.kt @@ -71,12 +71,16 @@ class CapturedResponseBodyTest { private val closed = CountDownLatch(1) private var sent = false + /** Counts down once a read is blocked waiting for [close]. */ + val parked = CountDownLatch(1) + override fun read(sink: Buffer, byteCount: Long): Long { if (!sent) { sent = true sink.write(chunk) return chunk.size.toLong() } + parked.countDown() closed.await(10, TimeUnit.SECONDS) return -1L } @@ -260,19 +264,19 @@ class CapturedResponseBodyTest { val chunk = "data: event-0\n\n".toByteArray() val source = ParkingSource(chunk) val (wrapper, captured) = capture(source, 1024) - val chunkRead = CountDownLatch(1) val readDone = CountDownLatch(1) val reader = Thread { val bodySource = wrapper.source() bodySource.readByteArray(chunk.size.toLong()) - chunkRead.countDown() bodySource.readByteArray() readDone.countDown() } reader.isDaemon = true reader.start() - assertTrue(chunkRead.await(10, TimeUnit.SECONDS), "the reader must have received the chunk") + // Wait until the reader is blocked inside read(). Closing before that would make the next read + // throw "closed" on the reader thread instead of returning end of stream. + assertTrue(source.parked.await(10, TimeUnit.SECONDS), "the reader must be blocked in read()") wrapper.close() assertTrue(