• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3  */
4 
5 import kotlinx.coroutines.*
6 import kotlinx.coroutines.test.*
7 import kotlin.concurrent.*
8 import kotlin.coroutines.*
9 import kotlin.test.*
10 
11 class MultithreadingTest {
12 
13     @Test
14     fun incorrectlyCalledRunBlocking_doesNotHaveSameInterceptor() = runBlockingTest {
15         // this code is an error as a production test, please do not use this as an example
16 
17         // this test exists to document this error condition, if it's possible to make this code work please update
18         val outerInterceptor = coroutineContext[ContinuationInterceptor]
19         // runBlocking always requires an argument to pass the context in tests
20         runBlocking {
21             assertNotSame(coroutineContext[ContinuationInterceptor], outerInterceptor)
22         }
23     }
24 
25     @Test
26     fun testSingleThreadExecutor() = runBlocking {
27         val mainThread = Thread.currentThread()
28         Dispatchers.setMain(Dispatchers.Unconfined)
29         newSingleThreadContext("testSingleThread").use { threadPool ->
30             withContext(Dispatchers.Main) {
31                 assertSame(mainThread, Thread.currentThread())
32             }
33 
34             Dispatchers.setMain(threadPool)
35             withContext(Dispatchers.Main) {
36                 assertNotSame(mainThread, Thread.currentThread())
37             }
38             assertSame(mainThread, Thread.currentThread())
39 
40             withContext(Dispatchers.Main.immediate) {
41                 assertNotSame(mainThread, Thread.currentThread())
42             }
43             assertSame(mainThread, Thread.currentThread())
44 
45             Dispatchers.setMain(Dispatchers.Unconfined)
46             withContext(Dispatchers.Main.immediate) {
47                 assertSame(mainThread, Thread.currentThread())
48             }
49             assertSame(mainThread, Thread.currentThread())
50         }
51     }
52 
53     @Test
54     fun whenDispatchCalled_runsOnCurrentThread() {
55         val currentThread = Thread.currentThread()
56         val subject = TestCoroutineDispatcher()
57         val scope = TestCoroutineScope(subject)
58 
59         val deferred = scope.async(Dispatchers.Default) {
60             withContext(subject) {
61                 assertNotSame(currentThread, Thread.currentThread())
62                 3
63             }
64         }
65 
66         runBlocking {
67             // just to ensure the above code terminates
68             assertEquals(3, deferred.await())
69         }
70     }
71 
72     @Test
73     fun whenAllDispatchersMocked_runsOnSameThread() {
74         val currentThread = Thread.currentThread()
75         val subject = TestCoroutineDispatcher()
76         val scope = TestCoroutineScope(subject)
77 
78         val deferred = scope.async(subject) {
79             withContext(subject) {
80                 assertSame(currentThread, Thread.currentThread())
81                 3
82             }
83         }
84 
85         runBlocking {
86             // just to ensure the above code terminates
87             assertEquals(3, deferred.await())
88         }
89     }
90 
91     /** Tests that resuming the coroutine of [runTest] asynchronously in reasonable time succeeds. */
92     @Test
93     fun testResumingFromAnotherThread() = runTest {
94         suspendCancellableCoroutine<Unit> { cont ->
95             thread {
96                 Thread.sleep(10)
97                 cont.resume(Unit)
98             }
99         }
100     }
101 
102     /** Tests that [StandardTestDispatcher] is not executed in-place but confined to the thread in which the
103      * virtual time control happens. */
104     @Test
105     fun testStandardTestDispatcherIsConfined(): Unit = runBlocking {
106         val scheduler = TestCoroutineScheduler()
107         val initialThread = Thread.currentThread()
108         val job = launch(StandardTestDispatcher(scheduler)) {
109             assertEquals(initialThread, Thread.currentThread())
110             withContext(Dispatchers.IO) {
111                 val ioThread = Thread.currentThread()
112                 assertNotSame(initialThread, ioThread)
113             }
114             assertEquals(initialThread, Thread.currentThread())
115         }
116         scheduler.advanceUntilIdle()
117         while (job.isActive) {
118             scheduler.receiveDispatchEvent()
119             scheduler.advanceUntilIdle()
120         }
121     }
122 }
123