mirror of
https://github.com/golang/go
synced 2024-11-05 19:56:11 -07:00
net: add helpers for server testing
Also moves a few server test helpers into mockserver_test.go. Change-Id: I5a95c9bc6f0c4683751bcca77e26a8586a377466 Reviewed-on: https://go-review.googlesource.com/9106 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
f9bc9a7a2e
commit
832c573595
@ -18,8 +18,7 @@ import (
|
|||||||
const someTimeout = 10 * time.Second
|
const someTimeout = 10 * time.Second
|
||||||
|
|
||||||
func TestConnAndListener(t *testing.T) {
|
func TestConnAndListener(t *testing.T) {
|
||||||
handler := func(ls *localServer, ln Listener) { transponder(t, ln) }
|
for i, network := range []string{"tcp", "unix", "unixpacket"} {
|
||||||
for _, network := range []string{"tcp", "unix", "unixpacket"} {
|
|
||||||
if !testableNetwork(network) {
|
if !testableNetwork(network) {
|
||||||
t.Logf("skipping %s test", network)
|
t.Logf("skipping %s test", network)
|
||||||
continue
|
continue
|
||||||
@ -30,6 +29,8 @@ func TestConnAndListener(t *testing.T) {
|
|||||||
t.Fatalf("Listen failed: %v", err)
|
t.Fatalf("Listen failed: %v", err)
|
||||||
}
|
}
|
||||||
defer ls.teardown()
|
defer ls.teardown()
|
||||||
|
ch := make(chan error, 1)
|
||||||
|
handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
|
||||||
if err := ls.buildup(handler); err != nil {
|
if err := ls.buildup(handler); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -56,40 +57,9 @@ func TestConnAndListener(t *testing.T) {
|
|||||||
if _, err := c.Read(rb); err != nil {
|
if _, err := c.Read(rb); err != nil {
|
||||||
t.Fatalf("Conn.Read failed: %v", err)
|
t.Fatalf("Conn.Read failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
for err := range ch {
|
||||||
|
t.Errorf("#%d: %v", i, err)
|
||||||
func transponder(t *testing.T, ln Listener) {
|
}
|
||||||
switch ln := ln.(type) {
|
|
||||||
case *TCPListener:
|
|
||||||
ln.SetDeadline(time.Now().Add(someTimeout))
|
|
||||||
case *UnixListener:
|
|
||||||
ln.SetDeadline(time.Now().Add(someTimeout))
|
|
||||||
}
|
|
||||||
c, err := ln.Accept()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Listener.Accept failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
network := ln.Addr().Network()
|
|
||||||
if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
|
|
||||||
t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.SetDeadline(time.Now().Add(someTimeout))
|
|
||||||
c.SetReadDeadline(time.Now().Add(someTimeout))
|
|
||||||
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
|
||||||
|
|
||||||
b := make([]byte, 128)
|
|
||||||
n, err := c.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Conn.Read failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := c.Write(b[:n]); err != nil {
|
|
||||||
t.Errorf("Conn.Write failed: %v", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,6 +317,11 @@ second:
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch err := nestedErr.(type) {
|
switch err := nestedErr.(type) {
|
||||||
|
case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
|
||||||
|
return nil
|
||||||
|
case *DNSConfigError:
|
||||||
|
nestedErr = err.Err
|
||||||
|
goto third
|
||||||
case *os.SyscallError:
|
case *os.SyscallError:
|
||||||
nestedErr = err.Err
|
nestedErr = err.Err
|
||||||
goto third
|
goto third
|
||||||
|
@ -6,10 +6,26 @@ package net
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// testUnixAddr uses ioutil.TempFile to get a name that is unique.
|
||||||
|
// It also uses /tmp directory in case it is prohibited to create UNIX
|
||||||
|
// sockets in TMPDIR.
|
||||||
|
func testUnixAddr() string {
|
||||||
|
f, err := ioutil.TempFile("", "nettest")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
addr := f.Name()
|
||||||
|
f.Close()
|
||||||
|
os.Remove(addr)
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
func newLocalListener(network string) (Listener, error) {
|
func newLocalListener(network string) (Listener, error) {
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp", "tcp4", "tcp6":
|
case "tcp", "tcp4", "tcp6":
|
||||||
@ -155,3 +171,212 @@ func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
|
|||||||
}
|
}
|
||||||
return dss, nil
|
return dss, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func transponder(ln Listener, ch chan<- error) {
|
||||||
|
defer close(ch)
|
||||||
|
|
||||||
|
switch ln := ln.(type) {
|
||||||
|
case *TCPListener:
|
||||||
|
ln.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
case *UnixListener:
|
||||||
|
ln.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
}
|
||||||
|
c, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseAcceptError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
network := ln.Addr().Network()
|
||||||
|
if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
|
||||||
|
ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
||||||
|
|
||||||
|
b := make([]byte, 256)
|
||||||
|
n, err := c.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseReadError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := c.Write(b[:n]); err != nil {
|
||||||
|
if perr := parseWriteError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func transceiver(c Conn, wb []byte, ch chan<- error) {
|
||||||
|
defer close(ch)
|
||||||
|
|
||||||
|
c.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
||||||
|
|
||||||
|
n, err := c.Write(wb)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseWriteError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != len(wb) {
|
||||||
|
ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
|
||||||
|
}
|
||||||
|
rb := make([]byte, len(wb))
|
||||||
|
n, err = c.Read(rb)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseReadError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != len(wb) {
|
||||||
|
ch <- fmt.Errorf("read %d; want %d", n, len(wb))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLocalPacketListener(network string) (PacketConn, error) {
|
||||||
|
switch network {
|
||||||
|
case "udp", "udp4", "udp6":
|
||||||
|
if supportsIPv4 {
|
||||||
|
return ListenPacket("udp4", "127.0.0.1:0")
|
||||||
|
}
|
||||||
|
if supportsIPv6 {
|
||||||
|
return ListenPacket("udp6", "[::1]:0")
|
||||||
|
}
|
||||||
|
case "unixgram":
|
||||||
|
return ListenPacket(network, testUnixAddr())
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%s is not supported", network)
|
||||||
|
}
|
||||||
|
|
||||||
|
type localPacketServer struct {
|
||||||
|
pcmu sync.RWMutex
|
||||||
|
PacketConn
|
||||||
|
done chan bool // signal that indicates server stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
|
||||||
|
go func() {
|
||||||
|
handler(ls, ls.PacketConn)
|
||||||
|
close(ls.done)
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *localPacketServer) teardown() error {
|
||||||
|
ls.pcmu.Lock()
|
||||||
|
if ls.PacketConn != nil {
|
||||||
|
network := ls.PacketConn.LocalAddr().Network()
|
||||||
|
address := ls.PacketConn.LocalAddr().String()
|
||||||
|
ls.PacketConn.Close()
|
||||||
|
<-ls.done
|
||||||
|
ls.PacketConn = nil
|
||||||
|
switch network {
|
||||||
|
case "unixgram":
|
||||||
|
os.Remove(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ls.pcmu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newLocalPacketServer(network string) (*localPacketServer, error) {
|
||||||
|
c, err := newLocalPacketListener(network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type packetListener struct {
|
||||||
|
PacketConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pl *packetListener) newLocalServer() (*localPacketServer, error) {
|
||||||
|
return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func packetTransponder(c PacketConn, ch chan<- error) {
|
||||||
|
defer close(ch)
|
||||||
|
|
||||||
|
c.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
||||||
|
|
||||||
|
b := make([]byte, 256)
|
||||||
|
n, peer, err := c.ReadFrom(b)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseReadError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if peer == nil { // for connected-mode sockets
|
||||||
|
switch c.LocalAddr().Network() {
|
||||||
|
case "udp":
|
||||||
|
peer, err = ResolveUDPAddr("udp", string(b[:n]))
|
||||||
|
case "unixgram":
|
||||||
|
peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := c.WriteTo(b[:n], peer); err != nil {
|
||||||
|
if perr := parseWriteError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
|
||||||
|
defer close(ch)
|
||||||
|
|
||||||
|
c.SetDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetReadDeadline(time.Now().Add(someTimeout))
|
||||||
|
c.SetWriteDeadline(time.Now().Add(someTimeout))
|
||||||
|
|
||||||
|
n, err := c.WriteTo(wb, dst)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseWriteError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != len(wb) {
|
||||||
|
ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
|
||||||
|
}
|
||||||
|
rb := make([]byte, len(wb))
|
||||||
|
n, _, err = c.ReadFrom(rb)
|
||||||
|
if err != nil {
|
||||||
|
if perr := parseReadError(err); perr != nil {
|
||||||
|
ch <- perr
|
||||||
|
}
|
||||||
|
ch <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if n != len(wb) {
|
||||||
|
ch <- fmt.Errorf("read %d; want %d", n, len(wb))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
@ -21,20 +20,6 @@ import (
|
|||||||
// golang.org/x/net/ipv6
|
// golang.org/x/net/ipv6
|
||||||
// golang.org/x/net/icmp
|
// golang.org/x/net/icmp
|
||||||
|
|
||||||
// testUnixAddr uses ioutil.TempFile to get a name that is unique. It
|
|
||||||
// also uses /tmp directory in case it is prohibited to create UNIX
|
|
||||||
// sockets in TMPDIR.
|
|
||||||
func testUnixAddr() string {
|
|
||||||
f, err := ioutil.TempFile("", "nettest")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
addr := f.Name()
|
|
||||||
f.Close()
|
|
||||||
os.Remove(addr)
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTCPListenerSpecificMethods(t *testing.T) {
|
func TestTCPListenerSpecificMethods(t *testing.T) {
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "plan9":
|
case "plan9":
|
||||||
@ -84,7 +69,8 @@ func TestTCPConnSpecificMethods(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ListenTCP failed: %v", err)
|
t.Fatalf("ListenTCP failed: %v", err)
|
||||||
}
|
}
|
||||||
handler := func(ls *localServer, ln Listener) { transponder(t, ls.Listener) }
|
ch := make(chan error, 1)
|
||||||
|
handler := func(ls *localServer, ln Listener) { transponder(ls.Listener, ch) }
|
||||||
ls, err := (&streamListener{Listener: ln}).newLocalServer()
|
ls, err := (&streamListener{Listener: ln}).newLocalServer()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -120,6 +106,10 @@ func TestTCPConnSpecificMethods(t *testing.T) {
|
|||||||
if _, err := c.Read(rb); err != nil {
|
if _, err := c.Read(rb); err != nil {
|
||||||
t.Fatalf("TCPConn.Read failed: %v", err)
|
t.Fatalf("TCPConn.Read failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for err := range ch {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUDPConnSpecificMethods(t *testing.T) {
|
func TestUDPConnSpecificMethods(t *testing.T) {
|
||||||
|
@ -398,8 +398,7 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
|
|||||||
{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
|
{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
handler := func(ls *localServer, ln Listener) { transponder(t, ln) }
|
for i, tt := range tests {
|
||||||
for _, tt := range tests {
|
|
||||||
ln, err := Listen(tt.net, tt.addr)
|
ln, err := Listen(tt.net, tt.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// It might return "LookupHost returned no
|
// It might return "LookupHost returned no
|
||||||
@ -412,6 +411,8 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer ls.teardown()
|
defer ls.teardown()
|
||||||
|
ch := make(chan error, 1)
|
||||||
|
handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
|
||||||
if err := ls.buildup(handler); err != nil {
|
if err := ls.buildup(handler); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -438,6 +439,10 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
|
|||||||
if _, err := c.Read(b); err != nil {
|
if _, err := c.Read(b); err != nil {
|
||||||
t.Fatalf("Conn.Read failed: %v", err)
|
t.Fatalf("Conn.Read failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for err := range ch {
|
||||||
|
t.Errorf("#%d: %v", i, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user