1 /* <lambda>null2 * 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("DEPRECATION") 6 7 package kotlinx.coroutines 8 9 import kotlin.test.* 10 11 class JobTest : TestBase() { 12 @Test 13 fun testState() { 14 val job = Job() 15 assertNull(job.parent) 16 assertTrue(job.isActive) 17 job.cancel() 18 assertTrue(!job.isActive) 19 } 20 21 @Test 22 fun testHandler() { 23 val job = Job() 24 var fireCount = 0 25 job.invokeOnCompletion { fireCount++ } 26 assertTrue(job.isActive) 27 assertEquals(0, fireCount) 28 // cancel once 29 job.cancel() 30 assertTrue(!job.isActive) 31 assertEquals(1, fireCount) 32 // cancel again 33 job.cancel() 34 assertTrue(!job.isActive) 35 assertEquals(1, fireCount) 36 } 37 38 @Test 39 fun testManyHandlers() { 40 val job = Job() 41 val n = 100 * stressTestMultiplier 42 val fireCount = IntArray(n) 43 for (i in 0 until n) job.invokeOnCompletion { fireCount[i]++ } 44 assertTrue(job.isActive) 45 for (i in 0 until n) assertEquals(0, fireCount[i]) 46 // cancel once 47 job.cancel() 48 assertTrue(!job.isActive) 49 for (i in 0 until n) assertEquals(1, fireCount[i]) 50 // cancel again 51 job.cancel() 52 assertTrue(!job.isActive) 53 for (i in 0 until n) assertEquals(1, fireCount[i]) 54 } 55 56 @Test 57 fun testUnregisterInHandler() { 58 val job = Job() 59 val n = 100 * stressTestMultiplier 60 val fireCount = IntArray(n) 61 for (i in 0 until n) { 62 var registration: DisposableHandle? = null 63 registration = job.invokeOnCompletion { 64 fireCount[i]++ 65 registration!!.dispose() 66 } 67 } 68 assertTrue(job.isActive) 69 for (i in 0 until n) assertEquals(0, fireCount[i]) 70 // cancel once 71 job.cancel() 72 assertTrue(!job.isActive) 73 for (i in 0 until n) assertEquals(1, fireCount[i]) 74 // cancel again 75 job.cancel() 76 assertTrue(!job.isActive) 77 for (i in 0 until n) assertEquals(1, fireCount[i]) 78 } 79 80 @Test 81 fun testManyHandlersWithUnregister() { 82 val job = Job() 83 val n = 100 * stressTestMultiplier 84 val fireCount = IntArray(n) 85 val registrations = Array<DisposableHandle>(n) { i -> job.invokeOnCompletion { fireCount[i]++ } } 86 assertTrue(job.isActive) 87 fun unreg(i: Int) = i % 4 <= 1 88 for (i in 0 until n) if (unreg(i)) registrations[i].dispose() 89 for (i in 0 until n) assertEquals(0, fireCount[i]) 90 job.cancel() 91 assertTrue(!job.isActive) 92 for (i in 0 until n) assertEquals(if (unreg(i)) 0 else 1, fireCount[i]) 93 } 94 95 @Test 96 fun testExceptionsInHandler() { 97 val job = Job() 98 val n = 100 * stressTestMultiplier 99 val fireCount = IntArray(n) 100 for (i in 0 until n) job.invokeOnCompletion { 101 fireCount[i]++ 102 throw TestException() 103 } 104 assertTrue(job.isActive) 105 for (i in 0 until n) assertEquals(0, fireCount[i]) 106 val cancelResult = runCatching { job.cancel() } 107 assertTrue(!job.isActive) 108 for (i in 0 until n) assertEquals(1, fireCount[i]) 109 assertTrue(cancelResult.exceptionOrNull() is CompletionHandlerException) 110 assertTrue(cancelResult.exceptionOrNull()!!.cause is TestException) 111 } 112 113 @Test 114 fun testCancelledParent() { 115 val parent = Job() 116 parent.cancel() 117 assertTrue(!parent.isActive) 118 val child = Job(parent) 119 assertTrue(!child.isActive) 120 } 121 122 @Test 123 fun testDisposeSingleHandler() { 124 val job = Job() 125 var fireCount = 0 126 val handler = job.invokeOnCompletion { fireCount++ } 127 handler.dispose() 128 job.cancel() 129 assertEquals(0, fireCount) 130 } 131 132 @Test 133 fun testDisposeMultipleHandler() { 134 val job = Job() 135 val handlerCount = 10 136 var fireCount = 0 137 val handlers = Array(handlerCount) { job.invokeOnCompletion { fireCount++ } } 138 handlers.forEach { it.dispose() } 139 job.cancel() 140 assertEquals(0, fireCount) 141 } 142 143 @Test 144 fun testCancelAndJoinParentWaitChildren() = runTest { 145 expect(1) 146 val parent = Job() 147 launch(parent, start = CoroutineStart.UNDISPATCHED) { 148 expect(2) 149 try { 150 yield() // will get cancelled 151 } finally { 152 expect(5) 153 } 154 } 155 expect(3) 156 parent.cancel() 157 expect(4) 158 parent.join() 159 finish(6) 160 } 161 162 @Test 163 fun testOnCancellingHandler() = runTest { 164 val job = launch { 165 expect(2) 166 delay(Long.MAX_VALUE) 167 } 168 169 job.invokeOnCompletion(onCancelling = true) { 170 assertNotNull(it) 171 expect(3) 172 } 173 174 expect(1) 175 yield() 176 job.cancelAndJoin() 177 finish(4) 178 } 179 180 @Test 181 fun testOverriddenParent() = runTest { 182 val parent = Job() 183 val deferred = launch(parent, CoroutineStart.ATOMIC) { 184 expect(2) 185 delay(Long.MAX_VALUE) 186 } 187 188 parent.cancel() 189 expect(1) 190 deferred.join() 191 finish(3) 192 } 193 194 @Test 195 fun testJobWithParentCancelNormally() { 196 val parent = Job() 197 val job = Job(parent) 198 job.cancel() 199 assertTrue(job.isCancelled) 200 assertFalse(parent.isCancelled) 201 } 202 203 @Test 204 fun testJobWithParentCancelException() { 205 val parent = Job() 206 val job = Job(parent) 207 job.completeExceptionally(TestException()) 208 assertTrue(job.isCancelled) 209 assertTrue(parent.isCancelled) 210 } 211 212 @Test 213 fun testIncompleteJobState() = runTest { 214 val parent = coroutineContext.job 215 val job = launch { 216 coroutineContext[Job]!!.invokeOnCompletion { } 217 } 218 assertSame(parent, job.parent) 219 job.join() 220 assertNull(job.parent) 221 assertTrue(job.isCompleted) 222 assertFalse(job.isActive) 223 assertFalse(job.isCancelled) 224 } 225 226 @Test 227 fun testChildrenWithIncompleteState() = runTest { 228 val job = async { Wrapper() } 229 job.join() 230 assertTrue(job.children.toList().isEmpty()) 231 } 232 233 private class Wrapper : Incomplete { 234 override val isActive: Boolean 235 get() = error("") 236 override val list: NodeList? 237 get() = error("") 238 } 239 } 240