Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 1 | // Copyright 2010 The Go Authors. All rights reserved. |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package netchan |
| 6 | |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 7 | import ( |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 8 | "net" |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 9 | "strings" |
| 10 | "testing" |
| 11 | "time" |
| 12 | ) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 13 | |
Rob Pike | 752b47c | 2010-05-28 22:32:29 -0700 | [diff] [blame] | 14 | const count = 10 // number of items in most tests |
| 15 | const closeCount = 5 // number of items when sender closes early |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 16 | |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 17 | const base = 23 |
| 18 | |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 19 | func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) { |
Rob Pike | eb20ba6 | 2010-06-28 15:59:54 -0700 | [diff] [blame] | 20 | ch := make(chan int) |
Rob Pike | d4384ff7 | 2010-06-28 17:12:09 -0700 | [diff] [blame] | 21 | err := exp.Export("exportedSend", ch, Send) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 22 | if err != nil { |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 23 | t.Fatal("exportSend:", err) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 24 | } |
Ian Lance Taylor | b279c04 | 2010-08-26 15:42:18 -0700 | [diff] [blame] | 25 | go func() { |
| 26 | for i := 0; i < n; i++ { |
Robert Griesemer | 288a39c | 2011-02-01 13:47:51 -0800 | [diff] [blame] | 27 | ch <- base + i |
Ian Lance Taylor | b279c04 | 2010-08-26 15:42:18 -0700 | [diff] [blame] | 28 | } |
| 29 | close(ch) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 30 | if done != nil { |
| 31 | done <- true |
| 32 | } |
Ian Lance Taylor | b279c04 | 2010-08-26 15:42:18 -0700 | [diff] [blame] | 33 | }() |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 34 | } |
| 35 | |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 36 | func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) { |
Rob Pike | eb20ba6 | 2010-06-28 15:59:54 -0700 | [diff] [blame] | 37 | ch := make(chan int) |
Rob Pike | d4384ff7 | 2010-06-28 17:12:09 -0700 | [diff] [blame] | 38 | err := exp.Export("exportedRecv", ch, Recv) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 39 | expDone <- true |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 40 | if err != nil { |
| 41 | t.Fatal("exportReceive:", err) |
| 42 | } |
| 43 | for i := 0; i < count; i++ { |
Russ Cox | 3f915f5 | 2011-03-11 14:47:44 -0500 | [diff] [blame] | 44 | v, ok := <-ch |
| 45 | if !ok { |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 46 | if i != closeCount { |
Rob Pike | 1959c3a | 2010-09-23 13:48:56 +1000 | [diff] [blame] | 47 | t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i) |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 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) |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 53 | } |
| 54 | } |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 55 | } |
| 56 | |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 57 | func importSend(imp *Importer, n int, t *testing.T, done chan bool) { |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 58 | ch := make(chan int) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 59 | err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1) |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 60 | if err != nil { |
| 61 | t.Fatal("importSend:", err) |
| 62 | } |
| 63 | go func() { |
| 64 | for i := 0; i < n; i++ { |
Robert Griesemer | 288a39c | 2011-02-01 13:47:51 -0800 | [diff] [blame] | 65 | ch <- base + i |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 66 | } |
| 67 | close(ch) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 68 | if done != nil { |
| 69 | done <- true |
| 70 | } |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 71 | }() |
| 72 | } |
| 73 | |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 74 | func importReceive(imp *Importer, t *testing.T, done chan bool) { |
Rob Pike | eb20ba6 | 2010-06-28 15:59:54 -0700 | [diff] [blame] | 75 | ch := make(chan int) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 76 | err := imp.ImportNValues("exportedSend", ch, Recv, 3, count) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 77 | if err != nil { |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 78 | t.Fatal("importReceive:", err) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 79 | } |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 80 | for i := 0; i < count; i++ { |
Russ Cox | 3f915f5 | 2011-03-11 14:47:44 -0500 | [diff] [blame] | 81 | v, ok := <-ch |
| 82 | if !ok { |
Rob Pike | 752b47c | 2010-05-28 22:32:29 -0700 | [diff] [blame] | 83 | if i != closeCount { |
Rob Pike | 1959c3a | 2010-09-23 13:48:56 +1000 | [diff] [blame] | 84 | t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i) |
Rob Pike | 752b47c | 2010-05-28 22:32:29 -0700 | [diff] [blame] | 85 | } |
| 86 | break |
| 87 | } |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 88 | if v != base+i { |
Rob Pike | 1ce6245 | 2010-12-07 16:42:54 -0500 | [diff] [blame] | 89 | t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v) |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 90 | } |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 91 | } |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 92 | if done != nil { |
| 93 | done <- true |
| 94 | } |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 95 | } |
| 96 | |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 97 | func TestExportSendImportReceive(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 98 | exp, imp := pair(t) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 99 | exportSend(exp, count, t, nil) |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 100 | importReceive(imp, t, nil) |
Rob Pike | 4d45dd3 | 2010-01-20 14:12:29 +1100 | [diff] [blame] | 101 | } |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 102 | |
| 103 | func TestExportReceiveImportSend(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 104 | exp, imp := pair(t) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 105 | expDone := make(chan bool) |
| 106 | done := make(chan bool) |
| 107 | go func() { |
| 108 | exportReceive(exp, t, expDone) |
| 109 | done <- true |
| 110 | }() |
| 111 | <-expDone |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 112 | importSend(imp, count, t, nil) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 113 | <-done |
Rob Pike | 1b56947 | 2010-04-13 13:49:42 -0700 | [diff] [blame] | 114 | } |
Rob Pike | 752b47c | 2010-05-28 22:32:29 -0700 | [diff] [blame] | 115 | |
| 116 | func TestClosingExportSendImportReceive(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 117 | exp, imp := pair(t) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 118 | exportSend(exp, closeCount, t, nil) |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 119 | importReceive(imp, t, nil) |
| 120 | } |
| 121 | |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 122 | func TestClosingImportSendExportReceive(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 123 | exp, imp := pair(t) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 124 | expDone := make(chan bool) |
| 125 | done := make(chan bool) |
| 126 | go func() { |
| 127 | exportReceive(exp, t, expDone) |
| 128 | done <- true |
| 129 | }() |
| 130 | <-expDone |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 131 | importSend(imp, closeCount, t, nil) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 132 | <-done |
Rob Pike | 1e4b1f9 | 2010-09-20 10:14:39 +1000 | [diff] [blame] | 133 | } |
| 134 | |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 135 | func TestErrorForIllegalChannel(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 136 | exp, imp := pair(t) |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 137 | // Now export a channel. |
| 138 | ch := make(chan int, 1) |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 139 | err := exp.Export("aChannel", ch, Send) |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 140 | 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 Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 147 | err = imp.Import("notAChannel", ch, Recv, 1) |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 148 | 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 Symonds | 3dbecd5 | 2011-12-13 10:42:56 +1100 | [diff] [blame] | 154 | time.Sleep(10 * time.Second) // very long, to give even really slow machines a chance. |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 155 | timeout <- true |
| 156 | }() |
| 157 | select { |
| 158 | case err = <-imp.Errors(): |
Russ Cox | eb69292 | 2011-11-01 22:05:34 -0400 | [diff] [blame] | 159 | if strings.Index(err.Error(), "no such channel") < 0 { |
Rob Pike | 724886b | 2010-09-20 17:24:40 +1000 | [diff] [blame] | 160 | t.Error("wrong error for nonexistent channel:", err) |
Rob Pike | da705c6 | 2010-09-20 15:28:38 +1000 | [diff] [blame] | 161 | } |
| 162 | case <-timeout: |
| 163 | t.Error("import of nonexistent channel did not receive an error") |
| 164 | } |
| 165 | } |
| 166 | |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 167 | // Not a great test but it does at least invoke Drain. |
| 168 | func TestExportDrain(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 169 | exp, imp := pair(t) |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 170 | done := make(chan bool) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 171 | go func() { |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 172 | exportSend(exp, closeCount, t, nil) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 173 | done <- true |
| 174 | }() |
| 175 | <-done |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 176 | go importReceive(imp, t, done) |
| 177 | exp.Drain(0) |
| 178 | <-done |
| 179 | } |
| 180 | |
David Jakob Fritz | ce877ac | 2011-06-06 06:55:32 +0000 | [diff] [blame] | 181 | // Not a great test but it does at least invoke Drain. |
| 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 | |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 191 | // Not a great test but it does at least invoke Sync. |
| 192 | func TestExportSync(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 193 | exp, imp := pair(t) |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 194 | done := make(chan bool) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 195 | exportSend(exp, closeCount, t, nil) |
Roger Peppe | d465ea5 | 2010-10-12 15:05:53 -0700 | [diff] [blame] | 196 | go importReceive(imp, t, done) |
Rob Pike | d54b921 | 2010-09-04 23:41:54 +1000 | [diff] [blame] | 197 | exp.Sync(0) |
| 198 | <-done |
Rob Pike | 752b47c | 2010-05-28 22:32:29 -0700 | [diff] [blame] | 199 | } |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 200 | |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 201 | // Test hanging up the send side of an export. |
| 202 | // TODO: test hanging up the receive side of an export. |
| 203 | func TestExportHangup(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 204 | exp, imp := pair(t) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 205 | ech := make(chan int) |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 206 | err := exp.Export("exportedSend", ech, Send) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 207 | 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 Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 212 | err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 213 | 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 Cox | 3f915f5 | 2011-03-11 14:47:44 -0500 | [diff] [blame] | 225 | v, ok := <-ich |
| 226 | if ok { |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 227 | 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. |
| 233 | func TestImportHangup(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 234 | exp, imp := pair(t) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 235 | ech := make(chan int) |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 236 | err := exp.Export("exportedRecv", ech, Recv) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 237 | 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 Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 242 | err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2) |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 243 | 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 Cox | 3f915f5 | 2011-03-11 14:47:44 -0500 | [diff] [blame] | 255 | v, ok := <-ech |
| 256 | if ok { |
Rob Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 257 | t.Fatal("expected channel to be closed; got value", v) |
| 258 | } |
| 259 | } |
| 260 | |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 261 | // loop back exportedRecv to exportedSend, |
| 262 | // but receive a value from ctlch before starting the loop. |
| 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 | // This test checks that channel operations can proceed |
| 292 | // even when other concurrent operations are blocked. |
| 293 | func TestIndependentSends(t *testing.T) { |
Russ Cox | 0e70f27 | 2012-02-18 16:24:23 -0500 | [diff] [blame] | 294 | if testing.Short() { |
| 295 | t.Logf("disabled test during -short") |
| 296 | return |
| 297 | } |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 298 | exp, imp := pair(t) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 299 | |
| 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 Symonds | 3dbecd5 | 2011-12-13 10:42:56 +1100 | [diff] [blame] | 307 | time.Sleep(250 * time.Millisecond) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 308 | |
| 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 Pike | 1ffb1f2 | 2010-10-18 15:09:43 -0700 | [diff] [blame] | 318 | // This test cross-connects a pair of exporter/importer pairs. |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 319 | type value struct { |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 320 | I int |
| 321 | Source string |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 322 | } |
| 323 | |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 324 | func TestCrossConnect(t *testing.T) { |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 325 | e1, i1 := pair(t) |
| 326 | e2, i2 := pair(t) |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 327 | |
Ian Lance Taylor | 9a9c156 | 2011-01-26 15:51:04 -0800 | [diff] [blame] | 328 | crossExport(e1, e2, t) |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 329 | crossImport(i1, i2, t) |
| 330 | } |
| 331 | |
| 332 | // Export side of cross-traffic. |
| 333 | func 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 Taylor | 9a9c156 | 2011-01-26 15:51:04 -0800 | [diff] [blame] | 346 | go crossLoop("export", s, r, t) |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | // Import side of cross-traffic. |
| 350 | func crossImport(i1, i2 *Importer, t *testing.T) { |
| 351 | s := make(chan value) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 352 | err := i2.Import("exportedReceive", s, Send, 2) |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 353 | if err != nil { |
| 354 | t.Fatal("import of exportedReceive:", err) |
| 355 | } |
| 356 | |
| 357 | r := make(chan value) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 358 | err = i1.Import("exportedSend", r, Recv, 2) |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 359 | 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. |
| 367 | func 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 Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 373 | if v.I != ri { |
Rob Pike | 19075ea | 2010-09-17 07:12:54 +1000 | [diff] [blame] | 374 | t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v) |
| 375 | } |
| 376 | ri++ |
| 377 | } |
| 378 | } |
| 379 | } |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 380 | |
| 381 | const flowCount = 100 |
| 382 | |
| 383 | // test flow control from exporter to importer. |
| 384 | func TestExportFlowControl(t *testing.T) { |
Russ Cox | 0e70f27 | 2012-02-18 16:24:23 -0500 | [diff] [blame] | 385 | if testing.Short() { |
| 386 | t.Logf("disabled test during -short") |
| 387 | return |
| 388 | } |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 389 | exp, imp := pair(t) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 390 | |
| 391 | sendDone := make(chan bool, 1) |
| 392 | exportSend(exp, flowCount, t, sendDone) |
| 393 | |
| 394 | ch := make(chan int) |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 395 | err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 396 | 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. |
| 404 | func TestImportFlowControl(t *testing.T) { |
Russ Cox | 0e70f27 | 2012-02-18 16:24:23 -0500 | [diff] [blame] | 405 | if testing.Short() { |
| 406 | t.Logf("disabled test during -short") |
| 407 | return |
| 408 | } |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 409 | exp, imp := pair(t) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 410 | |
| 411 | ch := make(chan int) |
Roger Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 412 | err := exp.Export("exportedRecv", ch, Recv) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 413 | 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 | |
| 422 | func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) { |
| 423 | go func() { |
David Symonds | 3dbecd5 | 2011-12-13 10:42:56 +1100 | [diff] [blame] | 424 | time.Sleep(500 * time.Millisecond) |
Roger Peppe | 6fb1bf2 | 2011-01-19 12:28:49 -0800 | [diff] [blame] | 425 | 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 Peppe | 1a96391 | 2011-02-16 08:14:41 -0800 | [diff] [blame] | 440 | |
| 441 | func 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 | } |