@@ -3,9 +3,6 @@ package kotlinx.coroutines
33import kotlinx.coroutines.flow.*
44import kotlinx.coroutines.testing.*
55import org.junit.Test
6- import java.util.concurrent.CopyOnWriteArrayList
7- import java.util.concurrent.ExecutorService
8- import java.util.concurrent.Executors
96import kotlin.coroutines.*
107import kotlin.test.*
118
@@ -63,83 +60,6 @@ class ThreadContextElementJvmTest : TestBase() {
6360 }
6461 }
6562
66- class JobCaptor (val capturees : MutableList <String > = CopyOnWriteArrayList ()) : ThreadContextElement<Unit> {
67-
68- companion object Key : CoroutineContext.Key<MyElement>
69-
70- override val key: CoroutineContext .Key <* > get() = Key
71-
72- override fun updateThreadContext (context : CoroutineContext ) {
73- capturees.add(" Update: ${context.job} " )
74- }
75-
76- override fun restoreThreadContext (context : CoroutineContext , oldState : Unit ) {
77- capturees.add(" Restore: ${context.job} " )
78- }
79- }
80-
81- /* *
82- * For stability of the test, it is important to make sure that
83- * the parent job actually suspends when calling
84- * `withContext(dispatcher2 + CoroutineName("dispatched"))`.
85- *
86- * Here this requirement is fulfilled by forcing execution on a single thread.
87- * However, dispatching is performed with two non-equal dispatchers to force dispatching.
88- *
89- * Suspend of the parent coroutine [kotlinx.coroutines.DispatchedCoroutine.trySuspend] is out of the control of the test,
90- * while being executed concurrently with resume of the child coroutine [kotlinx.coroutines.DispatchedCoroutine.tryResume].
91- */
92- @Test
93- fun testWithContextJobAccess () = runTest {
94- val executor = Executors .newSingleThreadExecutor()
95- // Emulate non-equal dispatchers
96- val executor1 = object : ExecutorService by executor {}
97- val executor2 = object : ExecutorService by executor {}
98- val dispatcher1 = executor1.asCoroutineDispatcher()
99- val dispatcher2 = executor2.asCoroutineDispatcher()
100- val captor = JobCaptor ()
101- val manuallyCaptured = mutableListOf<String >()
102-
103- fun registerUpdate (job : Job ? ) = manuallyCaptured.add(" Update: $job " )
104- fun registerRestore (job : Job ? ) = manuallyCaptured.add(" Restore: $job " )
105-
106- var rootJob: Job ? = null
107- runBlocking(captor + dispatcher1) {
108- rootJob = coroutineContext.job
109- registerUpdate(rootJob)
110- var undispatchedJob: Job ? = null
111- withContext(CoroutineName (" undispatched" )) {
112- undispatchedJob = coroutineContext.job
113- registerUpdate(undispatchedJob)
114- // These 2 restores and the corresponding next 2 updates happen only if the following `withContext`
115- // call actually suspends.
116- registerRestore(undispatchedJob)
117- registerRestore(rootJob)
118- // Without forcing of single backing thread the code inside `withContext`
119- // may already complete at the moment when the parent coroutine decides
120- // whether it needs to suspend or not.
121- var dispatchedJob: Job ? = null
122- withContext(dispatcher2 + CoroutineName (" dispatched" )) {
123- dispatchedJob = coroutineContext.job
124- registerUpdate(dispatchedJob)
125- }
126- registerRestore(dispatchedJob)
127- // Context restored, captured again
128- registerUpdate(undispatchedJob)
129- }
130- registerRestore(undispatchedJob)
131- // Context restored, captured again
132- registerUpdate(rootJob)
133- }
134- registerRestore(rootJob)
135-
136- // Restores may be called concurrently to the update calls in other threads, so their order is not checked.
137- val expected = manuallyCaptured.filter { it.startsWith(" Update: " ) }.joinToString(separator = " \n " )
138- val actual = captor.capturees.filter { it.startsWith(" Update: " ) }.joinToString(separator = " \n " )
139- assertEquals(expected, actual)
140- executor.shutdownNow()
141- }
142-
14363 @Test
14464 fun testThreadLocalFlowOn () = runTest {
14565 val myData = MyData ()
@@ -216,4 +136,3 @@ private inline fun <ThreadLocalT, OutputT> ThreadLocal<ThreadLocalT>.setForBlock
216136 block()
217137 set(priorValue)
218138}
219-
0 commit comments