1
0
mirror of https://github.com/golang/go synced 2024-11-20 05:44:44 -07:00

net: add test for Conn, PacketConn and Listener

I just realized that there is no good place for adding
exposed function or method tests because server, unicast
and multicast_test.go do test complicated multiple test
objects, platform behaviros, protocol behaviors and API,
at the same time. Perhaps splitting them into per test
object might be better, so this CL provides tests focused
on API.

R=rsc
CC=gobot, golang-dev
https://golang.org/cl/6501057
This commit is contained in:
Mikio Hara 2012-10-21 17:17:51 -04:00 committed by Russ Cox
parent 922c0b4755
commit 4545dc6a69
3 changed files with 449 additions and 0 deletions

103
src/pkg/net/conn_test.go Normal file
View File

@ -0,0 +1,103 @@
// Copyright 2012 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_test
import (
"net"
"os"
"runtime"
"testing"
"time"
)
var connTests = []struct {
net string
addr string
}{
{"tcp", "127.0.0.1:0"},
{"unix", "/tmp/gotest.net"},
{"unixpacket", "/tmp/gotest.net"},
}
func TestConnAndListener(t *testing.T) {
for _, tt := range connTests {
switch tt.net {
case "unix", "unixpacket":
switch runtime.GOOS {
case "plan9", "windows":
continue
}
if tt.net == "unixpacket" && runtime.GOOS != "linux" {
continue
}
os.Remove(tt.addr)
}
ln, err := net.Listen(tt.net, tt.addr)
if err != nil {
t.Errorf("net.Listen failed: %v", err)
return
}
ln.Addr()
defer ln.Close()
done := make(chan int)
go transponder(t, ln, done)
c, err := net.Dial(tt.net, ln.Addr().String())
if err != nil {
t.Errorf("net.Dial failed: %v", err)
return
}
c.LocalAddr()
c.RemoteAddr()
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c.Close()
if _, err := c.Write([]byte("CONN TEST")); err != nil {
t.Errorf("net.Conn.Write failed: %v", err)
return
}
rb := make([]byte, 128)
if _, err := c.Read(rb); err != nil {
t.Errorf("net.Conn.Read failed: %v", err)
}
<-done
switch tt.net {
case "unix", "unixpacket":
os.Remove(tt.addr)
}
}
}
func transponder(t *testing.T, ln net.Listener, done chan<- int) {
defer func() { done <- 1 }()
c, err := ln.Accept()
if err != nil {
t.Errorf("net.Listener.Accept failed: %v", err)
return
}
c.LocalAddr()
c.RemoteAddr()
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c.Close()
b := make([]byte, 128)
n, err := c.Read(b)
if err != nil {
t.Errorf("net.Conn.Read failed: %v", err)
return
}
if _, err := c.Write(b[:n]); err != nil {
t.Errorf("net.Conn.Write failed: %v", err)
return
}
}

View File

@ -0,0 +1,161 @@
// Copyright 2012 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_test
import (
"net"
"os"
"runtime"
"strings"
"testing"
"time"
)
var packetConnTests = []struct {
net string
addr1 string
addr2 string
}{
{"udp", "127.0.0.1:0", "127.0.0.1:0"},
{"ip:icmp", "127.0.0.1", "127.0.0.1"},
{"unixgram", "/tmp/gotest.net1", "/tmp/gotest.net2"},
}
func TestPacketConn(t *testing.T) {
for _, tt := range packetConnTests {
var wb []byte
netstr := strings.Split(tt.net, ":")
switch netstr[0] {
case "udp":
wb = []byte("UDP PACKETCONN TEST")
case "ip":
switch runtime.GOOS {
case "plan9":
continue
}
if os.Getuid() != 0 {
continue
}
id := os.Getpid() & 0xffff
wb = newICMPEchoRequest(id, 1, 128, []byte("IP PACKETCONN TEST "))
case "unixgram":
switch runtime.GOOS {
case "plan9", "windows":
continue
}
os.Remove(tt.addr1)
os.Remove(tt.addr2)
wb = []byte("UNIXGRAM PACKETCONN TEST")
default:
continue
}
c1, err := net.ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("net.ListenPacket failed: %v", err)
}
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c1.Close()
c2, err := net.ListenPacket(tt.net, tt.addr2)
if err != nil {
t.Fatalf("net.ListenPacket failed: %v", err)
}
c2.LocalAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c2.Close()
if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil {
t.Fatalf("net.PacketConn.WriteTo failed: %v", err)
}
rb2 := make([]byte, 128)
if _, _, err := c2.ReadFrom(rb2); err != nil {
t.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
}
if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil {
t.Fatalf("net.PacketConn.WriteTo failed: %v", err)
}
rb1 := make([]byte, 128)
if _, _, err := c1.ReadFrom(rb1); err != nil {
t.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
}
switch netstr[0] {
case "unixgram":
os.Remove(tt.addr1)
os.Remove(tt.addr2)
}
}
}
func TestConnAndPacketConn(t *testing.T) {
for _, tt := range packetConnTests {
var wb []byte
netstr := strings.Split(tt.net, ":")
switch netstr[0] {
case "udp":
wb = []byte("UDP PACKETCONN TEST")
case "ip":
switch runtime.GOOS {
case "plan9":
continue
}
if os.Getuid() != 0 {
continue
}
id := os.Getpid() & 0xffff
wb = newICMPEchoRequest(id, 1, 128, []byte("IP PACKETCONN TEST"))
default:
continue
}
c1, err := net.ListenPacket(tt.net, tt.addr1)
if err != nil {
t.Fatalf("net.ListenPacket failed: %v", err)
}
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c1.Close()
c2, err := net.Dial(tt.net, c1.LocalAddr().String())
if err != nil {
t.Fatalf("net.Dial failed: %v", err)
}
c2.LocalAddr()
c2.RemoteAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
defer c2.Close()
if _, err := c2.Write(wb); err != nil {
t.Fatalf("net.Conn.Write failed: %v", err)
}
rb1 := make([]byte, 128)
if _, _, err := c1.ReadFrom(rb1); err != nil {
t.Fatalf("net.PacetConn.ReadFrom failed: %v", err)
}
var dst net.Addr
if netstr[0] == "ip" {
dst = &net.IPAddr{IP: net.IPv4(127, 0, 0, 1)}
} else {
dst = c2.LocalAddr()
}
if _, err := c1.WriteTo(wb, dst); err != nil {
t.Fatalf("net.PacketConn.WriteTo failed: %v", err)
}
rb2 := make([]byte, 128)
if _, err := c2.Read(rb2); err != nil {
t.Fatalf("net.Conn.Read failed: %v", err)
}
}
}

View File

@ -0,0 +1,185 @@
// Copyright 2012 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_test
import (
"bytes"
"net"
"os"
"runtime"
"testing"
"time"
)
func TestUDPConnSpecificMethods(t *testing.T) {
la, err := net.ResolveUDPAddr("udp4", "127.0.0.1:0")
if err != nil {
t.Fatalf("net.ResolveUDPAddr failed: %v", err)
}
c, err := net.ListenUDP("udp4", la)
if err != nil {
t.Fatalf("net.ListenUDP failed: %v", err)
}
c.File()
c.LocalAddr()
c.RemoteAddr()
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadBuffer(2048)
c.SetWriteBuffer(2048)
defer c.Close()
wb := []byte("UDPCONN TEST")
if _, err := c.WriteToUDP(wb, c.LocalAddr().(*net.UDPAddr)); err != nil {
t.Fatalf("net.UDPConn.WriteToUDP failed: %v", err)
}
rb := make([]byte, 128)
if _, _, err := c.ReadFromUDP(rb); err != nil {
t.Fatalf("net.UDPConn.ReadFromUDP failed: %v", err)
}
}
func TestIPConnSpecificMethods(t *testing.T) {
switch runtime.GOOS {
case "plan9":
t.Logf("skipping read test on %q", runtime.GOOS)
return
}
if os.Getuid() != 0 {
t.Logf("skipping test; must be root")
return
}
la, err := net.ResolveIPAddr("ip4", "127.0.0.1")
if err != nil {
t.Fatalf("net.ResolveIPAddr failed: %v", err)
}
c, err := net.ListenIP("ip4:icmp", la)
if err != nil {
t.Fatalf("net.ListenIP failed: %v", err)
}
c.File()
c.LocalAddr()
c.RemoteAddr()
c.SetDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
c.SetReadBuffer(2048)
c.SetWriteBuffer(2048)
defer c.Close()
id := os.Getpid() & 0xffff
wb := newICMPEchoRequest(id, 1, 128, []byte("IPCONN TEST "))
if _, err := c.WriteToIP(wb, c.LocalAddr().(*net.IPAddr)); err != nil {
t.Fatalf("net.IPConn.WriteToIP failed: %v", err)
}
rb := make([]byte, 20+128)
if _, _, err := c.ReadFromIP(rb); err != nil {
t.Fatalf("net.IPConn.ReadFromIP failed: %v", err)
}
}
// TODO: Find out the use case of ListenUnixgram, I have no idea.
func TestUnixConnSpecificMethods(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
t.Logf("skipping test on %q", runtime.GOOS)
return
}
p1, p2 := "/tmp/gotest.net1", "/tmp/gotest.net2"
os.Remove(p1)
os.Remove(p2)
a1, err := net.ResolveUnixAddr("unixgram", p1)
if err != nil {
t.Fatalf("net.ResolveUnixAddr failed: %v", err)
}
c1, err := net.DialUnix("unixgram", a1, nil)
if err != nil {
t.Fatalf("net.DialUnix failed: %v", err)
}
c1.File()
c1.LocalAddr()
c1.RemoteAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadBuffer(2048)
c1.SetWriteBuffer(2048)
defer c1.Close()
defer os.Remove(p1)
a2, err := net.ResolveUnixAddr("unixgram", p2)
if err != nil {
t.Fatalf("net.ResolveUnixAddr failed: %v", err)
}
c2, err := net.DialUnix("unixgram", a2, nil)
if err != nil {
t.Fatalf("net.DialUnix failed: %v", err)
}
c2.File()
c2.LocalAddr()
c2.RemoteAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadBuffer(2048)
c2.SetWriteBuffer(2048)
defer c2.Close()
defer os.Remove(p2)
wb := []byte("UNIXCONN TEST")
if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil {
t.Fatalf("net.UnixConn.WriteMsgUnix failed: %v", err)
}
rb2 := make([]byte, 128)
if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil {
t.Fatalf("net.UnixConn.ReadMsgUnix failed: %v", err)
}
if _, err := c2.WriteToUnix(wb, a1); err != nil {
t.Fatalf("net.UnixConn.WriteToUnix failed: %v", err)
}
rb1 := make([]byte, 128)
if _, _, err := c1.ReadFromUnix(rb1); err != nil {
t.Fatalf("net.UnixConn.ReadFromUnix failed: %v", err)
}
}
func newICMPEchoRequest(id, seqnum, msglen int, filler []byte) []byte {
b := newICMPInfoMessage(id, seqnum, msglen, filler)
b[0] = 8
// calculate ICMP checksum
cklen := len(b)
s := uint32(0)
for i := 0; i < cklen-1; i += 2 {
s += uint32(b[i+1])<<8 | uint32(b[i])
}
if cklen&1 == 1 {
s += uint32(b[cklen-1])
}
s = (s >> 16) + (s & 0xffff)
s = s + (s >> 16)
// place checksum back in header; using ^= avoids the
// assumption the checksum bytes are zero
b[2] ^= byte(^s & 0xff)
b[3] ^= byte(^s >> 8)
return b
}
func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
b := make([]byte, msglen)
copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
b[0] = 0 // type
b[1] = 0 // code
b[2] = 0 // checksum
b[3] = 0 // checksum
b[4] = byte(id >> 8) // identifier
b[5] = byte(id & 0xff) // identifier
b[6] = byte(seqnum >> 8) // sequence number
b[7] = byte(seqnum & 0xff) // sequence number
return b
}