blob: 2b1b98793a840957edc8c90766eed35317f6b806 [file] [log] [blame]
Roman Elizarovf16fd272017-02-07 11:26:00 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Roman Elizarov187eace2017-01-31 09:39:58 +030017package kotlinx.coroutines.experimental.channels
18
Roman Elizarovb555d912017-08-17 21:01:33 +030019import kotlinx.coroutines.experimental.*
Roman Elizarov9fe5f462018-02-21 19:05:52 +030020import kotlin.coroutines.experimental.*
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030021import kotlin.test.*
Roman Elizarov187eace2017-01-31 09:39:58 +030022
23class RendezvousChannelTest : TestBase() {
24 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030025 fun testSimple() = runTest {
Roman Elizarov187eace2017-01-31 09:39:58 +030026 val q = RendezvousChannel<Int>()
27 check(q.isEmpty && q.isFull)
28 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +030029 val sender = launch(coroutineContext) {
Roman Elizarov187eace2017-01-31 09:39:58 +030030 expect(4)
31 q.send(1) // suspend -- the first to come to rendezvous
32 expect(7)
33 q.send(2) // does not suspend -- receiver is there
34 expect(8)
35 }
36 expect(2)
Roman Elizarov43e3af72017-07-21 16:01:31 +030037 val receiver = launch(coroutineContext) {
Roman Elizarov187eace2017-01-31 09:39:58 +030038 expect(5)
39 check(q.receive() == 1) // does not suspend -- sender was there
40 expect(6)
41 check(q.receive() == 2) // suspends
42 expect(9)
43 }
44 expect(3)
45 sender.join()
46 receiver.join()
47 check(q.isEmpty && q.isFull)
48 finish(10)
49 }
50
51 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030052 fun testClosedReceiveOrNull() = runTest {
Roman Elizarov187eace2017-01-31 09:39:58 +030053 val q = RendezvousChannel<Int>()
54 check(q.isEmpty && q.isFull && !q.isClosedForSend && !q.isClosedForReceive)
55 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +030056 launch(coroutineContext) {
Roman Elizarov187eace2017-01-31 09:39:58 +030057 expect(3)
58 assertEquals(42, q.receiveOrNull())
59 expect(4)
60 assertEquals(null, q.receiveOrNull())
61 expect(6)
62 }
63 expect(2)
64 q.send(42)
65 expect(5)
66 q.close()
67 check(!q.isEmpty && !q.isFull && q.isClosedForSend && q.isClosedForReceive)
68 yield()
69 check(!q.isEmpty && !q.isFull && q.isClosedForSend && q.isClosedForReceive)
70 finish(7)
71 }
72
73 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030074 fun testClosedExceptions() = runTest {
Roman Elizarov187eace2017-01-31 09:39:58 +030075 val q = RendezvousChannel<Int>()
76 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +030077 launch(coroutineContext) {
Roman Elizarov187eace2017-01-31 09:39:58 +030078 expect(4)
79 try { q.receive() }
80 catch (e: ClosedReceiveChannelException) {
81 expect(5)
82 }
83 }
84 expect(2)
85 q.close()
86 expect(3)
87 yield()
88 expect(6)
89 try { q.send(42) }
90 catch (e: ClosedSendChannelException) {
91 finish(7)
92 }
93 }
94
95 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +030096 fun testOfferAndPool() = runTest {
Roman Elizarov187eace2017-01-31 09:39:58 +030097 val q = RendezvousChannel<Int>()
98 assertFalse(q.offer(1))
99 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300100 launch(coroutineContext) {
Roman Elizarov187eace2017-01-31 09:39:58 +0300101 expect(3)
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300102 assertEquals(null, q.poll())
Roman Elizarov187eace2017-01-31 09:39:58 +0300103 expect(4)
104 assertEquals(2, q.receive())
105 expect(7)
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300106 assertEquals(null, q.poll())
Roman Elizarov187eace2017-01-31 09:39:58 +0300107 yield()
108 expect(9)
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300109 assertEquals(3, q.poll())
Roman Elizarov187eace2017-01-31 09:39:58 +0300110 expect(10)
111 }
112 expect(2)
113 yield()
114 expect(5)
115 assertTrue(q.offer(2))
116 expect(6)
117 yield()
118 expect(8)
119 q.send(3)
120 finish(11)
121 }
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300122
123 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300124 fun testIteratorClosed() = runTest {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300125 val q = RendezvousChannel<Int>()
126 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300127 launch(coroutineContext) {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300128 expect(3)
129 q.close()
130 expect(4)
131 }
132 expect(2)
133 for (x in q) {
134 expectUnreached()
135 }
136 finish(5)
137 }
138
139 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300140 fun testIteratorOne() = runTest {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300141 val q = RendezvousChannel<Int>()
142 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300143 launch(coroutineContext) {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300144 expect(3)
145 q.send(1)
146 expect(4)
147 q.close()
148 expect(5)
149 }
150 expect(2)
151 for (x in q) {
152 expect(6)
153 assertEquals(1, x)
154 }
155 finish(7)
156 }
157
158 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300159 fun testIteratorOneWithYield() = runTest {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300160 val q = RendezvousChannel<Int>()
161 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300162 launch(coroutineContext) {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300163 expect(3)
164 q.send(1) // will suspend
165 expect(6)
166 q.close()
167 expect(7)
168 }
169 expect(2)
170 yield() // yield to sender coroutine right before starting for loop
171 expect(4)
172 for (x in q) {
173 expect(5)
174 assertEquals(1, x)
175 }
176 finish(8)
177 }
178
179 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300180 fun testIteratorTwo() = runTest {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300181 val q = RendezvousChannel<Int>()
182 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300183 launch(coroutineContext) {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300184 expect(3)
185 q.send(1)
186 expect(4)
187 q.send(2)
188 expect(7)
189 q.close()
190 expect(8)
191 }
192 expect(2)
193 for (x in q) {
194 when (x) {
195 1 -> expect(5)
196 2 -> expect(6)
197 else -> expectUnreached()
198 }
199 }
200 finish(9)
201 }
202
203 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300204 fun testIteratorTwoWithYield() = runTest {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300205 val q = RendezvousChannel<Int>()
206 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300207 launch(coroutineContext) {
Roman Elizarov7b2d8b02017-02-02 20:09:14 +0300208 expect(3)
209 q.send(1) // will suspend
210 expect(6)
211 q.send(2)
212 expect(7)
213 q.close()
214 expect(8)
215 }
216 expect(2)
217 yield() // yield to sender coroutine right before starting for loop
218 expect(4)
219 for (x in q) {
220 when (x) {
221 1 -> expect(5)
222 2 -> expect(9)
223 else -> expectUnreached()
224 }
225 }
226 finish(10)
227 }
Roman Elizarovb6b01252017-02-06 13:17:40 +0300228
Roman Elizarov4e601322017-03-17 12:46:36 +0300229 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300230 fun testSuspendSendOnClosedChannel() = runTest {
Roman Elizarov4e601322017-03-17 12:46:36 +0300231 val q = RendezvousChannel<Int>()
232 expect(1)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300233 launch(coroutineContext) {
Roman Elizarov4e601322017-03-17 12:46:36 +0300234 expect(4)
235 q.send(42) // suspend
236 expect(11)
237 }
238 expect(2)
Roman Elizarov43e3af72017-07-21 16:01:31 +0300239 launch(coroutineContext) {
Roman Elizarov4e601322017-03-17 12:46:36 +0300240 expect(5)
241 q.close()
242 expect(6)
243 }
244 expect(3)
245 yield() // to sender
246 expect(7)
247 yield() // try to resume sender (it will not resume despite the close!)
248 expect(8)
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300249 assertEquals(42, q.receiveOrNull())
Roman Elizarov4e601322017-03-17 12:46:36 +0300250 expect(9)
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300251 assertNull(q.receiveOrNull())
Roman Elizarov4e601322017-03-17 12:46:36 +0300252 expect(10)
253 yield() // to sender, it was resumed!
254 finish(12)
255 }
256
Roman Elizarovb6b01252017-02-06 13:17:40 +0300257 class BadClass {
258 override fun equals(other: Any?): Boolean = error("equals")
259 override fun hashCode(): Int = error("hashCode")
260 override fun toString(): String = error("toString")
261 }
262
263 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300264 fun testProduceBadClass() = runTest {
Roman Elizarovb6b01252017-02-06 13:17:40 +0300265 val bad = BadClass()
Roman Elizarov43e3af72017-07-21 16:01:31 +0300266 val c = produce(coroutineContext) {
Roman Elizarovb6b01252017-02-06 13:17:40 +0300267 expect(1)
268 send(bad)
269 }
270 assertTrue(c.receive() === bad)
271 finish(2)
272 }
Roman Elizarovb555d912017-08-17 21:01:33 +0300273
274 @Test
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300275 fun testConsumeAll() = runTest {
Roman Elizarovb555d912017-08-17 21:01:33 +0300276 val q = RendezvousChannel<Int>()
277 for (i in 1..10) {
278 launch(coroutineContext, CoroutineStart.UNDISPATCHED) {
279 expect(i)
280 q.send(i) // suspends
281 expectUnreached() // will get cancelled by cancel
282 }
283 }
284 expect(11)
285 q.cancel()
286 check(q.isClosedForSend)
287 check(q.isClosedForReceive)
288 check(q.receiveOrNull() == null)
289 finish(12)
290 }
Vsevolod Tolstopyatov4b9a5592018-04-11 13:17:14 +0300291
Roman Elizarovf2bdf602018-04-26 11:29:47 +0300292 @Test
293 fun testCancelWithCause() = runTest({ it is TestException }) {
Vsevolod Tolstopyatov4b9a5592018-04-11 13:17:14 +0300294 val channel = RendezvousChannel<Int>()
Roman Elizarovf2bdf602018-04-26 11:29:47 +0300295 channel.cancel(TestException())
Vsevolod Tolstopyatov4b9a5592018-04-11 13:17:14 +0300296 channel.receiveOrNull()
297 }
Roman Elizarovf2bdf602018-04-26 11:29:47 +0300298
299 private class TestException : Exception()
Vsevolod Tolstopyatov96191342018-04-20 18:13:33 +0300300}