OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [old/] [netchan/] [netchan_test.go] - Rev 809

Go to most recent revision | Compare with Previous | Blame | View Log

// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package netchan

import (
        "net"
        "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, done chan bool) {
        ch := make(chan int)
        err := exp.Export("exportedSend", ch, Send)
        if err != nil {
                t.Fatal("exportSend:", err)
        }
        go func() {
                for i := 0; i < n; i++ {
                        ch <- base + i
                }
                close(ch)
                if done != nil {
                        done <- true
                }
        }()
}

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, ok := <-ch
                if !ok {
                        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 importSend(imp *Importer, n int, t *testing.T, done chan bool) {
        ch := make(chan int)
        err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
        if err != nil {
                t.Fatal("importSend:", err)
        }
        go func() {
                for i := 0; i < n; i++ {
                        ch <- base + i
                }
                close(ch)
                if done != nil {
                        done <- true
                }
        }()
}

func importReceive(imp *Importer, t *testing.T, done chan bool) {
        ch := make(chan int)
        err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
        if err != nil {
                t.Fatal("importReceive:", err)
        }
        for i := 0; i < count; i++ {
                v, ok := <-ch
                if !ok {
                        if i != closeCount {
                                t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
                        }
                        break
                }
                if v != base+i {
                        t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
                }
        }
        if done != nil {
                done <- true
        }
}

func TestExportSendImportReceive(t *testing.T) {
        exp, imp := pair(t)
        exportSend(exp, count, t, nil)
        importReceive(imp, t, nil)
}

func TestExportReceiveImportSend(t *testing.T) {
        exp, imp := pair(t)
        expDone := make(chan bool)
        done := make(chan bool)
        go func() {
                exportReceive(exp, t, expDone)
                done <- true
        }()
        <-expDone
        importSend(imp, count, t, nil)
        <-done
}

func TestClosingExportSendImportReceive(t *testing.T) {
        exp, imp := pair(t)
        exportSend(exp, closeCount, t, nil)
        importReceive(imp, t, nil)
}

func TestClosingImportSendExportReceive(t *testing.T) {
        exp, imp := pair(t)
        expDone := make(chan bool)
        done := make(chan bool)
        go func() {
                exportReceive(exp, t, expDone)
                done <- true
        }()
        <-expDone
        importSend(imp, closeCount, t, nil)
        <-done
}

func TestErrorForIllegalChannel(t *testing.T) {
        exp, imp := pair(t)
        // 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, 1)
        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(10 * time.Second) // very long, to give even really slow machines a chance.
                timeout <- true
        }()
        select {
        case err = <-imp.Errors():
                if strings.Index(err.Error(), "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, imp := pair(t)
        done := make(chan bool)
        go func() {
                exportSend(exp, closeCount, t, nil)
                done <- true
        }()
        <-done
        go importReceive(imp, t, done)
        exp.Drain(0)
        <-done
}

// Not a great test but it does at least invoke Drain.
func TestImportDrain(t *testing.T) {
        exp, imp := pair(t)
        expDone := make(chan bool)
        go exportReceive(exp, t, expDone)
        <-expDone
        importSend(imp, closeCount, t, nil)
        imp.Drain(0)
}

// Not a great test but it does at least invoke Sync.
func TestExportSync(t *testing.T) {
        exp, imp := pair(t)
        done := make(chan bool)
        exportSend(exp, closeCount, t, nil)
        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, imp := pair(t)
        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, 1, 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, ok := <-ich
        if ok {
                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, imp := pair(t)
        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, 1, 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, ok := <-ech
        if ok {
                t.Fatal("expected channel to be closed; got value", v)
        }
}

// loop back exportedRecv to exportedSend,
// but receive a value from ctlch before starting the loop.
func exportLoopback(exp *Exporter, t *testing.T) {
        inch := make(chan int)
        if err := exp.Export("exportedRecv", inch, Recv); err != nil {
                t.Fatal("exportRecv")
        }

        outch := make(chan int)
        if err := exp.Export("exportedSend", outch, Send); err != nil {
                t.Fatal("exportSend")
        }

        ctlch := make(chan int)
        if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
                t.Fatal("exportRecv")
        }

        go func() {
                <-ctlch
                for i := 0; i < count; i++ {
                        x := <-inch
                        if x != base+i {
                                t.Errorf("exportLoopback expected %d; got %d", i, x)
                        }
                        outch <- x
                }
        }()
}

// This test checks that channel operations can proceed
// even when other concurrent operations are blocked.
func TestIndependentSends(t *testing.T) {
        exp, imp := pair(t)

        exportLoopback(exp, t)

        importSend(imp, count, t, nil)
        done := make(chan bool)
        go importReceive(imp, t, done)

        // wait for export side to try to deliver some values.
        time.Sleep(250 * time.Millisecond)

        ctlch := make(chan int)
        if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
                t.Fatal("importSend:", err)
        }
        ctlch <- 0

        <-done
}

// This test cross-connects a pair of exporter/importer pairs.
type value struct {
        I      int
        Source string
}

func TestCrossConnect(t *testing.T) {
        e1, i1 := pair(t)
        e2, i2 := pair(t)

        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)
        }

        go 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, 2)
        if err != nil {
                t.Fatal("import of exportedReceive:", err)
        }

        r := make(chan value)
        err = i1.Import("exportedSend", r, Recv, 2)
        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++
                }
        }
}

const flowCount = 100

// test flow control from exporter to importer.
func TestExportFlowControl(t *testing.T) {
        exp, imp := pair(t)

        sendDone := make(chan bool, 1)
        exportSend(exp, flowCount, t, sendDone)

        ch := make(chan int)
        err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
        if err != nil {
                t.Fatal("importReceive:", err)
        }

        testFlow(sendDone, ch, flowCount, t)
}

// test flow control from importer to exporter.
func TestImportFlowControl(t *testing.T) {
        exp, imp := pair(t)

        ch := make(chan int)
        err := exp.Export("exportedRecv", ch, Recv)
        if err != nil {
                t.Fatal("importReceive:", err)
        }

        sendDone := make(chan bool, 1)
        importSend(imp, flowCount, t, sendDone)
        testFlow(sendDone, ch, flowCount, t)
}

func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
        go func() {
                time.Sleep(500 * time.Millisecond)
                sendDone <- false
        }()

        if <-sendDone {
                t.Fatal("send did not block")
        }
        n := 0
        for i := range ch {
                t.Log("after blocking, got value ", i)
                n++
        }
        if n != N {
                t.Fatalf("expected %d values; got %d", N, n)
        }
}

func pair(t *testing.T) (*Exporter, *Importer) {
        c0, c1 := net.Pipe()
        exp := NewExporter()
        go exp.ServeConn(c0)
        imp := NewImporter(c1)
        return exp, imp
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.