go.net/ipv6: add missing API tests

Now the package has a code coverage of 76.1% of statements.
Also fixes flaky concurrent test.

Fixes golang/go#5696.

R=golang-codereviews, dave
CC=golang-codereviews
https://golang.org/cl/45620043
diff --git a/ipv6/control_test.go b/ipv6/control_test.go
deleted file mode 100644
index 0f99321..0000000
--- a/ipv6/control_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 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 ipv6
-
-import (
-	"sync"
-	"testing"
-)
-
-func TestControlFlags(t *testing.T) {
-	tf := FlagInterface | FlagPathMTU
-	opt := rawOpt{cflags: tf | FlagHopLimit}
-
-	// This loop runs methods of raw.Opt concurrently for testing
-	// concurrent access to the rawOpt. The first entry shold be
-	// opt.set and the last entry should be opt.clear.
-	tfns := []func(ControlFlags){opt.set, opt.clear, opt.clear}
-	ch := make(chan bool)
-	var wg sync.WaitGroup
-	for i, fn := range tfns {
-		wg.Add(1)
-		go func(i int, fn func(ControlFlags)) {
-			defer wg.Done()
-			switch i {
-			case 0:
-				close(ch)
-			case len(tfns) - 1:
-				<-ch
-			}
-			opt.Lock()
-			defer opt.Unlock()
-			fn(tf)
-		}(i, fn)
-	}
-	wg.Wait()
-
-	if opt.isset(tf) {
-		t.Fatalf("got %#x; expected %#x", opt.cflags, FlagHopLimit)
-	}
-}
diff --git a/ipv6/icmp_test.go b/ipv6/icmp_test.go
index a7833dd..4005036 100644
--- a/ipv6/icmp_test.go
+++ b/ipv6/icmp_test.go
@@ -14,6 +14,24 @@
 	"testing"
 )
 
+var icmpStringTests = []struct {
+	in  ipv6.ICMPType
+	out string
+}{
+	{ipv6.ICMPTypeDestinationUnreachable, "destination unreachable"},
+
+	{256, "<nil>"},
+}
+
+func TestICMPString(t *testing.T) {
+	for _, tt := range icmpStringTests {
+		s := tt.in.String()
+		if s != tt.out {
+			t.Errorf("got %s; expected %s", s, tt.out)
+		}
+	}
+}
+
 func TestICMPFilter(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9", "windows":
diff --git a/ipv6/multicast_test.go b/ipv6/multicast_test.go
index 79568f4..6801681 100644
--- a/ipv6/multicast_test.go
+++ b/ipv6/multicast_test.go
@@ -5,6 +5,7 @@
 package ipv6_test
 
 import (
+	"bytes"
 	"code.google.com/p/go.net/ipv6"
 	"net"
 	"os"
@@ -64,9 +65,11 @@
 
 	cm := ipv6.ControlMessage{
 		TrafficClass: DiffServAF11 | CongestionExperienced,
+		Src:          net.IPv6loopback,
 		IfIndex:      ifi.Index,
 	}
-	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
+	wb := []byte("HELLO-R-U-THERE")
 
 	for i, toggle := range []bool{true, false, true} {
 		if err := p.SetControlMessage(cf, toggle); err != nil {
@@ -76,12 +79,16 @@
 			t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
 		}
 		cm.HopLimit = i + 1
-		if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil {
+		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
 			t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
+		} else if n != len(wb) {
+			t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
 		}
-		b := make([]byte, 128)
-		if _, cm, _, err := p.ReadFrom(b); err != nil {
+		rb := make([]byte, 128)
+		if n, cm, _, err := p.ReadFrom(rb); err != nil {
 			t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
+		} else if !bytes.Equal(rb[:n], wb) {
+			t.Fatalf("got %v; expected %v", rb[:n], wb)
 		} else {
 			t.Logf("rcvd cmsg: %v", cm)
 		}
@@ -136,9 +143,10 @@
 
 	cm := ipv6.ControlMessage{
 		TrafficClass: DiffServAF11 | CongestionExperienced,
+		Src:          net.IPv6loopback,
 		IfIndex:      ifi.Index,
 	}
-	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
 
 	var f ipv6.ICMPFilter
 	f.SetAll(true)
@@ -177,15 +185,17 @@
 			t.Fatalf("ipv6.PacketConn.SetDeadline failed: %v", err)
 		}
 		cm.HopLimit = i + 1
-		if _, err := p.WriteTo(wb, &cm, dst); err != nil {
+		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
 			t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
+		} else if n != len(wb) {
+			t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
 		}
-		b := make([]byte, 128)
-		if n, cm, _, err := p.ReadFrom(b); err != nil {
+		rb := make([]byte, 128)
+		if n, cm, _, err := p.ReadFrom(rb); err != nil {
 			t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
 		} else {
 			t.Logf("rcvd cmsg: %v", cm)
-			if m, err := parseICMPMessage(b[:n]); err != nil {
+			if m, err := parseICMPMessage(rb[:n]); err != nil {
 				t.Fatalf("parseICMPMessage failed: %v", err)
 			} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
 				t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)
diff --git a/ipv6/readwrite_test.go b/ipv6/readwrite_test.go
new file mode 100644
index 0000000..f0d09b3
--- /dev/null
+++ b/ipv6/readwrite_test.go
@@ -0,0 +1,168 @@
+// Copyright 2013 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 ipv6_test
+
+import (
+	"bytes"
+	"code.google.com/p/go.net/ipv6"
+	"net"
+	"runtime"
+	"sync"
+	"testing"
+)
+
+func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
+	c, err := net.ListenPacket("udp6", "[::1]:0")
+	if err != nil {
+		return nil, nil, err
+	}
+	dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
+	if err != nil {
+		c.Close()
+		return nil, nil, err
+	}
+	return c, dst, nil
+}
+
+func BenchmarkReadWriteNetUDP(b *testing.B) {
+	c, dst, err := benchmarkUDPListener()
+	if err != nil {
+		b.Fatalf("benchmarkUDPListener failed: %v", err)
+	}
+	defer c.Close()
+
+	wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
+	}
+}
+
+func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
+	if _, err := c.WriteTo(wb, dst); err != nil {
+		b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
+	}
+	if _, _, err := c.ReadFrom(rb); err != nil {
+		b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
+	}
+}
+
+func BenchmarkReadWriteIPv6UDP(b *testing.B) {
+	c, dst, err := benchmarkUDPListener()
+	if err != nil {
+		b.Fatalf("benchmarkUDPListener failed: %v", err)
+	}
+	defer c.Close()
+
+	p := ipv6.NewPacketConn(c)
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
+	if err := p.SetControlMessage(cf, true); err != nil {
+		b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
+	}
+	ifi := loopbackInterface()
+
+	wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi)
+	}
+}
+
+func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
+	cm := ipv6.ControlMessage{
+		TrafficClass: DiffServAF11 | CongestionExperienced,
+		HopLimit:     1,
+	}
+	if ifi != nil {
+		cm.IfIndex = ifi.Index
+	}
+	if n, err := p.WriteTo(wb, &cm, dst); err != nil {
+		b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
+	} else if n != len(wb) {
+		b.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
+	}
+	if _, _, _, err := p.ReadFrom(rb); err != nil {
+		b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
+	}
+}
+
+func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		t.Skipf("not supported on %q", runtime.GOOS)
+	}
+	if !supportsIPv6 {
+		t.Skip("ipv6 is not supported")
+	}
+
+	c, err := net.ListenPacket("udp6", "[::1]:0")
+	if err != nil {
+		t.Fatalf("net.ListenPacket failed: %v", err)
+	}
+	defer c.Close()
+	p := ipv6.NewPacketConn(c)
+	defer p.Close()
+
+	dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
+	if err != nil {
+		t.Fatalf("net.ResolveUDPAddr failed: %v", err)
+	}
+
+	ifi := loopbackInterface()
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
+	wb := []byte("HELLO-R-U-THERE")
+
+	var wg sync.WaitGroup
+	reader := func() {
+		defer wg.Done()
+		rb := make([]byte, 128)
+		if n, cm, _, err := p.ReadFrom(rb); err != nil {
+			t.Errorf("ipv6.PacketConn.ReadFrom failed: %v", err)
+			return
+		} else if !bytes.Equal(rb[:n], wb) {
+			t.Errorf("got %v; expected %v", rb[:n], wb)
+			return
+		} else {
+			t.Logf("rcvd cmsg: %v", cm)
+		}
+	}
+	writer := func(toggle bool) {
+		defer wg.Done()
+		cm := ipv6.ControlMessage{
+			TrafficClass: DiffServAF11 | CongestionExperienced,
+			Src:          net.IPv6loopback,
+			Dst:          net.IPv6loopback,
+		}
+		if ifi != nil {
+			cm.IfIndex = ifi.Index
+		}
+		if err := p.SetControlMessage(cf, toggle); err != nil {
+			t.Errorf("ipv6.PacketConn.SetControlMessage failed: %v", err)
+			return
+		}
+		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
+			t.Errorf("ipv6.PacketConn.WriteTo failed: %v", err)
+			return
+		} else if n != len(wb) {
+			t.Errorf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
+			return
+		}
+	}
+
+	const N = 10
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go reader()
+	}
+	wg.Add(2 * N)
+	for i := 0; i < 2*N; i++ {
+		go writer(i%2 != 0)
+	}
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go reader()
+	}
+	wg.Wait()
+}
diff --git a/ipv6/unicast_test.go b/ipv6/unicast_test.go
index fed8a69..ad42b5e 100644
--- a/ipv6/unicast_test.go
+++ b/ipv6/unicast_test.go
@@ -5,6 +5,7 @@
 package ipv6_test
 
 import (
+	"bytes"
 	"code.google.com/p/go.net/ipv6"
 	"net"
 	"os"
@@ -13,79 +14,6 @@
 	"time"
 )
 
-func benchmarkUDPListener() (net.PacketConn, net.Addr, error) {
-	c, err := net.ListenPacket("udp6", "[::1]:0")
-	if err != nil {
-		return nil, nil, err
-	}
-	dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
-	if err != nil {
-		c.Close()
-		return nil, nil, err
-	}
-	return c, dst, nil
-}
-
-func BenchmarkReadWriteNetUDP(b *testing.B) {
-	c, dst, err := benchmarkUDPListener()
-	if err != nil {
-		b.Fatalf("benchmarkUDPListener failed: %v", err)
-	}
-	defer c.Close()
-
-	wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		benchmarkReadWriteNetUDP(b, c, wb, rb, dst)
-	}
-}
-
-func benchmarkReadWriteNetUDP(b *testing.B, c net.PacketConn, wb, rb []byte, dst net.Addr) {
-	if _, err := c.WriteTo(wb, dst); err != nil {
-		b.Fatalf("net.PacketConn.WriteTo failed: %v", err)
-	}
-	if _, _, err := c.ReadFrom(rb); err != nil {
-		b.Fatalf("net.PacketConn.ReadFrom failed: %v", err)
-	}
-}
-
-func BenchmarkReadWriteIPv6UDP(b *testing.B) {
-	c, dst, err := benchmarkUDPListener()
-	if err != nil {
-		b.Fatalf("benchmarkUDPListener failed: %v", err)
-	}
-	defer c.Close()
-
-	p := ipv6.NewPacketConn(c)
-	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
-	if err := p.SetControlMessage(cf, true); err != nil {
-		b.Fatalf("ipv6.PacketConn.SetControlMessage failed: %v", err)
-	}
-	ifi := loopbackInterface()
-
-	wb, rb := []byte("HELLO-R-U-THERE"), make([]byte, 128)
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		benchmarkReadWriteIPv6UDP(b, p, wb, rb, dst, ifi)
-	}
-}
-
-func benchmarkReadWriteIPv6UDP(b *testing.B, p *ipv6.PacketConn, wb, rb []byte, dst net.Addr, ifi *net.Interface) {
-	cm := ipv6.ControlMessage{
-		TrafficClass: DiffServAF11 | CongestionExperienced,
-		HopLimit:     1,
-	}
-	if ifi != nil {
-		cm.IfIndex = ifi.Index
-	}
-	if _, err := p.WriteTo(wb, &cm, dst); err != nil {
-		b.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
-	}
-	if _, _, _, err := p.ReadFrom(rb); err != nil {
-		b.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
-	}
-}
-
 func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9", "windows":
@@ -100,22 +28,25 @@
 		t.Fatalf("net.ListenPacket failed: %v", err)
 	}
 	defer c.Close()
+	p := ipv6.NewPacketConn(c)
+	defer p.Close()
 
 	dst, err := net.ResolveUDPAddr("udp6", c.LocalAddr().String())
 	if err != nil {
 		t.Fatalf("net.ResolveUDPAddr failed: %v", err)
 	}
 
-	p := ipv6.NewPacketConn(c)
-	defer p.Close()
 	cm := ipv6.ControlMessage{
 		TrafficClass: DiffServAF11 | CongestionExperienced,
+		Src:          net.IPv6loopback,
+		Dst:          net.IPv6loopback,
 	}
-	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
 	ifi := loopbackInterface()
 	if ifi != nil {
 		cm.IfIndex = ifi.Index
 	}
+	wb := []byte("HELLO-R-U-THERE")
 
 	for i, toggle := range []bool{true, false, true} {
 		if err := p.SetControlMessage(cf, toggle); err != nil {
@@ -125,15 +56,19 @@
 		if err := p.SetWriteDeadline(time.Now().Add(time.Millisecond * 100)); err != nil {
 			t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
 		}
-		if _, err := p.WriteTo([]byte("HELLO-R-U-THERE"), &cm, dst); err != nil {
+		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
 			t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
+		} else if n != len(wb) {
+			t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
 		}
-		b := make([]byte, 128)
+		rb := make([]byte, 128)
 		if err := p.SetReadDeadline(time.Now().Add(time.Millisecond * 100)); err != nil {
 			t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
 		}
-		if _, cm, _, err := p.ReadFrom(b); err != nil {
+		if n, cm, _, err := p.ReadFrom(rb); err != nil {
 			t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
+		} else if !bytes.Equal(rb[:n], wb) {
+			t.Fatalf("got %v; expected %v", rb[:n], wb)
 		} else {
 			t.Logf("rcvd cmsg: %v", cm)
 		}
@@ -157,6 +92,8 @@
 		t.Fatalf("net.ListenPacket failed: %v", err)
 	}
 	defer c.Close()
+	p := ipv6.NewPacketConn(c)
+	defer p.Close()
 
 	dst, err := net.ResolveIPAddr("ip6", "::1")
 	if err != nil {
@@ -164,10 +101,12 @@
 	}
 
 	pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
-	p := ipv6.NewPacketConn(c)
-	defer p.Close()
-	cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced}
-	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
+	cm := ipv6.ControlMessage{
+		TrafficClass: DiffServAF11 | CongestionExperienced,
+		Src:          net.IPv6loopback,
+		Dst:          net.IPv6loopback,
+	}
+	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagSrc | ipv6.FlagDst | ipv6.FlagInterface | ipv6.FlagPathMTU
 	ifi := loopbackInterface()
 	if ifi != nil {
 		cm.IfIndex = ifi.Index
@@ -210,18 +149,20 @@
 		if err := p.SetWriteDeadline(time.Now().Add(time.Millisecond * 100)); err != nil {
 			t.Fatalf("ipv6.PacketConn.SetWriteDeadline failed: %v", err)
 		}
-		if _, err := p.WriteTo(wb, &cm, dst); err != nil {
+		if n, err := p.WriteTo(wb, &cm, dst); err != nil {
 			t.Fatalf("ipv6.PacketConn.WriteTo failed: %v", err)
+		} else if n != len(wb) {
+			t.Fatalf("ipv6.PacketConn.WriteTo failed: short write: %v", n)
 		}
-		b := make([]byte, 128)
+		rb := make([]byte, 128)
 		if err := p.SetReadDeadline(time.Now().Add(time.Millisecond * 100)); err != nil {
 			t.Fatalf("ipv6.PacketConn.SetReadDeadline failed: %v", err)
 		}
-		if n, cm, _, err := p.ReadFrom(b); err != nil {
+		if n, cm, _, err := p.ReadFrom(rb); err != nil {
 			t.Fatalf("ipv6.PacketConn.ReadFrom failed: %v", err)
 		} else {
 			t.Logf("rcvd cmsg: %v", cm)
-			if m, err := parseICMPMessage(b[:n]); err != nil {
+			if m, err := parseICMPMessage(rb[:n]); err != nil {
 				t.Fatalf("parseICMPMessage failed: %v", err)
 			} else if m.Type != ipv6.ICMPTypeEchoReply || m.Code != 0 {
 				t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, ipv6.ICMPTypeEchoReply, 0)