1 /* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines 6 7 import kotlinx.coroutines.channels.* 8 import kotlinx.coroutines.selects.* 9 import kotlin.test.* 10 11 class AtomicCancellationTest : TestBase() { 12 @Test <lambda>null13 fun testSendCancellable() = runBlocking { 14 expect(1) 15 val channel = Channel<Int>() 16 val job = launch(start = CoroutineStart.UNDISPATCHED) { 17 expect(2) 18 channel.send(42) // suspends 19 expectUnreached() // should NOT execute because of cancellation 20 } 21 expect(3) 22 assertEquals(42, channel.receive()) // will schedule sender for further execution 23 job.cancel() // cancel the job next 24 yield() // now yield 25 finish(4) 26 } 27 28 @Test <lambda>null29 fun testSelectSendCancellable() = runBlocking { 30 expect(1) 31 val channel = Channel<Int>() 32 val job = launch(start = CoroutineStart.UNDISPATCHED) { 33 expect(2) 34 val result = select<String> { // suspends 35 channel.onSend(42) { 36 expect(4) 37 "OK" 38 } 39 } 40 expectUnreached() // should NOT execute because of cancellation 41 } 42 expect(3) 43 assertEquals(42, channel.receive()) // will schedule sender for further execution 44 job.cancel() // cancel the job next 45 yield() // now yield 46 finish(4) 47 } 48 49 @Test <lambda>null50 fun testReceiveCancellable() = runBlocking { 51 expect(1) 52 val channel = Channel<Int>() 53 val job = launch(start = CoroutineStart.UNDISPATCHED) { 54 expect(2) 55 assertEquals(42, channel.receive()) // suspends 56 expectUnreached() // should NOT execute because of cancellation 57 } 58 expect(3) 59 channel.send(42) // will schedule receiver for further execution 60 job.cancel() // cancel the job next 61 yield() // now yield 62 finish(4) 63 } 64 65 @Test <lambda>null66 fun testSelectReceiveCancellable() = runBlocking { 67 expect(1) 68 val channel = Channel<Int>() 69 val job = launch(start = CoroutineStart.UNDISPATCHED) { 70 expect(2) 71 val result = select<String> { // suspends 72 channel.onReceive { 73 assertEquals(42, it) 74 expect(4) 75 "OK" 76 } 77 } 78 expectUnreached() // should NOT execute because of cancellation 79 } 80 expect(3) 81 channel.send(42) // will schedule receiver for further execution 82 job.cancel() // cancel the job next 83 yield() // now yield 84 finish(4) 85 } 86 87 @Test <lambda>null88 fun testSelectDeferredAwaitCancellable() = runBlocking { 89 expect(1) 90 val deferred = async { // deferred, not yet complete 91 expect(4) 92 "OK" 93 } 94 assertEquals(false, deferred.isCompleted) 95 var job: Job? = null 96 launch { // will cancel job as soon as deferred completes 97 expect(5) 98 assertEquals(true, deferred.isCompleted) 99 job!!.cancel() 100 } 101 job = launch(start = CoroutineStart.UNDISPATCHED) { 102 expect(2) 103 try { 104 select<Unit> { // suspends 105 deferred.onAwait { expectUnreached() } 106 } 107 expectUnreached() // will not execute -- cancelled while dispatched 108 } finally { 109 finish(7) // but will execute finally blocks 110 } 111 } 112 expect(3) // continues to execute when the job suspends 113 yield() // to deferred & canceller 114 expect(6) 115 } 116 117 @Test <lambda>null118 fun testSelectJobJoinCancellable() = runBlocking { 119 expect(1) 120 val jobToJoin = launch { // not yet complete 121 expect(4) 122 } 123 assertEquals(false, jobToJoin.isCompleted) 124 var job: Job? = null 125 launch { // will cancel job as soon as jobToJoin completes 126 expect(5) 127 assertEquals(true, jobToJoin.isCompleted) 128 job!!.cancel() 129 } 130 job = launch(start = CoroutineStart.UNDISPATCHED) { 131 expect(2) 132 try { 133 select<Unit> { // suspends 134 jobToJoin.onJoin { expectUnreached() } 135 } 136 expectUnreached() // will not execute -- cancelled while dispatched 137 } finally { 138 finish(7) // but will execute finally blocks 139 } 140 } 141 expect(3) // continues to execute when the job suspends 142 yield() // to jobToJoin & canceller 143 expect(6) 144 } 145 } 146