]> Cypherpunks repositories - gostls13.git/commitdiff
net: add test for Conn, PacketConn and Listener
authorMikio Hara <mikioh.mikioh@gmail.com>
Sun, 21 Oct 2012 21:17:51 +0000 (17:17 -0400)
committerRuss Cox <rsc@golang.org>
Sun, 21 Oct 2012 21:17:51 +0000 (17:17 -0400)
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

src/pkg/net/conn_test.go [new file with mode: 0644]
src/pkg/net/packetconn_test.go [new file with mode: 0644]
src/pkg/net/protoconn_test.go [new file with mode: 0644]

diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
new file mode 100644 (file)
index 0000000..037ce80
--- /dev/null
@@ -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
+       }
+}
diff --git a/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go
new file mode 100644 (file)
index 0000000..5075baa
--- /dev/null
@@ -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)
+               }
+       }
+}
diff --git a/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go
new file mode 100644 (file)
index 0000000..5cdceb7
--- /dev/null
@@ -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
+}