| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 | // Copyright 2016 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 nettest provides utilities for network testing.package nettestimport (	"bytes"	"encoding/binary"	"io"	"io/ioutil"	"math/rand"	"net"	"runtime"	"sync"	"testing"	"time")var (	aLongTimeAgo = time.Unix(233431200, 0)	neverTimeout = time.Time{})// MakePipe creates a connection between two endpoints and returns the pair// as c1 and c2, such that anything written to c1 is read by c2 and vice-versa.// The stop function closes all resources, including c1, c2, and the underlying// net.Listener (if there is one), and should not be nil.type MakePipe func() (c1, c2 net.Conn, stop func(), err error)// TestConn tests that a net.Conn implementation properly satisfies the interface.// The tests should not produce any false positives, but may experience// false negatives. Thus, some issues may only be detected when the test is// run multiple times. For maximal effectiveness, run the tests under the// race detector.func TestConn(t *testing.T, mp MakePipe) {	testConn(t, mp)}type connTester func(t *testing.T, c1, c2 net.Conn)func timeoutWrapper(t *testing.T, mp MakePipe, f connTester) {	c1, c2, stop, err := mp()	if err != nil {		t.Fatalf("unable to make pipe: %v", err)	}	var once sync.Once	defer once.Do(func() { stop() })	timer := time.AfterFunc(time.Minute, func() {		once.Do(func() {			t.Error("test timed out; terminating pipe")			stop()		})	})	defer timer.Stop()	f(t, c1, c2)}// testBasicIO tests that the data sent on c1 is properly received on c2.func testBasicIO(t *testing.T, c1, c2 net.Conn) {	want := make([]byte, 1<<20)	rand.New(rand.NewSource(0)).Read(want)	dataCh := make(chan []byte)	go func() {		rd := bytes.NewReader(want)		if err := chunkedCopy(c1, rd); err != nil {			t.Errorf("unexpected c1.Write error: %v", err)		}		if err := c1.Close(); err != nil {			t.Errorf("unexpected c1.Close error: %v", err)		}	}()	go func() {		wr := new(bytes.Buffer)		if err := chunkedCopy(wr, c2); err != nil {			t.Errorf("unexpected c2.Read error: %v", err)		}		if err := c2.Close(); err != nil {			t.Errorf("unexpected c2.Close error: %v", err)		}		dataCh <- wr.Bytes()	}()	if got := <-dataCh; !bytes.Equal(got, want) {		t.Errorf("transmitted data differs")	}}// testPingPong tests that the two endpoints can synchronously send data to// each other in a typical request-response pattern.func testPingPong(t *testing.T, c1, c2 net.Conn) {	var wg sync.WaitGroup	defer wg.Wait()	pingPonger := func(c net.Conn) {		defer wg.Done()		buf := make([]byte, 8)		var prev uint64		for {			if _, err := io.ReadFull(c, buf); err != nil {				if err == io.EOF {					break				}				t.Errorf("unexpected Read error: %v", err)			}			v := binary.LittleEndian.Uint64(buf)			binary.LittleEndian.PutUint64(buf, v+1)			if prev != 0 && prev+2 != v {				t.Errorf("mismatching value: got %d, want %d", v, prev+2)			}			prev = v			if v == 1000 {				break			}			if _, err := c.Write(buf); err != nil {				t.Errorf("unexpected Write error: %v", err)				break			}		}		if err := c.Close(); err != nil {			t.Errorf("unexpected Close error: %v", err)		}	}	wg.Add(2)	go pingPonger(c1)	go pingPonger(c2)	// Start off the chain reaction.	if _, err := c1.Write(make([]byte, 8)); err != nil {		t.Errorf("unexpected c1.Write error: %v", err)	}}// testRacyRead tests that it is safe to mutate the input Read buffer// immediately after cancelation has occurred.func testRacyRead(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(c2, rand.New(rand.NewSource(0)))	var wg sync.WaitGroup	defer wg.Wait()	c1.SetReadDeadline(time.Now().Add(time.Millisecond))	for i := 0; i < 10; i++ {		wg.Add(1)		go func() {			defer wg.Done()			b1 := make([]byte, 1024)			b2 := make([]byte, 1024)			for j := 0; j < 100; j++ {				_, err := c1.Read(b1)				copy(b1, b2) // Mutate b1 to trigger potential race				if err != nil {					checkForTimeoutError(t, err)					c1.SetReadDeadline(time.Now().Add(time.Millisecond))				}			}		}()	}}// testRacyWrite tests that it is safe to mutate the input Write buffer// immediately after cancelation has occurred.func testRacyWrite(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(ioutil.Discard, c2)	var wg sync.WaitGroup	defer wg.Wait()	c1.SetWriteDeadline(time.Now().Add(time.Millisecond))	for i := 0; i < 10; i++ {		wg.Add(1)		go func() {			defer wg.Done()			b1 := make([]byte, 1024)			b2 := make([]byte, 1024)			for j := 0; j < 100; j++ {				_, err := c1.Write(b1)				copy(b1, b2) // Mutate b1 to trigger potential race				if err != nil {					checkForTimeoutError(t, err)					c1.SetWriteDeadline(time.Now().Add(time.Millisecond))				}			}		}()	}}// testReadTimeout tests that Read timeouts do not affect Write.func testReadTimeout(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(ioutil.Discard, c2)	c1.SetReadDeadline(aLongTimeAgo)	_, err := c1.Read(make([]byte, 1024))	checkForTimeoutError(t, err)	if _, err := c1.Write(make([]byte, 1024)); err != nil {		t.Errorf("unexpected Write error: %v", err)	}}// testWriteTimeout tests that Write timeouts do not affect Read.func testWriteTimeout(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(c2, rand.New(rand.NewSource(0)))	c1.SetWriteDeadline(aLongTimeAgo)	_, err := c1.Write(make([]byte, 1024))	checkForTimeoutError(t, err)	if _, err := c1.Read(make([]byte, 1024)); err != nil {		t.Errorf("unexpected Read error: %v", err)	}}// testPastTimeout tests that a deadline set in the past immediately times out// Read and Write requests.func testPastTimeout(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(c2, c2)	testRoundtrip(t, c1)	c1.SetDeadline(aLongTimeAgo)	n, err := c1.Write(make([]byte, 1024))	if n != 0 {		t.Errorf("unexpected Write count: got %d, want 0", n)	}	checkForTimeoutError(t, err)	n, err = c1.Read(make([]byte, 1024))	if n != 0 {		t.Errorf("unexpected Read count: got %d, want 0", n)	}	checkForTimeoutError(t, err)	testRoundtrip(t, c1)}// testPresentTimeout tests that a deadline set while there are pending// Read and Write operations immediately times out those operations.func testPresentTimeout(t *testing.T, c1, c2 net.Conn) {	var wg sync.WaitGroup	defer wg.Wait()	wg.Add(3)	deadlineSet := make(chan bool, 1)	go func() {		defer wg.Done()		time.Sleep(100 * time.Millisecond)		deadlineSet <- true		c1.SetReadDeadline(aLongTimeAgo)		c1.SetWriteDeadline(aLongTimeAgo)	}()	go func() {		defer wg.Done()		n, err := c1.Read(make([]byte, 1024))		if n != 0 {			t.Errorf("unexpected Read count: got %d, want 0", n)		}		checkForTimeoutError(t, err)		if len(deadlineSet) == 0 {			t.Error("Read timed out before deadline is set")		}	}()	go func() {		defer wg.Done()		var err error		for err == nil {			_, err = c1.Write(make([]byte, 1024))		}		checkForTimeoutError(t, err)		if len(deadlineSet) == 0 {			t.Error("Write timed out before deadline is set")		}	}()}// testFutureTimeout tests that a future deadline will eventually time out// Read and Write operations.func testFutureTimeout(t *testing.T, c1, c2 net.Conn) {	var wg sync.WaitGroup	wg.Add(2)	c1.SetDeadline(time.Now().Add(100 * time.Millisecond))	go func() {		defer wg.Done()		_, err := c1.Read(make([]byte, 1024))		checkForTimeoutError(t, err)	}()	go func() {		defer wg.Done()		var err error		for err == nil {			_, err = c1.Write(make([]byte, 1024))		}		checkForTimeoutError(t, err)	}()	wg.Wait()	go chunkedCopy(c2, c2)	resyncConn(t, c1)	testRoundtrip(t, c1)}// testCloseTimeout tests that calling Close immediately times out pending// Read and Write operations.func testCloseTimeout(t *testing.T, c1, c2 net.Conn) {	go chunkedCopy(c2, c2)	var wg sync.WaitGroup	defer wg.Wait()	wg.Add(3)	// Test for cancelation upon connection closure.	c1.SetDeadline(neverTimeout)	go func() {		defer wg.Done()		time.Sleep(100 * time.Millisecond)		c1.Close()	}()	go func() {		defer wg.Done()		var err error		buf := make([]byte, 1024)		for err == nil {			_, err = c1.Read(buf)		}	}()	go func() {		defer wg.Done()		var err error		buf := make([]byte, 1024)		for err == nil {			_, err = c1.Write(buf)		}	}()}// testConcurrentMethods tests that the methods of net.Conn can safely// be called concurrently.func testConcurrentMethods(t *testing.T, c1, c2 net.Conn) {	if runtime.GOOS == "plan9" {		t.Skip("skipping on plan9; see https://golang.org/issue/20489")	}	go chunkedCopy(c2, c2)	// The results of the calls may be nonsensical, but this should	// not trigger a race detector warning.	var wg sync.WaitGroup	for i := 0; i < 100; i++ {		wg.Add(7)		go func() {			defer wg.Done()			c1.Read(make([]byte, 1024))		}()		go func() {			defer wg.Done()			c1.Write(make([]byte, 1024))		}()		go func() {			defer wg.Done()			c1.SetDeadline(time.Now().Add(10 * time.Millisecond))		}()		go func() {			defer wg.Done()			c1.SetReadDeadline(aLongTimeAgo)		}()		go func() {			defer wg.Done()			c1.SetWriteDeadline(aLongTimeAgo)		}()		go func() {			defer wg.Done()			c1.LocalAddr()		}()		go func() {			defer wg.Done()			c1.RemoteAddr()		}()	}	wg.Wait() // At worst, the deadline is set 10ms into the future	resyncConn(t, c1)	testRoundtrip(t, c1)}// checkForTimeoutError checks that the error satisfies the Error interface// and that Timeout returns true.func checkForTimeoutError(t *testing.T, err error) {	if nerr, ok := err.(net.Error); ok {		if !nerr.Timeout() {			t.Errorf("err.Timeout() = false, want true")		}	} else {		t.Errorf("got %T, want net.Error", err)	}}// testRoundtrip writes something into c and reads it back.// It assumes that everything written into c is echoed back to itself.func testRoundtrip(t *testing.T, c net.Conn) {	if err := c.SetDeadline(neverTimeout); err != nil {		t.Errorf("roundtrip SetDeadline error: %v", err)	}	const s = "Hello, world!"	buf := []byte(s)	if _, err := c.Write(buf); err != nil {		t.Errorf("roundtrip Write error: %v", err)	}	if _, err := io.ReadFull(c, buf); err != nil {		t.Errorf("roundtrip Read error: %v", err)	}	if string(buf) != s {		t.Errorf("roundtrip data mismatch: got %q, want %q", buf, s)	}}// resyncConn resynchronizes the connection into a sane state.// It assumes that everything written into c is echoed back to itself.// It assumes that 0xff is not currently on the wire or in the read buffer.func resyncConn(t *testing.T, c net.Conn) {	c.SetDeadline(neverTimeout)	errCh := make(chan error)	go func() {		_, err := c.Write([]byte{0xff})		errCh <- err	}()	buf := make([]byte, 1024)	for {		n, err := c.Read(buf)		if n > 0 && bytes.IndexByte(buf[:n], 0xff) == n-1 {			break		}		if err != nil {			t.Errorf("unexpected Read error: %v", err)			break		}	}	if err := <-errCh; err != nil {		t.Errorf("unexpected Write error: %v", err)	}}// chunkedCopy copies from r to w in fixed-width chunks to avoid// causing a Write that exceeds the maximum packet size for packet-based// connections like "unixpacket".// We assume that the maximum packet size is at least 1024.func chunkedCopy(w io.Writer, r io.Reader) error {	b := make([]byte, 1024)	_, err := io.CopyBuffer(struct{ io.Writer }{w}, struct{ io.Reader }{r}, b)	return err}
 |