Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 1 | /* |
Roman Elizarov | 1f74a2d | 2018-06-29 19:19:45 +0300 | [diff] [blame^] | 2 | * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 3 | */ |
| 4 | |
| 5 | package kotlinx.coroutines.experimental.channels |
| 6 | |
Roman Elizarov | 9fe5f46 | 2018-02-21 19:05:52 +0300 | [diff] [blame] | 7 | import kotlinx.coroutines.experimental.* |
| 8 | import org.hamcrest.core.* |
| 9 | import org.junit.* |
| 10 | import org.junit.Assert.* |
Vsevolod Tolstopyatov | f5e63ca | 2018-04-12 19:59:56 +0300 | [diff] [blame] | 11 | import org.junit.runner.* |
| 12 | import org.junit.runners.* |
| 13 | import java.io.* |
Roman Elizarov | 9fe5f46 | 2018-02-21 19:05:52 +0300 | [diff] [blame] | 14 | import kotlin.coroutines.experimental.* |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 15 | |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 16 | @RunWith(Parameterized::class) |
| 17 | class ActorTest(private val capacity: Int) : TestBase() { |
| 18 | |
| 19 | companion object { |
| 20 | @Parameterized.Parameters(name = "Capacity: {0}") |
| 21 | @JvmStatic |
| 22 | fun params(): Collection<Array<Any>> = listOf(0, 1, Channel.UNLIMITED, Channel.CONFLATED).map { arrayOf<Any>(it) } |
| 23 | } |
| 24 | |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 25 | @Test |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 26 | fun testEmpty() = runBlocking { |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 27 | expect(1) |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 28 | val actor = actor<String>(coroutineContext, capacity) { |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 29 | expect(3) |
| 30 | } |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 31 | actor as Job // type assertion |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 32 | assertThat(actor.isActive, IsEqual(true)) |
| 33 | assertThat(actor.isCompleted, IsEqual(false)) |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 34 | assertThat(actor.isClosedForSend, IsEqual(false)) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 35 | expect(2) |
| 36 | yield() // to actor code |
| 37 | assertThat(actor.isActive, IsEqual(false)) |
| 38 | assertThat(actor.isCompleted, IsEqual(true)) |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 39 | assertThat(actor.isClosedForSend, IsEqual(true)) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 40 | finish(4) |
| 41 | } |
| 42 | |
| 43 | @Test |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 44 | fun testOne() = runBlocking { |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 45 | expect(1) |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 46 | val actor = actor<String>(coroutineContext, capacity) { |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 47 | expect(3) |
| 48 | assertThat(receive(), IsEqual("OK")) |
| 49 | expect(6) |
| 50 | } |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 51 | actor as Job // type assertion |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 52 | assertThat(actor.isActive, IsEqual(true)) |
| 53 | assertThat(actor.isCompleted, IsEqual(false)) |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 54 | assertThat(actor.isClosedForSend, IsEqual(false)) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 55 | expect(2) |
| 56 | yield() // to actor code |
| 57 | assertThat(actor.isActive, IsEqual(true)) |
| 58 | assertThat(actor.isCompleted, IsEqual(false)) |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 59 | assertThat(actor.isClosedForSend, IsEqual(false)) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 60 | expect(4) |
| 61 | // send message to actor |
| 62 | actor.send("OK") |
| 63 | expect(5) |
| 64 | yield() // to actor code |
| 65 | assertThat(actor.isActive, IsEqual(false)) |
| 66 | assertThat(actor.isCompleted, IsEqual(true)) |
Roman Elizarov | b555d91 | 2017-08-17 21:01:33 +0300 | [diff] [blame] | 67 | assertThat(actor.isClosedForSend, IsEqual(true)) |
Roman Elizarov | ecda27f | 2017-04-06 23:06:26 +0300 | [diff] [blame] | 68 | finish(7) |
| 69 | } |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 70 | |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 71 | @Test |
Vsevolod Tolstopyatov | f5e63ca | 2018-04-12 19:59:56 +0300 | [diff] [blame] | 72 | fun testCloseWithoutCause() = runTest { |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 73 | val actor = actor<Int>(coroutineContext, capacity) { |
| 74 | val element = channel.receiveOrNull() |
| 75 | expect(2) |
| 76 | assertEquals(42, element) |
| 77 | val next = channel.receiveOrNull() |
| 78 | assertNull(next) |
| 79 | expect(3) |
| 80 | } |
| 81 | |
| 82 | expect(1) |
| 83 | actor.send(42) |
| 84 | yield() |
| 85 | actor.close() |
| 86 | yield() |
| 87 | finish(4) |
| 88 | } |
| 89 | |
| 90 | @Test |
Vsevolod Tolstopyatov | f5e63ca | 2018-04-12 19:59:56 +0300 | [diff] [blame] | 91 | fun testCloseWithCause() = runTest { |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 92 | val actor = actor<Int>(coroutineContext, capacity) { |
| 93 | val element = channel.receiveOrNull() |
| 94 | expect(2) |
| 95 | require(element!! == 42) |
| 96 | try { |
Vsevolod Tolstopyatov | 87f2faa | 2018-04-30 22:53:02 +0300 | [diff] [blame] | 97 | channel.receiveOrNull() |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 98 | } catch (e: IOException) { |
| 99 | expect(3) |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | expect(1) |
| 104 | actor.send(42) |
| 105 | yield() |
| 106 | actor.close(IOException()) |
| 107 | yield() |
| 108 | finish(4) |
| 109 | } |
Vsevolod Tolstopyatov | f5e63ca | 2018-04-12 19:59:56 +0300 | [diff] [blame] | 110 | |
| 111 | @Test |
| 112 | fun testCancelEnclosingJob() = runTest { |
| 113 | val job = async(coroutineContext) { |
| 114 | actor<Int>(coroutineContext, capacity) { |
| 115 | expect(1) |
| 116 | channel.receiveOrNull() |
| 117 | expectUnreached() |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | yield() |
| 122 | yield() |
| 123 | |
| 124 | expect(2) |
| 125 | yield() |
| 126 | job.cancel() |
| 127 | |
| 128 | try { |
| 129 | job.await() |
| 130 | expectUnreached() |
| 131 | } catch (e: JobCancellationException) { |
| 132 | assertTrue(e.message?.contains("Job was cancelled normally") ?: false) |
| 133 | } |
| 134 | |
| 135 | finish(3) |
| 136 | } |
Vsevolod Tolstopyatov | fd42442 | 2018-05-23 18:48:37 +0300 | [diff] [blame] | 137 | |
| 138 | @Test |
| 139 | fun testThrowingActor() = runTest(unhandled = listOf({e -> e is IllegalArgumentException})) { |
| 140 | val parent = Job() |
| 141 | val actor = actor<Int>(context = coroutineContext, parent = parent) { |
| 142 | channel.consumeEach { |
| 143 | expect(1) |
| 144 | throw IllegalArgumentException() |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | actor.send(1) |
| 149 | parent.cancel() |
| 150 | parent.join() |
| 151 | finish(2) |
| 152 | } |
Vsevolod Tolstopyatov | 4b9a559 | 2018-04-11 13:17:14 +0300 | [diff] [blame] | 153 | } |