Skip to content

ThreadLocal element not updated correctly when using UnconfinedTestDispatcher #4326

@chuckjaz

Description

@chuckjaz

When using an UnconfinedTestDispatcher, the context element for a thread local is not restored when the coroutine is suspended.

Reproduction

playground

import kotlin.coroutines.*
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*

val MyThreadLocal = ThreadLocal<String>().apply { set("initial") }

@OptIn(ExperimentalCoroutinesApi::class)
fun main() = runTest(UnconfinedTestDispatcher()) {
    val toResume = CompletableDeferred<Continuation<Unit>>()
    launch {
    	println("Initial value: ${MyThreadLocal.get()}")
    	withContext(MyThreadLocal.asContextElement(value = "inContext")) {
        	println("in withContext: ${MyThreadLocal.get()}")
        	suspendCoroutine { co ->
            	toResume.complete(co)
        	}
   		}
        println("after withContext: ${MyThreadLocal.get()}")
    }
    toResume.await().resume(Unit)
}

Expected: "after withContext: initial"

Received: "after withContext: inContext"

NOTE: Removing (UnconfinedTestDispatcher()) from the test case above produces the expected result.

This seems related to #2930 and #4121 as the repro steps are similar.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions