1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Package nettest provides utilities for network testing.
22 aLongTimeAgo
= time
.Unix(233431200, 0)
23 neverTimeout
= time
.Time
{}
26 // MakePipe creates a connection between two endpoints and returns the pair
27 // as c1 and c2, such that anything written to c1 is read by c2 and vice-versa.
28 // The stop function closes all resources, including c1, c2, and the underlying
29 // net.Listener (if there is one), and should not be nil.
30 type MakePipe
func() (c1
, c2 net
.Conn
, stop
func(), err error
)
32 // TestConn tests that a net.Conn implementation properly satisfies the interface.
33 // The tests should not produce any false positives, but may experience
34 // false negatives. Thus, some issues may only be detected when the test is
35 // run multiple times. For maximal effectiveness, run the tests under the
37 func TestConn(t
*testing
.T
, mp MakePipe
) {
41 type connTester
func(t
*testing
.T
, c1
, c2 net
.Conn
)
43 func timeoutWrapper(t
*testing
.T
, mp MakePipe
, f connTester
) {
44 c1
, c2
, stop
, err
:= mp()
46 t
.Fatalf("unable to make pipe: %v", err
)
49 defer once
.Do(func() { stop() })
50 timer
:= time
.AfterFunc(time
.Minute
, func() {
52 t
.Error("test timed out; terminating pipe")
60 // testBasicIO tests that the data sent on c1 is properly received on c2.
61 func testBasicIO(t
*testing
.T
, c1
, c2 net
.Conn
) {
62 want
:= make([]byte, 1<<20)
63 rand
.New(rand
.NewSource(0)).Read(want
)
65 dataCh
:= make(chan []byte)
67 rd
:= bytes
.NewReader(want
)
68 if err
:= chunkedCopy(c1
, rd
); err
!= nil {
69 t
.Errorf("unexpected c1.Write error: %v", err
)
71 if err
:= c1
.Close(); err
!= nil {
72 t
.Errorf("unexpected c1.Close error: %v", err
)
77 wr
:= new(bytes
.Buffer
)
78 if err
:= chunkedCopy(wr
, c2
); err
!= nil {
79 t
.Errorf("unexpected c2.Read error: %v", err
)
81 if err
:= c2
.Close(); err
!= nil {
82 t
.Errorf("unexpected c2.Close error: %v", err
)
87 if got
:= <-dataCh
; !bytes
.Equal(got
, want
) {
88 t
.Errorf("transmitted data differs")
92 // testPingPong tests that the two endpoints can synchronously send data to
93 // each other in a typical request-response pattern.
94 func testPingPong(t
*testing
.T
, c1
, c2 net
.Conn
) {
98 pingPonger
:= func(c net
.Conn
) {
100 buf
:= make([]byte, 8)
103 if _
, err
:= io
.ReadFull(c
, buf
); err
!= nil {
107 t
.Errorf("unexpected Read error: %v", err
)
110 v
:= binary
.LittleEndian
.Uint64(buf
)
111 binary
.LittleEndian
.PutUint64(buf
, v
+1)
112 if prev
!= 0 && prev
+2 != v
{
113 t
.Errorf("mismatching value: got %d, want %d", v
, prev
+2)
120 if _
, err
:= c
.Write(buf
); err
!= nil {
121 t
.Errorf("unexpected Write error: %v", err
)
125 if err
:= c
.Close(); err
!= nil {
126 t
.Errorf("unexpected Close error: %v", err
)
134 // Start off the chain reaction.
135 if _
, err
:= c1
.Write(make([]byte, 8)); err
!= nil {
136 t
.Errorf("unexpected c1.Write error: %v", err
)
140 // testRacyRead tests that it is safe to mutate the input Read buffer
141 // immediately after cancelation has occurred.
142 func testRacyRead(t
*testing
.T
, c1
, c2 net
.Conn
) {
143 go chunkedCopy(c2
, rand
.New(rand
.NewSource(0)))
145 var wg sync
.WaitGroup
148 c1
.SetReadDeadline(time
.Now().Add(time
.Millisecond
))
149 for i
:= 0; i
< 10; i
++ {
154 b1
:= make([]byte, 1024)
155 b2
:= make([]byte, 1024)
156 for j
:= 0; j
< 100; j
++ {
157 _
, err
:= c1
.Read(b1
)
158 copy(b1
, b2
) // Mutate b1 to trigger potential race
160 checkForTimeoutError(t
, err
)
161 c1
.SetReadDeadline(time
.Now().Add(time
.Millisecond
))
168 // testRacyWrite tests that it is safe to mutate the input Write buffer
169 // immediately after cancelation has occurred.
170 func testRacyWrite(t
*testing
.T
, c1
, c2 net
.Conn
) {
171 go chunkedCopy(ioutil
.Discard
, c2
)
173 var wg sync
.WaitGroup
176 c1
.SetWriteDeadline(time
.Now().Add(time
.Millisecond
))
177 for i
:= 0; i
< 10; i
++ {
182 b1
:= make([]byte, 1024)
183 b2
:= make([]byte, 1024)
184 for j
:= 0; j
< 100; j
++ {
185 _
, err
:= c1
.Write(b1
)
186 copy(b1
, b2
) // Mutate b1 to trigger potential race
188 checkForTimeoutError(t
, err
)
189 c1
.SetWriteDeadline(time
.Now().Add(time
.Millisecond
))
196 // testReadTimeout tests that Read timeouts do not affect Write.
197 func testReadTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
198 go chunkedCopy(ioutil
.Discard
, c2
)
200 c1
.SetReadDeadline(aLongTimeAgo
)
201 _
, err
:= c1
.Read(make([]byte, 1024))
202 checkForTimeoutError(t
, err
)
203 if _
, err
:= c1
.Write(make([]byte, 1024)); err
!= nil {
204 t
.Errorf("unexpected Write error: %v", err
)
208 // testWriteTimeout tests that Write timeouts do not affect Read.
209 func testWriteTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
210 go chunkedCopy(c2
, rand
.New(rand
.NewSource(0)))
212 c1
.SetWriteDeadline(aLongTimeAgo
)
213 _
, err
:= c1
.Write(make([]byte, 1024))
214 checkForTimeoutError(t
, err
)
215 if _
, err
:= c1
.Read(make([]byte, 1024)); err
!= nil {
216 t
.Errorf("unexpected Read error: %v", err
)
220 // testPastTimeout tests that a deadline set in the past immediately times out
221 // Read and Write requests.
222 func testPastTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
223 go chunkedCopy(c2
, c2
)
227 c1
.SetDeadline(aLongTimeAgo
)
228 n
, err
:= c1
.Write(make([]byte, 1024))
230 t
.Errorf("unexpected Write count: got %d, want 0", n
)
232 checkForTimeoutError(t
, err
)
233 n
, err
= c1
.Read(make([]byte, 1024))
235 t
.Errorf("unexpected Read count: got %d, want 0", n
)
237 checkForTimeoutError(t
, err
)
242 // testPresentTimeout tests that a deadline set while there are pending
243 // Read and Write operations immediately times out those operations.
244 func testPresentTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
245 var wg sync
.WaitGroup
249 deadlineSet
:= make(chan bool, 1)
252 time
.Sleep(100 * time
.Millisecond
)
254 c1
.SetReadDeadline(aLongTimeAgo
)
255 c1
.SetWriteDeadline(aLongTimeAgo
)
259 n
, err
:= c1
.Read(make([]byte, 1024))
261 t
.Errorf("unexpected Read count: got %d, want 0", n
)
263 checkForTimeoutError(t
, err
)
264 if len(deadlineSet
) == 0 {
265 t
.Error("Read timed out before deadline is set")
272 _
, err
= c1
.Write(make([]byte, 1024))
274 checkForTimeoutError(t
, err
)
275 if len(deadlineSet
) == 0 {
276 t
.Error("Write timed out before deadline is set")
281 // testFutureTimeout tests that a future deadline will eventually time out
282 // Read and Write operations.
283 func testFutureTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
284 var wg sync
.WaitGroup
287 c1
.SetDeadline(time
.Now().Add(100 * time
.Millisecond
))
290 _
, err
:= c1
.Read(make([]byte, 1024))
291 checkForTimeoutError(t
, err
)
297 _
, err
= c1
.Write(make([]byte, 1024))
299 checkForTimeoutError(t
, err
)
303 go chunkedCopy(c2
, c2
)
308 // testCloseTimeout tests that calling Close immediately times out pending
309 // Read and Write operations.
310 func testCloseTimeout(t
*testing
.T
, c1
, c2 net
.Conn
) {
311 go chunkedCopy(c2
, c2
)
313 var wg sync
.WaitGroup
317 // Test for cancelation upon connection closure.
318 c1
.SetDeadline(neverTimeout
)
321 time
.Sleep(100 * time
.Millisecond
)
327 buf
:= make([]byte, 1024)
329 _
, err
= c1
.Read(buf
)
335 buf
:= make([]byte, 1024)
337 _
, err
= c1
.Write(buf
)
342 // testConcurrentMethods tests that the methods of net.Conn can safely
343 // be called concurrently.
344 func testConcurrentMethods(t
*testing
.T
, c1
, c2 net
.Conn
) {
345 if runtime
.GOOS
== "plan9" {
346 t
.Skip("skipping on plan9; see https://golang.org/issue/20489")
348 go chunkedCopy(c2
, c2
)
350 // The results of the calls may be nonsensical, but this should
351 // not trigger a race detector warning.
352 var wg sync
.WaitGroup
353 for i
:= 0; i
< 100; i
++ {
357 c1
.Read(make([]byte, 1024))
361 c1
.Write(make([]byte, 1024))
365 c1
.SetDeadline(time
.Now().Add(10 * time
.Millisecond
))
369 c1
.SetReadDeadline(aLongTimeAgo
)
373 c1
.SetWriteDeadline(aLongTimeAgo
)
384 wg
.Wait() // At worst, the deadline is set 10ms into the future
390 // checkForTimeoutError checks that the error satisfies the Error interface
391 // and that Timeout returns true.
392 func checkForTimeoutError(t
*testing
.T
, err error
) {
393 if nerr
, ok
:= err
.(net
.Error
); ok
{
395 t
.Errorf("err.Timeout() = false, want true")
398 t
.Errorf("got %T, want net.Error", err
)
402 // testRoundtrip writes something into c and reads it back.
403 // It assumes that everything written into c is echoed back to itself.
404 func testRoundtrip(t
*testing
.T
, c net
.Conn
) {
405 if err
:= c
.SetDeadline(neverTimeout
); err
!= nil {
406 t
.Errorf("roundtrip SetDeadline error: %v", err
)
409 const s
= "Hello, world!"
411 if _
, err
:= c
.Write(buf
); err
!= nil {
412 t
.Errorf("roundtrip Write error: %v", err
)
414 if _
, err
:= io
.ReadFull(c
, buf
); err
!= nil {
415 t
.Errorf("roundtrip Read error: %v", err
)
417 if string(buf
) != s
{
418 t
.Errorf("roundtrip data mismatch: got %q, want %q", buf
, s
)
422 // resyncConn resynchronizes the connection into a sane state.
423 // It assumes that everything written into c is echoed back to itself.
424 // It assumes that 0xff is not currently on the wire or in the read buffer.
425 func resyncConn(t
*testing
.T
, c net
.Conn
) {
426 c
.SetDeadline(neverTimeout
)
427 errCh
:= make(chan error
)
429 _
, err
:= c
.Write([]byte{0xff})
432 buf
:= make([]byte, 1024)
434 n
, err
:= c
.Read(buf
)
435 if n
> 0 && bytes
.IndexByte(buf
[:n
], 0xff) == n
-1 {
439 t
.Errorf("unexpected Read error: %v", err
)
443 if err
:= <-errCh
; err
!= nil {
444 t
.Errorf("unexpected Write error: %v", err
)
448 // chunkedCopy copies from r to w in fixed-width chunks to avoid
449 // causing a Write that exceeds the maximum packet size for packet-based
450 // connections like "unixpacket".
451 // We assume that the maximum packet size is at least 1024.
452 func chunkedCopy(w io
.Writer
, r io
.Reader
) error
{
453 b
:= make([]byte, 1024)
454 _
, err
:= io
.CopyBuffer(struct{ io
.Writer
}{w
}, struct{ io
.Reader
}{r
}, b
)