blob: 9a7c076d59c92303caa0001ba56288ef263ca7d8 [file] [log] [blame]
Rob Pike1b569472010-04-13 13:49:42 -07001// Copyright 2010 The Go Authors. All rights reserved.
Rob Pike4d45dd32010-01-20 14:12:29 +11002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package netchan
6
Rob Pikeda705c62010-09-20 15:28:38 +10007import (
Roger Peppe1a963912011-02-16 08:14:41 -08008 "net"
Rob Pikeda705c62010-09-20 15:28:38 +10009 "strings"
10 "testing"
11 "time"
12)
Rob Pike4d45dd32010-01-20 14:12:29 +110013
Rob Pike752b47c2010-05-28 22:32:29 -070014const count = 10 // number of items in most tests
15const closeCount = 5 // number of items when sender closes early
Rob Pike1b569472010-04-13 13:49:42 -070016
Rob Pike1e4b1f92010-09-20 10:14:39 +100017const base = 23
18
Roger Peppe6fb1bf22011-01-19 12:28:49 -080019func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
Rob Pikeeb20ba62010-06-28 15:59:54 -070020 ch := make(chan int)
Rob Piked4384ff72010-06-28 17:12:09 -070021 err := exp.Export("exportedSend", ch, Send)
Rob Pike4d45dd32010-01-20 14:12:29 +110022 if err != nil {
Rob Pike1b569472010-04-13 13:49:42 -070023 t.Fatal("exportSend:", err)
Rob Pike4d45dd32010-01-20 14:12:29 +110024 }
Ian Lance Taylorb279c042010-08-26 15:42:18 -070025 go func() {
26 for i := 0; i < n; i++ {
Robert Griesemer288a39c2011-02-01 13:47:51 -080027 ch <- base + i
Ian Lance Taylorb279c042010-08-26 15:42:18 -070028 }
29 close(ch)
Roger Peppe6fb1bf22011-01-19 12:28:49 -080030 if done != nil {
31 done <- true
32 }
Ian Lance Taylorb279c042010-08-26 15:42:18 -070033 }()
Rob Pike1b569472010-04-13 13:49:42 -070034}
35
Roger Pepped465ea52010-10-12 15:05:53 -070036func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
Rob Pikeeb20ba62010-06-28 15:59:54 -070037 ch := make(chan int)
Rob Piked4384ff72010-06-28 17:12:09 -070038 err := exp.Export("exportedRecv", ch, Recv)
Roger Pepped465ea52010-10-12 15:05:53 -070039 expDone <- true
Rob Pike1b569472010-04-13 13:49:42 -070040 if err != nil {
41 t.Fatal("exportReceive:", err)
42 }
43 for i := 0; i < count; i++ {
Russ Cox3f915f52011-03-11 14:47:44 -050044 v, ok := <-ch
45 if !ok {
Rob Pike1e4b1f92010-09-20 10:14:39 +100046 if i != closeCount {
Rob Pike1959c3a2010-09-23 13:48:56 +100047 t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
Rob Pike1e4b1f92010-09-20 10:14:39 +100048 }
49 break
50 }
51 if v != base+i {
52 t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
Rob Pike1b569472010-04-13 13:49:42 -070053 }
54 }
Rob Pike4d45dd32010-01-20 14:12:29 +110055}
56
Roger Peppe6fb1bf22011-01-19 12:28:49 -080057func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
Rob Pike1e4b1f92010-09-20 10:14:39 +100058 ch := make(chan int)
Roger Peppe6fb1bf22011-01-19 12:28:49 -080059 err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
Rob Pike1e4b1f92010-09-20 10:14:39 +100060 if err != nil {
61 t.Fatal("importSend:", err)
62 }
63 go func() {
64 for i := 0; i < n; i++ {
Robert Griesemer288a39c2011-02-01 13:47:51 -080065 ch <- base + i
Rob Pike1e4b1f92010-09-20 10:14:39 +100066 }
67 close(ch)
Roger Peppe6fb1bf22011-01-19 12:28:49 -080068 if done != nil {
69 done <- true
70 }
Rob Pike1e4b1f92010-09-20 10:14:39 +100071 }()
72}
73
Rob Piked54b9212010-09-04 23:41:54 +100074func importReceive(imp *Importer, t *testing.T, done chan bool) {
Rob Pikeeb20ba62010-06-28 15:59:54 -070075 ch := make(chan int)
Roger Peppe6fb1bf22011-01-19 12:28:49 -080076 err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
Rob Pike4d45dd32010-01-20 14:12:29 +110077 if err != nil {
Rob Pike1b569472010-04-13 13:49:42 -070078 t.Fatal("importReceive:", err)
Rob Pike4d45dd32010-01-20 14:12:29 +110079 }
Rob Pike1b569472010-04-13 13:49:42 -070080 for i := 0; i < count; i++ {
Russ Cox3f915f52011-03-11 14:47:44 -050081 v, ok := <-ch
82 if !ok {
Rob Pike752b47c2010-05-28 22:32:29 -070083 if i != closeCount {
Rob Pike1959c3a2010-09-23 13:48:56 +100084 t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
Rob Pike752b47c2010-05-28 22:32:29 -070085 }
86 break
87 }
Roger Peppe6fb1bf22011-01-19 12:28:49 -080088 if v != base+i {
Rob Pike1ce62452010-12-07 16:42:54 -050089 t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
Rob Pike1b569472010-04-13 13:49:42 -070090 }
Rob Pike4d45dd32010-01-20 14:12:29 +110091 }
Rob Piked54b9212010-09-04 23:41:54 +100092 if done != nil {
93 done <- true
94 }
Rob Pike4d45dd32010-01-20 14:12:29 +110095}
96
Rob Pike1b569472010-04-13 13:49:42 -070097func TestExportSendImportReceive(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -080098 exp, imp := pair(t)
Roger Peppe6fb1bf22011-01-19 12:28:49 -080099 exportSend(exp, count, t, nil)
Rob Piked54b9212010-09-04 23:41:54 +1000100 importReceive(imp, t, nil)
Rob Pike4d45dd32010-01-20 14:12:29 +1100101}
Rob Pike1b569472010-04-13 13:49:42 -0700102
103func TestExportReceiveImportSend(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800104 exp, imp := pair(t)
Roger Pepped465ea52010-10-12 15:05:53 -0700105 expDone := make(chan bool)
106 done := make(chan bool)
107 go func() {
108 exportReceive(exp, t, expDone)
109 done <- true
110 }()
111 <-expDone
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800112 importSend(imp, count, t, nil)
Roger Pepped465ea52010-10-12 15:05:53 -0700113 <-done
Rob Pike1b569472010-04-13 13:49:42 -0700114}
Rob Pike752b47c2010-05-28 22:32:29 -0700115
116func TestClosingExportSendImportReceive(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800117 exp, imp := pair(t)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800118 exportSend(exp, closeCount, t, nil)
Rob Piked54b9212010-09-04 23:41:54 +1000119 importReceive(imp, t, nil)
120}
121
Rob Pike1e4b1f92010-09-20 10:14:39 +1000122func TestClosingImportSendExportReceive(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800123 exp, imp := pair(t)
Roger Pepped465ea52010-10-12 15:05:53 -0700124 expDone := make(chan bool)
125 done := make(chan bool)
126 go func() {
127 exportReceive(exp, t, expDone)
128 done <- true
129 }()
130 <-expDone
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800131 importSend(imp, closeCount, t, nil)
Roger Pepped465ea52010-10-12 15:05:53 -0700132 <-done
Rob Pike1e4b1f92010-09-20 10:14:39 +1000133}
134
Rob Pikeda705c62010-09-20 15:28:38 +1000135func TestErrorForIllegalChannel(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800136 exp, imp := pair(t)
Rob Pikeda705c62010-09-20 15:28:38 +1000137 // Now export a channel.
138 ch := make(chan int, 1)
Roger Peppe1a963912011-02-16 08:14:41 -0800139 err := exp.Export("aChannel", ch, Send)
Rob Pikeda705c62010-09-20 15:28:38 +1000140 if err != nil {
141 t.Fatal("export:", err)
142 }
143 ch <- 1234
144 close(ch)
145 // Now try to import a different channel.
146 ch = make(chan int)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800147 err = imp.Import("notAChannel", ch, Recv, 1)
Rob Pikeda705c62010-09-20 15:28:38 +1000148 if err != nil {
149 t.Fatal("import:", err)
150 }
151 // Expect an error now. Start a timeout.
152 timeout := make(chan bool, 1) // buffered so closure will not hang around.
153 go func() {
David Symonds3dbecd52011-12-13 10:42:56 +1100154 time.Sleep(10 * time.Second) // very long, to give even really slow machines a chance.
Rob Pikeda705c62010-09-20 15:28:38 +1000155 timeout <- true
156 }()
157 select {
158 case err = <-imp.Errors():
Russ Coxeb692922011-11-01 22:05:34 -0400159 if strings.Index(err.Error(), "no such channel") < 0 {
Rob Pike724886b2010-09-20 17:24:40 +1000160 t.Error("wrong error for nonexistent channel:", err)
Rob Pikeda705c62010-09-20 15:28:38 +1000161 }
162 case <-timeout:
163 t.Error("import of nonexistent channel did not receive an error")
164 }
165}
166
Rob Piked54b9212010-09-04 23:41:54 +1000167// Not a great test but it does at least invoke Drain.
168func TestExportDrain(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800169 exp, imp := pair(t)
Rob Piked54b9212010-09-04 23:41:54 +1000170 done := make(chan bool)
Roger Pepped465ea52010-10-12 15:05:53 -0700171 go func() {
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800172 exportSend(exp, closeCount, t, nil)
Roger Pepped465ea52010-10-12 15:05:53 -0700173 done <- true
174 }()
175 <-done
Rob Piked54b9212010-09-04 23:41:54 +1000176 go importReceive(imp, t, done)
177 exp.Drain(0)
178 <-done
179}
180
David Jakob Fritzce877ac2011-06-06 06:55:32 +0000181// Not a great test but it does at least invoke Drain.
182func TestImportDrain(t *testing.T) {
183 exp, imp := pair(t)
184 expDone := make(chan bool)
185 go exportReceive(exp, t, expDone)
186 <-expDone
187 importSend(imp, closeCount, t, nil)
188 imp.Drain(0)
189}
190
Rob Piked54b9212010-09-04 23:41:54 +1000191// Not a great test but it does at least invoke Sync.
192func TestExportSync(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800193 exp, imp := pair(t)
Rob Piked54b9212010-09-04 23:41:54 +1000194 done := make(chan bool)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800195 exportSend(exp, closeCount, t, nil)
Roger Pepped465ea52010-10-12 15:05:53 -0700196 go importReceive(imp, t, done)
Rob Piked54b9212010-09-04 23:41:54 +1000197 exp.Sync(0)
198 <-done
Rob Pike752b47c2010-05-28 22:32:29 -0700199}
Rob Pike19075ea2010-09-17 07:12:54 +1000200
Rob Pike1ffb1f22010-10-18 15:09:43 -0700201// Test hanging up the send side of an export.
202// TODO: test hanging up the receive side of an export.
203func TestExportHangup(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800204 exp, imp := pair(t)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700205 ech := make(chan int)
Roger Peppe1a963912011-02-16 08:14:41 -0800206 err := exp.Export("exportedSend", ech, Send)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700207 if err != nil {
208 t.Fatal("export:", err)
209 }
210 // Prepare to receive two values. We'll actually deliver only one.
211 ich := make(chan int)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800212 err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700213 if err != nil {
214 t.Fatal("import exportedSend:", err)
215 }
216 // Send one value, receive it.
217 const Value = 1234
218 ech <- Value
219 v := <-ich
220 if v != Value {
221 t.Fatal("expected", Value, "got", v)
222 }
223 // Now hang up the channel. Importer should see it close.
224 exp.Hangup("exportedSend")
Russ Cox3f915f52011-03-11 14:47:44 -0500225 v, ok := <-ich
226 if ok {
Rob Pike1ffb1f22010-10-18 15:09:43 -0700227 t.Fatal("expected channel to be closed; got value", v)
228 }
229}
230
231// Test hanging up the send side of an import.
232// TODO: test hanging up the receive side of an import.
233func TestImportHangup(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800234 exp, imp := pair(t)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700235 ech := make(chan int)
Roger Peppe1a963912011-02-16 08:14:41 -0800236 err := exp.Export("exportedRecv", ech, Recv)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700237 if err != nil {
238 t.Fatal("export:", err)
239 }
240 // Prepare to Send two values. We'll actually deliver only one.
241 ich := make(chan int)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800242 err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
Rob Pike1ffb1f22010-10-18 15:09:43 -0700243 if err != nil {
244 t.Fatal("import exportedRecv:", err)
245 }
246 // Send one value, receive it.
247 const Value = 1234
248 ich <- Value
249 v := <-ech
250 if v != Value {
251 t.Fatal("expected", Value, "got", v)
252 }
253 // Now hang up the channel. Exporter should see it close.
254 imp.Hangup("exportedRecv")
Russ Cox3f915f52011-03-11 14:47:44 -0500255 v, ok := <-ech
256 if ok {
Rob Pike1ffb1f22010-10-18 15:09:43 -0700257 t.Fatal("expected channel to be closed; got value", v)
258 }
259}
260
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800261// loop back exportedRecv to exportedSend,
262// but receive a value from ctlch before starting the loop.
263func exportLoopback(exp *Exporter, t *testing.T) {
264 inch := make(chan int)
265 if err := exp.Export("exportedRecv", inch, Recv); err != nil {
266 t.Fatal("exportRecv")
267 }
268
269 outch := make(chan int)
270 if err := exp.Export("exportedSend", outch, Send); err != nil {
271 t.Fatal("exportSend")
272 }
273
274 ctlch := make(chan int)
275 if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
276 t.Fatal("exportRecv")
277 }
278
279 go func() {
280 <-ctlch
281 for i := 0; i < count; i++ {
282 x := <-inch
283 if x != base+i {
284 t.Errorf("exportLoopback expected %d; got %d", i, x)
285 }
286 outch <- x
287 }
288 }()
289}
290
291// This test checks that channel operations can proceed
292// even when other concurrent operations are blocked.
293func TestIndependentSends(t *testing.T) {
Russ Cox0e70f272012-02-18 16:24:23 -0500294 if testing.Short() {
295 t.Logf("disabled test during -short")
296 return
297 }
Roger Peppe1a963912011-02-16 08:14:41 -0800298 exp, imp := pair(t)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800299
300 exportLoopback(exp, t)
301
302 importSend(imp, count, t, nil)
303 done := make(chan bool)
304 go importReceive(imp, t, done)
305
306 // wait for export side to try to deliver some values.
David Symonds3dbecd52011-12-13 10:42:56 +1100307 time.Sleep(250 * time.Millisecond)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800308
309 ctlch := make(chan int)
310 if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
311 t.Fatal("importSend:", err)
312 }
313 ctlch <- 0
314
315 <-done
316}
317
Rob Pike1ffb1f22010-10-18 15:09:43 -0700318// This test cross-connects a pair of exporter/importer pairs.
Rob Pike19075ea2010-09-17 07:12:54 +1000319type value struct {
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800320 I int
321 Source string
Rob Pike19075ea2010-09-17 07:12:54 +1000322}
323
Rob Pike19075ea2010-09-17 07:12:54 +1000324func TestCrossConnect(t *testing.T) {
Roger Peppe1a963912011-02-16 08:14:41 -0800325 e1, i1 := pair(t)
326 e2, i2 := pair(t)
Rob Pike19075ea2010-09-17 07:12:54 +1000327
Ian Lance Taylor9a9c1562011-01-26 15:51:04 -0800328 crossExport(e1, e2, t)
Rob Pike19075ea2010-09-17 07:12:54 +1000329 crossImport(i1, i2, t)
330}
331
332// Export side of cross-traffic.
333func crossExport(e1, e2 *Exporter, t *testing.T) {
334 s := make(chan value)
335 err := e1.Export("exportedSend", s, Send)
336 if err != nil {
337 t.Fatal("exportSend:", err)
338 }
339
340 r := make(chan value)
341 err = e2.Export("exportedReceive", r, Recv)
342 if err != nil {
343 t.Fatal("exportReceive:", err)
344 }
345
Ian Lance Taylor9a9c1562011-01-26 15:51:04 -0800346 go crossLoop("export", s, r, t)
Rob Pike19075ea2010-09-17 07:12:54 +1000347}
348
349// Import side of cross-traffic.
350func crossImport(i1, i2 *Importer, t *testing.T) {
351 s := make(chan value)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800352 err := i2.Import("exportedReceive", s, Send, 2)
Rob Pike19075ea2010-09-17 07:12:54 +1000353 if err != nil {
354 t.Fatal("import of exportedReceive:", err)
355 }
356
357 r := make(chan value)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800358 err = i1.Import("exportedSend", r, Recv, 2)
Rob Pike19075ea2010-09-17 07:12:54 +1000359 if err != nil {
360 t.Fatal("import of exported Send:", err)
361 }
362
363 crossLoop("import", s, r, t)
364}
365
366// Cross-traffic: send and receive 'count' numbers.
367func crossLoop(name string, s, r chan value, t *testing.T) {
368 for si, ri := 0, 0; si < count && ri < count; {
369 select {
370 case s <- value{si, name}:
371 si++
372 case v := <-r:
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800373 if v.I != ri {
Rob Pike19075ea2010-09-17 07:12:54 +1000374 t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
375 }
376 ri++
377 }
378 }
379}
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800380
381const flowCount = 100
382
383// test flow control from exporter to importer.
384func TestExportFlowControl(t *testing.T) {
Russ Cox0e70f272012-02-18 16:24:23 -0500385 if testing.Short() {
386 t.Logf("disabled test during -short")
387 return
388 }
Roger Peppe1a963912011-02-16 08:14:41 -0800389 exp, imp := pair(t)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800390
391 sendDone := make(chan bool, 1)
392 exportSend(exp, flowCount, t, sendDone)
393
394 ch := make(chan int)
Roger Peppe1a963912011-02-16 08:14:41 -0800395 err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800396 if err != nil {
397 t.Fatal("importReceive:", err)
398 }
399
400 testFlow(sendDone, ch, flowCount, t)
401}
402
403// test flow control from importer to exporter.
404func TestImportFlowControl(t *testing.T) {
Russ Cox0e70f272012-02-18 16:24:23 -0500405 if testing.Short() {
406 t.Logf("disabled test during -short")
407 return
408 }
Roger Peppe1a963912011-02-16 08:14:41 -0800409 exp, imp := pair(t)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800410
411 ch := make(chan int)
Roger Peppe1a963912011-02-16 08:14:41 -0800412 err := exp.Export("exportedRecv", ch, Recv)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800413 if err != nil {
414 t.Fatal("importReceive:", err)
415 }
416
417 sendDone := make(chan bool, 1)
418 importSend(imp, flowCount, t, sendDone)
419 testFlow(sendDone, ch, flowCount, t)
420}
421
422func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
423 go func() {
David Symonds3dbecd52011-12-13 10:42:56 +1100424 time.Sleep(500 * time.Millisecond)
Roger Peppe6fb1bf22011-01-19 12:28:49 -0800425 sendDone <- false
426 }()
427
428 if <-sendDone {
429 t.Fatal("send did not block")
430 }
431 n := 0
432 for i := range ch {
433 t.Log("after blocking, got value ", i)
434 n++
435 }
436 if n != N {
437 t.Fatalf("expected %d values; got %d", N, n)
438 }
439}
Roger Peppe1a963912011-02-16 08:14:41 -0800440
441func pair(t *testing.T) (*Exporter, *Importer) {
442 c0, c1 := net.Pipe()
443 exp := NewExporter()
444 go exp.ServeConn(c0)
445 imp := NewImporter(c1)
446 return exp, imp
447}