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