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