1 /* 2 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED", "UNREACHABLE_CODE", "USELESS_IS_CHECK") // KT-21913 6 7 package kotlinx.coroutines 8 9 import kotlin.test.* 10 11 @Suppress("DEPRECATION") // cancel(cause) 12 class AsyncTest : TestBase() { 13 14 @Test <lambda>null15 fun testSimple() = runTest { 16 expect(1) 17 val d = async { 18 expect(3) 19 42 20 } 21 expect(2) 22 assertTrue(d.isActive) 23 assertEquals(d.await(), 42) 24 assertTrue(!d.isActive) 25 expect(4) 26 assertEquals(d.await(), 42) // second await -- same result 27 finish(5) 28 } 29 30 @Test testUndispatchednull31 fun testUndispatched() = runTest { 32 expect(1) 33 val d = async(start = CoroutineStart.UNDISPATCHED) { 34 expect(2) 35 42 36 } 37 expect(3) 38 assertTrue(!d.isActive) 39 assertEquals(d.await(), 42) 40 finish(4) 41 } 42 43 @Test <lambda>null44 fun testSimpleException() = runTest(expected = { it is TestException }) { 45 expect(1) <lambda>null46 val d = async<Unit> { 47 finish(3) 48 throw TestException() 49 } 50 expect(2) 51 d.await() // will throw TestException 52 } 53 54 @Test <lambda>null55 fun testCancellationWithCause() = runTest { 56 expect(1) 57 val d = async(NonCancellable, start = CoroutineStart.ATOMIC) { 58 expect(3) 59 yield() 60 } 61 expect(2) 62 d.cancel(TestCancellationException("TEST")) 63 try { 64 d.await() 65 } catch (e: TestCancellationException) { 66 finish(4) 67 assertEquals("TEST", e.message) 68 } 69 } 70 71 @Test <lambda>null72 fun testLostException() = runTest { 73 expect(1) 74 val deferred = async(Job()) { 75 expect(2) 76 throw Exception() 77 } 78 79 // Exception is not consumed -> nothing is reported 80 deferred.join() 81 finish(3) 82 } 83 84 @Test <lambda>null85 fun testParallelDecompositionCaughtException() = runTest { 86 val deferred = async(NonCancellable) { 87 val decomposed = async(NonCancellable) { 88 throw TestException() 89 1 90 } 91 try { 92 decomposed.await() 93 } catch (e: TestException) { 94 42 95 } 96 } 97 assertEquals(42, deferred.await()) 98 } 99 100 @Test <lambda>null101 fun testParallelDecompositionCaughtExceptionWithInheritedParent() = runTest { 102 expect(1) 103 val deferred = async(NonCancellable) { 104 expect(2) 105 val decomposed = async { // inherits parent job! 106 expect(3) 107 throw TestException() 108 1 109 } 110 try { 111 decomposed.await() 112 } catch (e: TestException) { 113 expect(4) // Should catch this exception, but parent is already cancelled 114 42 115 } 116 } 117 try { 118 // This will fail 119 assertEquals(42, deferred.await()) 120 } catch (e: TestException) { 121 finish(5) 122 } 123 } 124 125 @Test <lambda>null126 fun testParallelDecompositionUncaughtExceptionWithInheritedParent() = runTest(expected = { it is TestException }) { <lambda>null127 val deferred = async(NonCancellable) { 128 val decomposed = async { 129 throw TestException() 130 1 131 } 132 133 decomposed.await() 134 } 135 136 deferred.await() 137 expectUnreached() 138 } 139 140 @Test <lambda>null141 fun testParallelDecompositionUncaughtException() = runTest(expected = { it is TestException }) { <lambda>null142 val deferred = async(NonCancellable) { 143 val decomposed = async { 144 throw TestException() 145 1 146 } 147 148 decomposed.await() 149 } 150 151 deferred.await() 152 expectUnreached() 153 } 154 155 @Test <lambda>null156 fun testCancellationTransparency() = runTest { 157 val deferred = async(NonCancellable, start = CoroutineStart.ATOMIC) { 158 expect(2) 159 throw TestException() 160 } 161 expect(1) 162 deferred.cancel() 163 try { 164 deferred.await() 165 } catch (e: TestException) { 166 finish(3) 167 } 168 } 169 170 @Test <lambda>null171 fun testDeferAndYieldException() = runTest(expected = { it is TestException }) { 172 expect(1) <lambda>null173 val d = async<Unit> { 174 expect(3) 175 yield() // no effect, parent waiting 176 finish(4) 177 throw TestException() 178 } 179 expect(2) 180 d.await() // will throw IOException 181 } 182 183 @Test <lambda>null184 fun testDeferWithTwoWaiters() = runTest { 185 expect(1) 186 val d = async { 187 expect(5) 188 yield() 189 expect(9) 190 42 191 } 192 expect(2) 193 launch { 194 expect(6) 195 assertEquals(d.await(), 42) 196 expect(11) 197 } 198 expect(3) 199 launch { 200 expect(7) 201 assertEquals(d.await(), 42) 202 expect(12) 203 } 204 expect(4) 205 yield() // this actually yields control to async, which produces results and resumes both waiters (in order) 206 expect(8) 207 yield() // yield again to "d", which completes 208 expect(10) 209 yield() // yield to both waiters 210 finish(13) 211 } 212 213 @Test <lambda>null214 fun testDeferBadClass() = runTest { 215 val bad = BadClass() 216 val d = async { 217 expect(1) 218 bad 219 } 220 assertSame(d.await(), bad) 221 finish(2) 222 } 223 224 @Test <lambda>null225 fun testOverriddenParent() = runTest { 226 val parent = Job() 227 val deferred = async(parent, CoroutineStart.ATOMIC) { 228 expect(2) 229 delay(Long.MAX_VALUE) 230 } 231 232 parent.cancel() 233 try { 234 expect(1) 235 deferred.await() 236 } catch (e: CancellationException) { 237 finish(3) 238 } 239 } 240 241 @Test <lambda>null242 fun testIncompleteAsyncState() = runTest { 243 val deferred = async { 244 coroutineContext[Job]!!.invokeOnCompletion { } 245 } 246 247 deferred.await().dispose() 248 assertTrue(deferred.getCompleted() is DisposableHandle) 249 assertNull(deferred.getCompletionExceptionOrNull()) 250 assertTrue(deferred.isCompleted) 251 assertFalse(deferred.isActive) 252 assertFalse(deferred.isCancelled) 253 } 254 255 @Test <lambda>null256 fun testIncompleteAsyncFastPath() = runTest { 257 val deferred = async(Dispatchers.Unconfined) { 258 coroutineContext[Job]!!.invokeOnCompletion { } 259 } 260 261 deferred.await().dispose() 262 assertTrue(deferred.getCompleted() is DisposableHandle) 263 assertNull(deferred.getCompletionExceptionOrNull()) 264 assertTrue(deferred.isCompleted) 265 assertFalse(deferred.isActive) 266 assertFalse(deferred.isCancelled) 267 } 268 269 @Test <lambda>null270 fun testAsyncWithFinally() = runTest { 271 expect(1) 272 273 @Suppress("UNREACHABLE_CODE") 274 val d = async { 275 expect(3) 276 try { 277 yield() // to main, will cancel 278 } finally { 279 expect(6) // will go there on await 280 return@async "Fail" // result will not override cancellation 281 } 282 expectUnreached() 283 "Fail2" 284 } 285 expect(2) 286 yield() // to async 287 expect(4) 288 check(d.isActive && !d.isCompleted && !d.isCancelled) 289 d.cancel() 290 check(!d.isActive && !d.isCompleted && d.isCancelled) 291 check(!d.isActive && !d.isCompleted && d.isCancelled) 292 expect(5) 293 try { 294 d.await() // awaits 295 expectUnreached() // does not complete normally 296 } catch (e: Throwable) { 297 expect(7) 298 check(e is CancellationException) 299 } 300 check(!d.isActive && d.isCompleted && d.isCancelled) 301 finish(8) 302 } 303 } 304