blob: 8ff7dcbf159f8c20b358250ffce968547e2fc402 [file] [log] [blame]
Roman Elizarov507f5d42017-04-19 19:15:34 +03001/*
Roman Elizarov1f74a2d2018-06-29 19:19:45 +03002 * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
Roman Elizarov507f5d42017-04-19 19:15:34 +03003 */
4
5package kotlinx.coroutines.experimental
6
Roman Elizarovc0d71dc2017-12-21 22:12:43 +03007import kotlin.test.*
Roman Elizarov507f5d42017-04-19 19:15:34 +03008import java.util.concurrent.ExecutorService
9import java.util.concurrent.Executors
10import java.util.concurrent.ThreadFactory
Roman Elizarovca9d5be2017-04-20 19:23:18 +030011import java.util.concurrent.atomic.AtomicInteger
Roman Elizarov507f5d42017-04-19 19:15:34 +030012import kotlin.coroutines.experimental.CoroutineContext
13
14class WithTimeoutOrNullThreadDispatchTest : TestBase() {
15 var executor: ExecutorService? = null
16
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030017 @AfterTest
Roman Elizarov507f5d42017-04-19 19:15:34 +030018 fun tearDown() {
19 executor?.shutdown()
20 }
21
22 @Test
23 fun testCancellationDispatchScheduled() {
24 checkCancellationDispatch {
25 executor = Executors.newScheduledThreadPool(1, it)
26 executor!!.asCoroutineDispatcher()
27 }
28 }
29
30 @Test
31 fun testCancellationDispatchNonScheduled() {
32 checkCancellationDispatch {
33 executor = Executors.newSingleThreadExecutor(it)
34 executor!!.asCoroutineDispatcher()
35 }
36 }
37
38 @Test
39 fun testCancellationDispatchCustomNoDelay() {
Roman Elizarovca9d5be2017-04-20 19:23:18 +030040 // it also checks that there is at most once scheduled request in flight (no spurious concurrency)
41 var error: String? = null
Roman Elizarov507f5d42017-04-19 19:15:34 +030042 checkCancellationDispatch {
43 executor = Executors.newSingleThreadExecutor(it)
Roman Elizarovca9d5be2017-04-20 19:23:18 +030044 val scheduled = AtomicInteger(0)
Roman Elizarov507f5d42017-04-19 19:15:34 +030045 object : CoroutineDispatcher() {
46 override fun dispatch(context: CoroutineContext, block: Runnable) {
Roman Elizarovca9d5be2017-04-20 19:23:18 +030047 if (scheduled.incrementAndGet() > 1) error = "Two requests are scheduled concurrently"
48 executor!!.execute {
49 scheduled.decrementAndGet()
50 block.run()
51 }
Roman Elizarov507f5d42017-04-19 19:15:34 +030052 }
53 }
54 }
Roman Elizarovca9d5be2017-04-20 19:23:18 +030055 error?.let { error(it) }
Roman Elizarov507f5d42017-04-19 19:15:34 +030056 }
57
58 private fun checkCancellationDispatch(factory: (ThreadFactory) -> CoroutineDispatcher) = runBlocking {
59 expect(1)
60 var thread: Thread? = null
61 val dispatcher = factory(ThreadFactory { Thread(it).also { thread = it } })
Roman Elizarovf9e13f52017-12-21 12:23:15 +030062 withContext(dispatcher) {
Roman Elizarov507f5d42017-04-19 19:15:34 +030063 expect(2)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030064 assertEquals(thread, Thread.currentThread())
Roman Elizarovca9d5be2017-04-20 19:23:18 +030065 val result = withTimeoutOrNull(100) {
66 try {
67 expect(3)
68 delay(1000)
69 expectUnreached()
70 } catch (e: CancellationException) {
71 expect(4)
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030072 assertEquals(thread, Thread.currentThread())
Roman Elizarovca9d5be2017-04-20 19:23:18 +030073 throw e // rethrow
Roman Elizarov507f5d42017-04-19 19:15:34 +030074 }
Roman Elizarovca9d5be2017-04-20 19:23:18 +030075 }
Roman Elizarovc0d71dc2017-12-21 22:12:43 +030076 assertEquals(thread, Thread.currentThread())
77 assertEquals(null, result)
Roman Elizarovca9d5be2017-04-20 19:23:18 +030078 expect(5)
Roman Elizarov507f5d42017-04-19 19:15:34 +030079 }
Roman Elizarovca9d5be2017-04-20 19:23:18 +030080 finish(6)
Roman Elizarov507f5d42017-04-19 19:15:34 +030081 }
82}