• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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