1
2
3
4
5 package netchan
6
7 import (
8 "net"
9 "strings"
10 "testing"
11 "time"
12 )
13
14 const count = 10
15 const closeCount = 5
16
17 const base = 23
18
19 func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
20 ch := make(chan int)
21 err := exp.Export("exportedSend", ch, Send)
22 if err != nil {
23 t.Fatal("exportSend:", err)
24 }
25 go func() {
26 for i := 0; i < n; i++ {
27 ch <- base + i
28 }
29 close(ch)
30 if done != nil {
31 done <- true
32 }
33 }()
34 }
35
36 func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
37 ch := make(chan int)
38 err := exp.Export("exportedRecv", ch, Recv)
39 expDone <- true
40 if err != nil {
41 t.Fatal("exportReceive:", err)
42 }
43 for i := 0; i < count; i++ {
44 v, ok := <-ch
45 if !ok {
46 if i != closeCount {
47 t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
48 }
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)
53 }
54 }
55 }
56
57 func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
58 ch := make(chan int)
59 err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
60 if err != nil {
61 t.Fatal("importSend:", err)
62 }
63 go func() {
64 for i := 0; i < n; i++ {
65 ch <- base + i
66 }
67 close(ch)
68 if done != nil {
69 done <- true
70 }
71 }()
72 }
73
74 func importReceive(imp *Importer, t *testing.T, done chan bool) {
75 ch := make(chan int)
76 err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
77 if err != nil {
78 t.Fatal("importReceive:", err)
79 }
80 for i := 0; i < count; i++ {
81 v, ok := <-ch
82 if !ok {
83 if i != closeCount {
84 t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
85 }
86 break
87 }
88 if v != base+i {
89 t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
90 }
91 }
92 if done != nil {
93 done <- true
94 }
95 }
96
97 func TestExportSendImportReceive(t *testing.T) {
98 exp, imp := pair(t)
99 exportSend(exp, count, t, nil)
100 importReceive(imp, t, nil)
101 }
102
103 func TestExportReceiveImportSend(t *testing.T) {
104 exp, imp := pair(t)
105 expDone := make(chan bool)
106 done := make(chan bool)
107 go func() {
108 exportReceive(exp, t, expDone)
109 done <- true
110 }()
111 <-expDone
112 importSend(imp, count, t, nil)
113 <-done
114 }
115
116 func TestClosingExportSendImportReceive(t *testing.T) {
117 exp, imp := pair(t)
118 exportSend(exp, closeCount, t, nil)
119 importReceive(imp, t, nil)
120 }
121
122 func TestClosingImportSendExportReceive(t *testing.T) {
123 exp, imp := pair(t)
124 expDone := make(chan bool)
125 done := make(chan bool)
126 go func() {
127 exportReceive(exp, t, expDone)
128 done <- true
129 }()
130 <-expDone
131 importSend(imp, closeCount, t, nil)
132 <-done
133 }
134
135 func TestErrorForIllegalChannel(t *testing.T) {
136 exp, imp := pair(t)
137
138 ch := make(chan int, 1)
139 err := exp.Export("aChannel", ch, Send)
140 if err != nil {
141 t.Fatal("export:", err)
142 }
143 ch <- 1234
144 close(ch)
145
146 ch = make(chan int)
147 err = imp.Import("notAChannel", ch, Recv, 1)
148 if err != nil {
149 t.Fatal("import:", err)
150 }
151
152 timeout := make(chan bool, 1)
153 go func() {
154 time.Sleep(10e9)
155 timeout <- true
156 }()
157 select {
158 case err = <-imp.Errors():
159 if strings.Index(err.String(), "no such channel") < 0 {
160 t.Error("wrong error for nonexistent channel:", err)
161 }
162 case <-timeout:
163 t.Error("import of nonexistent channel did not receive an error")
164 }
165 }
166
167
168 func TestExportDrain(t *testing.T) {
169 exp, imp := pair(t)
170 done := make(chan bool)
171 go func() {
172 exportSend(exp, closeCount, t, nil)
173 done <- true
174 }()
175 <-done
176 go importReceive(imp, t, done)
177 exp.Drain(0)
178 <-done
179 }
180
181
182 func 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
191
192 func TestExportSync(t *testing.T) {
193 exp, imp := pair(t)
194 done := make(chan bool)
195 exportSend(exp, closeCount, t, nil)
196 go importReceive(imp, t, done)
197 exp.Sync(0)
198 <-done
199 }
200
201
202
203 func TestExportHangup(t *testing.T) {
204 exp, imp := pair(t)
205 ech := make(chan int)
206 err := exp.Export("exportedSend", ech, Send)
207 if err != nil {
208 t.Fatal("export:", err)
209 }
210
211 ich := make(chan int)
212 err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
213 if err != nil {
214 t.Fatal("import exportedSend:", err)
215 }
216
217 const Value = 1234
218 ech <- Value
219 v := <-ich
220 if v != Value {
221 t.Fatal("expected", Value, "got", v)
222 }
223
224 exp.Hangup("exportedSend")
225 v, ok := <-ich
226 if ok {
227 t.Fatal("expected channel to be closed; got value", v)
228 }
229 }
230
231
232
233 func TestImportHangup(t *testing.T) {
234 exp, imp := pair(t)
235 ech := make(chan int)
236 err := exp.Export("exportedRecv", ech, Recv)
237 if err != nil {
238 t.Fatal("export:", err)
239 }
240
241 ich := make(chan int)
242 err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
243 if err != nil {
244 t.Fatal("import exportedRecv:", err)
245 }
246
247 const Value = 1234
248 ich <- Value
249 v := <-ech
250 if v != Value {
251 t.Fatal("expected", Value, "got", v)
252 }
253
254 imp.Hangup("exportedRecv")
255 v, ok := <-ech
256 if ok {
257 t.Fatal("expected channel to be closed; got value", v)
258 }
259 }
260
261
262
263 func 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
292
293 func TestIndependentSends(t *testing.T) {
294 exp, imp := pair(t)
295
296 exportLoopback(exp, t)
297
298 importSend(imp, count, t, nil)
299 done := make(chan bool)
300 go importReceive(imp, t, done)
301
302
303 time.Sleep(0.25e9)
304
305 ctlch := make(chan int)
306 if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
307 t.Fatal("importSend:", err)
308 }
309 ctlch <- 0
310
311 <-done
312 }
313
314
315 type value struct {
316 I int
317 Source string
318 }
319
320 func TestCrossConnect(t *testing.T) {
321 e1, i1 := pair(t)
322 e2, i2 := pair(t)
323
324 crossExport(e1, e2, t)
325 crossImport(i1, i2, t)
326 }
327
328
329 func crossExport(e1, e2 *Exporter, t *testing.T) {
330 s := make(chan value)
331 err := e1.Export("exportedSend", s, Send)
332 if err != nil {
333 t.Fatal("exportSend:", err)
334 }
335
336 r := make(chan value)
337 err = e2.Export("exportedReceive", r, Recv)
338 if err != nil {
339 t.Fatal("exportReceive:", err)
340 }
341
342 go crossLoop("export", s, r, t)
343 }
344
345
346 func crossImport(i1, i2 *Importer, t *testing.T) {
347 s := make(chan value)
348 err := i2.Import("exportedReceive", s, Send, 2)
349 if err != nil {
350 t.Fatal("import of exportedReceive:", err)
351 }
352
353 r := make(chan value)
354 err = i1.Import("exportedSend", r, Recv, 2)
355 if err != nil {
356 t.Fatal("import of exported Send:", err)
357 }
358
359 crossLoop("import", s, r, t)
360 }
361
362
363 func crossLoop(name string, s, r chan value, t *testing.T) {
364 for si, ri := 0, 0; si < count && ri < count; {
365 select {
366 case s <- value{si, name}:
367 si++
368 case v := <-r:
369 if v.I != ri {
370 t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
371 }
372 ri++
373 }
374 }
375 }
376
377 const flowCount = 100
378
379
380 func TestExportFlowControl(t *testing.T) {
381 exp, imp := pair(t)
382
383 sendDone := make(chan bool, 1)
384 exportSend(exp, flowCount, t, sendDone)
385
386 ch := make(chan int)
387 err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
388 if err != nil {
389 t.Fatal("importReceive:", err)
390 }
391
392 testFlow(sendDone, ch, flowCount, t)
393 }
394
395
396 func TestImportFlowControl(t *testing.T) {
397 exp, imp := pair(t)
398
399 ch := make(chan int)
400 err := exp.Export("exportedRecv", ch, Recv)
401 if err != nil {
402 t.Fatal("importReceive:", err)
403 }
404
405 sendDone := make(chan bool, 1)
406 importSend(imp, flowCount, t, sendDone)
407 testFlow(sendDone, ch, flowCount, t)
408 }
409
410 func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
411 go func() {
412 time.Sleep(0.5e9)
413 sendDone <- false
414 }()
415
416 if <-sendDone {
417 t.Fatal("send did not block")
418 }
419 n := 0
420 for i := range ch {
421 t.Log("after blocking, got value ", i)
422 n++
423 }
424 if n != N {
425 t.Fatalf("expected %d values; got %d", N, n)
426 }
427 }
428
429 func pair(t *testing.T) (*Exporter, *Importer) {
430 c0, c1 := net.Pipe()
431 exp := NewExporter()
432 go exp.ServeConn(c0)
433 imp := NewImporter(c1)
434 return exp, imp
435 }