1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.exceptions
import kotlinx.coroutines.*
import org.junit.*
import org.junit.Test
import java.io.*
import java.util.concurrent.*
import kotlin.test.*
class JobExceptionsStressTest : TestBase() {
private val executor = newFixedThreadPoolContext(5, "JobExceptionsStressTest")
@After
fun tearDown() {
executor.close()
}
@Test
fun testMultipleChildrenThrows() {
/*
* Root parent: launched job
* Owner: launch 3 children, every of it throws an exception, and then call delay()
* Result: one of the exceptions with the rest two as suppressed
*/
repeat(1000 * stressTestMultiplier) {
val exception = runBlock(executor) {
val barrier = CyclicBarrier(4)
val job = launch(NonCancellable) {
launch(start = CoroutineStart.ATOMIC) {
barrier.await()
throw TestException1()
}
launch(start = CoroutineStart.ATOMIC) {
barrier.await()
throw TestException2()
}
launch(start = CoroutineStart.ATOMIC) {
barrier.await()
throw TestException3()
}
delay(1000) // to avoid OutOfMemory errors....
}
barrier.await()
job.join()
}
val classes = mutableSetOf(
TestException1::class,
TestException2::class,
TestException3::class
)
val suppressedExceptions = exception.suppressed.toSet()
assertTrue(classes.remove(exception::class),
"Failed to remove ${exception::class} from $suppressedExceptions"
)
for (throwable in suppressedExceptions.toSet()) { // defensive copy
assertTrue(classes.remove(throwable::class),
"Failed to remove ${throwable::class} from $suppressedExceptions")
}
assertTrue(classes.isEmpty(), "Expected all exception to be present, but following exceptions are missing: $classes")
}
}
}
|