blob: 665d0cebcbe261405845fc12071edef41329ab7d [file] [log] [blame]
Vsevolod Tolstopyatov931587a2018-04-16 17:51:12 +03001package kotlinx.coroutines.experimental
2
3import org.junit.*
4import org.junit.Test
5import java.io.*
6import java.util.concurrent.*
7import kotlin.test.*
8
9class JoinStressTest : TestBase() {
10
Vsevolod Tolstopyatov4aa18aa2018-04-17 15:43:12 +030011 private val iterations = 50_000 * stressTestMultiplier
Vsevolod Tolstopyatov931587a2018-04-16 17:51:12 +030012 private val pool = newFixedThreadPoolContext(3, "JoinStressTest")
13
14 @After
15 fun tearDown() {
16 pool.close()
17 }
18
19 class TestException : Exception() {
20 override fun fillInStackTrace(): Throwable = this
21 }
22
23 @Test
24 fun testExceptionalJoinWithCancellation() = runBlocking {
25 val results = IntArray(2)
26
27 repeat(iterations) {
28 val barrier = CyclicBarrier(3)
29 val exceptionalJob = async(pool) {
30 barrier.await()
31 throw TestException()
32 }
33
34
35 val awaiterJob = async(pool) {
36 barrier.await()
37 try {
38 exceptionalJob.await()
39 } catch (e: TestException) {
40 0
41 } catch (e: CancellationException) {
42 1
43 }
44 }
45
46 barrier.await()
47 exceptionalJob.cancel()
48 ++results[awaiterJob.await()]
49 require(!exceptionalJob.cancel())
50 }
51
52 // Check that concurrent cancellation of job which throws TestException without suspends doesn't suppress TestException
53 assertEquals(iterations, results[0], results.toList().toString())
54 assertEquals(0, results[1], results.toList().toString())
55 }
56
57 @Test
58 fun testExceptionalJoinWithMultipleCancellations() = runBlocking {
59 val results = IntArray(2)
60 var successfulCancellations = 0
61
62 repeat(iterations) {
63 val barrier = CyclicBarrier(4)
64 val exceptionalJob = async(pool) {
65 barrier.await()
66 throw TestException()
67 }
68
69 val awaiterJob = async(pool) {
70 barrier.await()
71 try {
72 exceptionalJob.await()
73 } catch (e: TestException) {
74 0
75 } catch (e: CancellationException) {
76 1
77 }
78 }
79
80 val canceller = async(pool) {
81 barrier.await()
82 exceptionalJob.cancel(IOException())
83 }
84
85 barrier.await()
86 val result = exceptionalJob.cancel()
87 ++results[awaiterJob.await()]
88 val cancellerResult = canceller.await()
89
90 // None or one cancel can succeed
91 require(!(result && cancellerResult))
92 require(!exceptionalJob.cancel())
93
94 if (result || cancellerResult) {
95 ++successfulCancellations
96 }
97 }
98
99 assertEquals(iterations, results[0], results.toList().toString())
100 assertEquals(0, results[1], results.toList().toString())
101 require(successfulCancellations > 0) { "Cancellation never succeeds, something wrong with stress test infra" }
102 }
103}