diff options
Diffstat (limited to 'src/pkg/netchan/netchan_test.go')
-rw-r--r-- | src/pkg/netchan/netchan_test.go | 329 |
1 files changed, 303 insertions, 26 deletions
diff --git a/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go index 6b5c67c3c..766c4c474 100644 --- a/src/pkg/netchan/netchan_test.go +++ b/src/pkg/netchan/netchan_test.go @@ -4,38 +4,67 @@ package netchan -import "testing" +import ( + "strings" + "testing" + "time" +) const count = 10 // number of items in most tests const closeCount = 5 // number of items when sender closes early +const base = 23 + func exportSend(exp *Exporter, n int, t *testing.T) { ch := make(chan int) err := exp.Export("exportedSend", ch, Send) if err != nil { t.Fatal("exportSend:", err) } - for i := 0; i < n; i++ { - ch <- 23+i - } - close(ch) + go func() { + for i := 0; i < n; i++ { + ch <- base+i + } + close(ch) + }() } -func exportReceive(exp *Exporter, t *testing.T) { +func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) { ch := make(chan int) err := exp.Export("exportedRecv", ch, Recv) + expDone <- true if err != nil { t.Fatal("exportReceive:", err) } for i := 0; i < count; i++ { v := <-ch - if v != 45+i { - t.Errorf("export Receive: bad value: expected 4%d; got %d", 45+i, v) + if closed(ch) { + if i != closeCount { + t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i) + } + break + } + if v != base+i { + t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v) } } } -func importReceive(imp *Importer, t *testing.T) { +func importSend(imp *Importer, n int, t *testing.T) { + ch := make(chan int) + err := imp.ImportNValues("exportedRecv", ch, Send, count) + if err != nil { + t.Fatal("importSend:", err) + } + go func() { + for i := 0; i < n; i++ { + ch <- base+i + } + close(ch) + }() +} + +func importReceive(imp *Importer, t *testing.T, done chan bool) { ch := make(chan int) err := imp.ImportNValues("exportedSend", ch, Recv, count) if err != nil { @@ -45,28 +74,33 @@ func importReceive(imp *Importer, t *testing.T) { v := <-ch if closed(ch) { if i != closeCount { - t.Errorf("expected close at %d; got one at %d\n", closeCount, i) + t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i) } break } if v != 23+i { - t.Errorf("importReceive: bad value: expected %d; got %+d", 23+i, v) + t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v) } } + if done != nil { + done <- true + } } -func importSend(imp *Importer, t *testing.T) { - ch := make(chan int) - err := imp.ImportNValues("exportedRecv", ch, Send, count) +func TestExportSendImportReceive(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") if err != nil { - t.Fatal("importSend:", err) + t.Fatal("new exporter:", err) } - for i := 0; i < count; i++ { - ch <- 45+i + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) } + exportSend(exp, count, t) + importReceive(imp, t, nil) } -func TestExportSendImportReceive(t *testing.T) { +func TestExportReceiveImportSend(t *testing.T) { exp, err := NewExporter("tcp", "127.0.0.1:0") if err != nil { t.Fatal("new exporter:", err) @@ -75,11 +109,18 @@ func TestExportSendImportReceive(t *testing.T) { if err != nil { t.Fatal("new importer:", err) } - go exportSend(exp, count, t) - importReceive(imp, t) + expDone := make(chan bool) + done := make(chan bool) + go func() { + exportReceive(exp, t, expDone) + done <- true + }() + <-expDone + importSend(imp, count, t) + <-done } -func TestExportReceiveImportSend(t *testing.T) { +func TestClosingExportSendImportReceive(t *testing.T) { exp, err := NewExporter("tcp", "127.0.0.1:0") if err != nil { t.Fatal("new exporter:", err) @@ -88,11 +129,92 @@ func TestExportReceiveImportSend(t *testing.T) { if err != nil { t.Fatal("new importer:", err) } - go importSend(imp, t) - exportReceive(exp, t) + exportSend(exp, closeCount, t) + importReceive(imp, t, nil) } -func TestClosingExportSendImportReceive(t *testing.T) { +func TestClosingImportSendExportReceive(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + expDone := make(chan bool) + done := make(chan bool) + go func() { + exportReceive(exp, t, expDone) + done <- true + }() + <-expDone + importSend(imp, closeCount, t) + <-done +} + +func TestErrorForIllegalChannel(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + // Now export a channel. + ch := make(chan int, 1) + err = exp.Export("aChannel", ch, Send) + if err != nil { + t.Fatal("export:", err) + } + ch <- 1234 + close(ch) + // Now try to import a different channel. + ch = make(chan int) + err = imp.Import("notAChannel", ch, Recv) + if err != nil { + t.Fatal("import:", err) + } + // Expect an error now. Start a timeout. + timeout := make(chan bool, 1) // buffered so closure will not hang around. + go func() { + time.Sleep(10e9) // very long, to give even really slow machines a chance. + timeout <- true + }() + select { + case err = <-imp.Errors(): + if strings.Index(err.String(), "no such channel") < 0 { + t.Error("wrong error for nonexistent channel:", err) + } + case <-timeout: + t.Error("import of nonexistent channel did not receive an error") + } +} + +// Not a great test but it does at least invoke Drain. +func TestExportDrain(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + done := make(chan bool) + go func() { + exportSend(exp, closeCount, t) + done <- true + }() + <-done + go importReceive(imp, t, done) + exp.Drain(0) + <-done +} + +// Not a great test but it does at least invoke Sync. +func TestExportSync(t *testing.T) { exp, err := NewExporter("tcp", "127.0.0.1:0") if err != nil { t.Fatal("new exporter:", err) @@ -101,6 +223,161 @@ func TestClosingExportSendImportReceive(t *testing.T) { if err != nil { t.Fatal("new importer:", err) } - go exportSend(exp, closeCount, t) - importReceive(imp, t) + done := make(chan bool) + exportSend(exp, closeCount, t) + go importReceive(imp, t, done) + exp.Sync(0) + <-done +} + +// Test hanging up the send side of an export. +// TODO: test hanging up the receive side of an export. +func TestExportHangup(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + ech := make(chan int) + err = exp.Export("exportedSend", ech, Send) + if err != nil { + t.Fatal("export:", err) + } + // Prepare to receive two values. We'll actually deliver only one. + ich := make(chan int) + err = imp.ImportNValues("exportedSend", ich, Recv, 2) + if err != nil { + t.Fatal("import exportedSend:", err) + } + // Send one value, receive it. + const Value = 1234 + ech <- Value + v := <-ich + if v != Value { + t.Fatal("expected", Value, "got", v) + } + // Now hang up the channel. Importer should see it close. + exp.Hangup("exportedSend") + v = <-ich + if !closed(ich) { + t.Fatal("expected channel to be closed; got value", v) + } +} + +// Test hanging up the send side of an import. +// TODO: test hanging up the receive side of an import. +func TestImportHangup(t *testing.T) { + exp, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + imp, err := NewImporter("tcp", exp.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + ech := make(chan int) + err = exp.Export("exportedRecv", ech, Recv) + if err != nil { + t.Fatal("export:", err) + } + // Prepare to Send two values. We'll actually deliver only one. + ich := make(chan int) + err = imp.ImportNValues("exportedRecv", ich, Send, 2) + if err != nil { + t.Fatal("import exportedRecv:", err) + } + // Send one value, receive it. + const Value = 1234 + ich <- Value + v := <-ech + if v != Value { + t.Fatal("expected", Value, "got", v) + } + // Now hang up the channel. Exporter should see it close. + imp.Hangup("exportedRecv") + v = <-ech + if !closed(ech) { + t.Fatal("expected channel to be closed; got value", v) + } +} + +// This test cross-connects a pair of exporter/importer pairs. +type value struct { + i int + source string +} + +func TestCrossConnect(t *testing.T) { + e1, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + i1, err := NewImporter("tcp", e1.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + + e2, err := NewExporter("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal("new exporter:", err) + } + i2, err := NewImporter("tcp", e2.Addr().String()) + if err != nil { + t.Fatal("new importer:", err) + } + + go crossExport(e1, e2, t) + crossImport(i1, i2, t) +} + +// Export side of cross-traffic. +func crossExport(e1, e2 *Exporter, t *testing.T) { + s := make(chan value) + err := e1.Export("exportedSend", s, Send) + if err != nil { + t.Fatal("exportSend:", err) + } + + r := make(chan value) + err = e2.Export("exportedReceive", r, Recv) + if err != nil { + t.Fatal("exportReceive:", err) + } + + crossLoop("export", s, r, t) +} + +// Import side of cross-traffic. +func crossImport(i1, i2 *Importer, t *testing.T) { + s := make(chan value) + err := i2.Import("exportedReceive", s, Send) + if err != nil { + t.Fatal("import of exportedReceive:", err) + } + + r := make(chan value) + err = i1.Import("exportedSend", r, Recv) + if err != nil { + t.Fatal("import of exported Send:", err) + } + + crossLoop("import", s, r, t) +} + +// Cross-traffic: send and receive 'count' numbers. +func crossLoop(name string, s, r chan value, t *testing.T) { + for si, ri := 0, 0; si < count && ri < count; { + select { + case s <- value{si, name}: + si++ + case v := <-r: + if v.i != ri { + t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v) + } + ri++ + } + } } |