@@ -173,13 +173,16 @@ class KotlinLoggingAsyncMDCTest {
173173 val requestAStarted = CompletableDeferred <Unit >()
174174 val requestBDone = CompletableDeferred <Unit >()
175175
176+ val requestADuringBlock = CompletableDeferred <Map <String , String >? > ()
176177 val requestAAfterBlock = CompletableDeferred <Map <String , String >? > ()
178+ val requestBDuringBlock = CompletableDeferred <Map <String , String >? > ()
177179 val requestBAfterBlock = CompletableDeferred <Map <String , String >? > ()
178180
179181 val jobA =
180182 launch(dispatcher) {
181183 withLoggingContextAsync(" foo" to " original" ) {
182184 requestAStarted.complete(Unit )
185+ requestADuringBlock.complete(MDC .getCopyOfContextMap())
183186 requestBDone.await() // Suspend while B runs
184187 }
185188 // will be empty
@@ -189,7 +192,9 @@ class KotlinLoggingAsyncMDCTest {
189192 val jobB =
190193 launch(dispatcher) {
191194 requestAStarted.await()
192- withLoggingContextAsync(" foo" to " bar" ) {}
195+ withLoggingContextAsync(" foo" to " bar" ) {
196+ requestBDuringBlock.complete(MDC .getCopyOfContextMap())
197+ }
193198 // Capture MDC state immediately after Request B's block, will NOT be empty due to the bug
194199 requestBAfterBlock.complete(MDC .getCopyOfContextMap())
195200 requestBDone.complete(Unit )
@@ -198,7 +203,9 @@ class KotlinLoggingAsyncMDCTest {
198203 jobA.join()
199204 jobB.join()
200205
206+ assertEquals(mapOf (" foo" to " original" ), requestADuringBlock.await())
201207 assertEquals(emptyMap(), requestAAfterBlock.await())
208+ assertEquals(mapOf (" foo" to " bar" ), requestBDuringBlock.await())
202209 // THIS IS THE BUG: Request B sees "original" after its own block exits
203210 // It should be null (no context) but it's leaking Request A's value
204211 assertEquals(mapOf (" foo" to " original" ), requestBAfterBlock.await())
@@ -214,13 +221,16 @@ class KotlinLoggingAsyncMDCTest {
214221 val requestAStarted = CompletableDeferred <Unit >()
215222 val requestBDone = CompletableDeferred <Unit >()
216223
224+ val requestADuringBlock = CompletableDeferred <Map <String , String >? > ()
217225 val requestAAfterBlock = CompletableDeferred <Map <String , String >? > ()
226+ val requestBDuringBlock = CompletableDeferred <Map <String , String >? > ()
218227 val requestBAfterBlock = CompletableDeferred <Map <String , String >? > ()
219228
220229 val jobA =
221230 launch(dispatcher) {
222231 withCoroutineLoggingContext(" foo" to " original" ) {
223232 requestAStarted.complete(Unit )
233+ requestADuringBlock.complete(MDC .getCopyOfContextMap())
224234 requestBDone.await() // Suspend while B runs
225235 }
226236 // will be empty
@@ -230,7 +240,9 @@ class KotlinLoggingAsyncMDCTest {
230240 val jobB =
231241 launch(dispatcher) {
232242 requestAStarted.await()
233- withCoroutineLoggingContext(" foo" to " bar" ) {}
243+ withCoroutineLoggingContext(" foo" to " bar" ) {
244+ requestBDuringBlock.complete(MDC .getCopyOfContextMap())
245+ }
234246 // Capture MDC state immediately after Request B's block, will NOT be empty due to the bug
235247 requestBAfterBlock.complete(MDC .getCopyOfContextMap())
236248 requestBDone.complete(Unit )
@@ -239,7 +251,9 @@ class KotlinLoggingAsyncMDCTest {
239251 jobA.join()
240252 jobB.join()
241253
254+ assertEquals(mapOf (" foo" to " original" ), requestADuringBlock.await())
242255 assertEquals(emptyMap(), requestAAfterBlock.await())
256+ assertEquals(mapOf (" foo" to " bar" ), requestBDuringBlock.await())
243257 assertEquals(emptyMap(), requestBAfterBlock.await())
244258 }
245259
0 commit comments