blob: 04d3c9e012e15db0f2c856fa78b03761d1892f28 [file] [log] [blame]
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION")
package kotlinx.coroutines
import kotlin.test.*
class JobTest : TestBase() {
@Test
fun testState() {
val job = Job()
assertTrue(job.isActive)
job.cancel()
assertTrue(!job.isActive)
}
@Test
fun testHandler() {
val job = Job()
var fireCount = 0
job.invokeOnCompletion { fireCount++ }
assertTrue(job.isActive)
assertEquals(0, fireCount)
// cancel once
job.cancel()
assertTrue(!job.isActive)
assertEquals(1, fireCount)
// cancel again
job.cancel()
assertTrue(!job.isActive)
assertEquals(1, fireCount)
}
@Test
fun testManyHandlers() {
val job = Job()
val n = 100 * stressTestMultiplier
val fireCount = IntArray(n)
for (i in 0 until n) job.invokeOnCompletion { fireCount[i]++ }
assertTrue(job.isActive)
for (i in 0 until n) assertEquals(0, fireCount[i])
// cancel once
job.cancel()
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(1, fireCount[i])
// cancel again
job.cancel()
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(1, fireCount[i])
}
@Test
fun testUnregisterInHandler() {
val job = Job()
val n = 100 * stressTestMultiplier
val fireCount = IntArray(n)
for (i in 0 until n) {
var registration: DisposableHandle? = null
registration = job.invokeOnCompletion {
fireCount[i]++
registration!!.dispose()
}
}
assertTrue(job.isActive)
for (i in 0 until n) assertEquals(0, fireCount[i])
// cancel once
job.cancel()
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(1, fireCount[i])
// cancel again
job.cancel()
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(1, fireCount[i])
}
@Test
fun testManyHandlersWithUnregister() {
val job = Job()
val n = 100 * stressTestMultiplier
val fireCount = IntArray(n)
val registrations = Array<DisposableHandle>(n) { i -> job.invokeOnCompletion { fireCount[i]++ } }
assertTrue(job.isActive)
fun unreg(i: Int) = i % 4 <= 1
for (i in 0 until n) if (unreg(i)) registrations[i].dispose()
for (i in 0 until n) assertEquals(0, fireCount[i])
job.cancel()
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(if (unreg(i)) 0 else 1, fireCount[i])
}
@Test
fun testExceptionsInHandler() {
val job = Job()
val n = 100 * stressTestMultiplier
val fireCount = IntArray(n)
for (i in 0 until n) job.invokeOnCompletion {
fireCount[i]++
throw TestException()
}
assertTrue(job.isActive)
for (i in 0 until n) assertEquals(0, fireCount[i])
val tryCancel = Try { job.cancel() }
assertTrue(!job.isActive)
for (i in 0 until n) assertEquals(1, fireCount[i])
assertTrue(tryCancel.exception is CompletionHandlerException)
assertTrue(tryCancel.exception!!.cause is TestException)
}
@Test
fun testCancelledParent() {
val parent = Job()
parent.cancel()
assertTrue(!parent.isActive)
val child = Job(parent)
assertTrue(!child.isActive)
}
@Test
fun testDisposeSingleHandler() {
val job = Job()
var fireCount = 0
val handler = job.invokeOnCompletion { fireCount++ }
handler.dispose()
job.cancel()
assertEquals(0, fireCount)
}
@Test
fun testDisposeMultipleHandler() {
val job = Job()
val handlerCount = 10
var fireCount = 0
val handlers = Array(handlerCount) { job.invokeOnCompletion { fireCount++ } }
handlers.forEach { it.dispose() }
job.cancel()
assertEquals(0, fireCount)
}
@Test
fun testCancelAndJoinParentWaitChildren() = runTest {
expect(1)
val parent = Job()
launch(parent, start = CoroutineStart.UNDISPATCHED) {
expect(2)
try {
yield() // will get cancelled
} finally {
expect(5)
}
}
expect(3)
parent.cancel()
expect(4)
parent.join()
finish(6)
}
@Test
fun testOnCancellingHandler() = runTest {
val job = launch {
expect(2)
delay(Long.MAX_VALUE)
}
job.invokeOnCompletion(onCancelling = true) {
assertNotNull(it)
expect(3)
}
expect(1)
yield()
job.cancelAndJoin()
finish(4)
}
@Test
fun testOverriddenParent() = runTest {
val parent = Job()
val deferred = launch(parent, CoroutineStart.ATOMIC) {
expect(2)
delay(Long.MAX_VALUE)
}
parent.cancel()
expect(1)
deferred.join()
finish(3)
}
@Test
fun testJobWithParentCancelNormally() {
val parent = Job()
val job = Job(parent)
job.cancel()
assertTrue(job.isCancelled)
assertFalse(parent.isCancelled)
}
@Test
fun testJobWithParentCancelException() {
val parent = Job()
val job = Job(parent)
job.completeExceptionally(TestException())
assertTrue(job.isCancelled)
assertTrue(parent.isCancelled)
}
@Test
fun testIncompleteJobState() = runTest {
val job = launch {
coroutineContext[Job]!!.invokeOnCompletion { }
}
job.join()
assertTrue(job.isCompleted)
assertFalse(job.isActive)
assertFalse(job.isCancelled)
}
@Test
fun testChildrenWithIncompleteState() = runTest {
val job = async { Wrapper() }
job.join()
assertTrue(job.children.toList().isEmpty())
}
private class Wrapper : Incomplete {
override val isActive: Boolean
get() = error("")
override val list: NodeList?
get() = error("")
}
}