go/src/net/server_test.go
Mikio Hara 7b2b45e544 net: simplify test helpers
This change consolidates test helpers that test platform capabilities.
testNetwork, testAddress and testListenArgs report whether given
ariguments are testable on the current platform configuration to
mitigate to receive weird test results.

Change-Id: Ie1ed568a1f9cc50f3155945ea01562904bc2c389
Reviewed-on: https://go-review.googlesource.com/8076
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-03-28 08:21:10 +00:00

417 lines
12 KiB
Go

// Copyright 2009 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 net
import (
"flag"
"io"
"os"
"testing"
"time"
)
var streamConnServerTests = []struct {
snet string // server side
saddr string
cnet string // client side
caddr string
empty bool // test with empty data
}{
{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "::1"},
{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "::1"},
{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "::1"},
{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "::1"},
{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp", saddr: ":0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp", saddr: "[::]:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "127.0.0.1:0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", cnet: "tcp", caddr: "127.0.0.1"},
{snet: "tcp", saddr: "[::1]:0", cnet: "tcp", caddr: "::1"},
{snet: "tcp4", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp4", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp4", saddr: "127.0.0.1:0", cnet: "tcp4", caddr: "127.0.0.1"},
{snet: "tcp6", saddr: ":0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp6", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
{snet: "tcp6", saddr: "[::1]:0", cnet: "tcp6", caddr: "::1"},
{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local"},
}
func TestStreamConnServer(t *testing.T) {
for _, tt := range streamConnServerTests {
if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
continue
}
listening := make(chan string)
done := make(chan int)
switch tt.snet {
case "unix":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
taddr := <-listening // wait for server to start
switch tt.cnet {
case "tcp", "tcp4", "tcp6":
_, port, err := SplitHostPort(taddr)
if err != nil {
t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
}
taddr = JoinHostPort(tt.caddr, port)
}
runStreamConnClient(t, tt.cnet, taddr, tt.empty)
<-done // make sure server stopped
switch tt.snet {
case "unix":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
}
}
var seqpacketConnServerTests = []struct {
net string
saddr string // server address
caddr string // client address
empty bool // test with empty data
}{
{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
}
func TestSeqpacketConnServer(t *testing.T) {
for _, tt := range seqpacketConnServerTests {
if !testableListenArgs(tt.net, tt.saddr, tt.caddr) {
t.Logf("skipping %s test", tt.net+":"+tt.saddr+"->"+tt.caddr)
continue
}
listening := make(chan string)
done := make(chan int)
switch tt.net {
case "unixpacket":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
taddr := <-listening // wait for server to start
runStreamConnClient(t, tt.net, taddr, tt.empty)
<-done // make sure server stopped
switch tt.net {
case "unixpacket":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
}
}
func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
defer close(done)
l, err := Listen(net, laddr)
if err != nil {
t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
listening <- "<nil>"
return
}
defer l.Close()
listening <- l.Addr().String()
echo := func(rw io.ReadWriter, done chan<- int) {
buf := make([]byte, 1024)
for {
n, err := rw.Read(buf[0:])
if err != nil || n == 0 || string(buf[:n]) == "END" {
break
}
rw.Write(buf[0:n])
}
close(done)
}
run:
for {
c, err := l.Accept()
if err != nil {
t.Logf("Accept failed: %v", err)
continue run
}
echodone := make(chan int)
go echo(c, echodone)
<-echodone // make sure echo stopped
c.Close()
break run
}
}
func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
c, err := Dial(net, taddr)
if err != nil {
t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
}
defer c.Close()
c.SetReadDeadline(time.Now().Add(1 * time.Second))
var wb []byte
if !isEmpty {
wb = []byte("StreamConnClient by Dial\n")
}
if n, err := c.Write(wb); err != nil || n != len(wb) {
t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
}
rb := make([]byte, 1024)
if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
}
// Send explicit ending for unixpacket.
// Older Linux kernels do not stop reads on close.
switch net {
case "unixpacket":
c.Write([]byte("END"))
}
}
// Do not test empty datagrams by default.
// It causes unexplained timeouts on some systems,
// including Snow Leopard. I think that the kernel
// doesn't quite expect them.
var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
var datagramPacketConnServerTests = []struct {
snet string // server side
saddr string
cnet string // client side
caddr string
dial bool // test with Dial or DialUnix
empty bool // test with empty data
}{
{snet: "udp", saddr: ":0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "::1"},
{snet: "udp", saddr: ":0", cnet: "udp", caddr: "::1"},
{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "::1"},
{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "::1"},
{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
{snet: "udp", saddr: ":0", cnet: "udp6", caddr: "::1"},
{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp6", caddr: "::1"},
{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp6", caddr: "::1"},
{snet: "udp", saddr: "[::]:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", cnet: "udp", caddr: "127.0.0.1"},
{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1"},
{snet: "udp4", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp4", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp4", saddr: "127.0.0.1:0", cnet: "udp4", caddr: "127.0.0.1"},
{snet: "udp6", saddr: ":0", cnet: "udp6", caddr: "::1"},
{snet: "udp6", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
{snet: "udp6", saddr: "[::1]:0", cnet: "udp6", caddr: "::1"},
{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true},
{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", empty: true},
{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true},
{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", empty: true},
{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true, empty: true},
{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()},
{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true},
{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true},
{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true},
{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local"},
}
func TestDatagramPacketConnServer(t *testing.T) {
if !*testDatagram {
return
}
for _, tt := range datagramPacketConnServerTests {
if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
continue
}
listening := make(chan string)
done := make(chan int)
switch tt.snet {
case "unixgram":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
taddr := <-listening // wait for server to start
switch tt.cnet {
case "udp", "udp4", "udp6":
_, port, err := SplitHostPort(taddr)
if err != nil {
t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
}
taddr = JoinHostPort(tt.caddr, port)
tt.caddr = JoinHostPort(tt.caddr, "0")
}
if tt.dial {
runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
} else {
runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
}
<-done // tell server to stop
<-done // make sure server stopped
switch tt.snet {
case "unixgram":
os.Remove(tt.saddr)
os.Remove(tt.caddr)
}
}
}
func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
c, err := ListenPacket(net, laddr)
if err != nil {
t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
listening <- "<nil>"
done <- 1
return
}
defer c.Close()
listening <- c.LocalAddr().String()
buf := make([]byte, 1024)
run:
for {
c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
n, ra, err := c.ReadFrom(buf[0:])
if nerr, ok := err.(Error); ok && nerr.Timeout() {
select {
case done <- 1:
break run
default:
continue run
}
}
if err != nil {
break run
}
if _, err = c.WriteTo(buf[0:n], ra); err != nil {
t.Errorf("WriteTo(%v) failed: %v", ra, err)
break run
}
}
done <- 1
}
func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
var c Conn
var err error
switch net {
case "udp", "udp4", "udp6":
c, err = Dial(net, taddr)
if err != nil {
t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
}
case "unixgram":
c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
if err != nil {
t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
}
}
defer c.Close()
c.SetReadDeadline(time.Now().Add(1 * time.Second))
var wb []byte
if !isEmpty {
wb = []byte("DatagramConnClient by Dial\n")
}
if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
}
rb := make([]byte, 1024)
if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
}
}
func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
var ra Addr
var err error
switch net {
case "udp", "udp4", "udp6":
ra, err = ResolveUDPAddr(net, taddr)
if err != nil {
t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
}
case "unixgram":
ra, err = ResolveUnixAddr(net, taddr)
if err != nil {
t.Fatalf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
}
}
c, err := ListenPacket(net, laddr)
if err != nil {
t.Fatalf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
}
defer c.Close()
c.SetReadDeadline(time.Now().Add(1 * time.Second))
var wb []byte
if !isEmpty {
wb = []byte("DatagramPacketConnClient by ListenPacket\n")
}
if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
t.Fatalf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
}
rb := make([]byte, 1024)
if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
t.Fatalf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
}
}