conntest.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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.
  4. // Package nettest provides utilities for network testing.
  5. package nettest
  6. import (
  7. "bytes"
  8. "encoding/binary"
  9. "io"
  10. "io/ioutil"
  11. "math/rand"
  12. "net"
  13. "runtime"
  14. "sync"
  15. "testing"
  16. "time"
  17. )
  18. var (
  19. aLongTimeAgo = time.Unix(233431200, 0)
  20. neverTimeout = time.Time{}
  21. )
  22. // MakePipe creates a connection between two endpoints and returns the pair
  23. // as c1 and c2, such that anything written to c1 is read by c2 and vice-versa.
  24. // The stop function closes all resources, including c1, c2, and the underlying
  25. // net.Listener (if there is one), and should not be nil.
  26. type MakePipe func() (c1, c2 net.Conn, stop func(), err error)
  27. // TestConn tests that a net.Conn implementation properly satisfies the interface.
  28. // The tests should not produce any false positives, but may experience
  29. // false negatives. Thus, some issues may only be detected when the test is
  30. // run multiple times. For maximal effectiveness, run the tests under the
  31. // race detector.
  32. func TestConn(t *testing.T, mp MakePipe) {
  33. testConn(t, mp)
  34. }
  35. type connTester func(t *testing.T, c1, c2 net.Conn)
  36. func timeoutWrapper(t *testing.T, mp MakePipe, f connTester) {
  37. c1, c2, stop, err := mp()
  38. if err != nil {
  39. t.Fatalf("unable to make pipe: %v", err)
  40. }
  41. var once sync.Once
  42. defer once.Do(func() { stop() })
  43. timer := time.AfterFunc(time.Minute, func() {
  44. once.Do(func() {
  45. t.Error("test timed out; terminating pipe")
  46. stop()
  47. })
  48. })
  49. defer timer.Stop()
  50. f(t, c1, c2)
  51. }
  52. // testBasicIO tests that the data sent on c1 is properly received on c2.
  53. func testBasicIO(t *testing.T, c1, c2 net.Conn) {
  54. want := make([]byte, 1<<20)
  55. rand.New(rand.NewSource(0)).Read(want)
  56. dataCh := make(chan []byte)
  57. go func() {
  58. rd := bytes.NewReader(want)
  59. if err := chunkedCopy(c1, rd); err != nil {
  60. t.Errorf("unexpected c1.Write error: %v", err)
  61. }
  62. if err := c1.Close(); err != nil {
  63. t.Errorf("unexpected c1.Close error: %v", err)
  64. }
  65. }()
  66. go func() {
  67. wr := new(bytes.Buffer)
  68. if err := chunkedCopy(wr, c2); err != nil {
  69. t.Errorf("unexpected c2.Read error: %v", err)
  70. }
  71. if err := c2.Close(); err != nil {
  72. t.Errorf("unexpected c2.Close error: %v", err)
  73. }
  74. dataCh <- wr.Bytes()
  75. }()
  76. if got := <-dataCh; !bytes.Equal(got, want) {
  77. t.Errorf("transmitted data differs")
  78. }
  79. }
  80. // testPingPong tests that the two endpoints can synchronously send data to
  81. // each other in a typical request-response pattern.
  82. func testPingPong(t *testing.T, c1, c2 net.Conn) {
  83. var wg sync.WaitGroup
  84. defer wg.Wait()
  85. pingPonger := func(c net.Conn) {
  86. defer wg.Done()
  87. buf := make([]byte, 8)
  88. var prev uint64
  89. for {
  90. if _, err := io.ReadFull(c, buf); err != nil {
  91. if err == io.EOF {
  92. break
  93. }
  94. t.Errorf("unexpected Read error: %v", err)
  95. }
  96. v := binary.LittleEndian.Uint64(buf)
  97. binary.LittleEndian.PutUint64(buf, v+1)
  98. if prev != 0 && prev+2 != v {
  99. t.Errorf("mismatching value: got %d, want %d", v, prev+2)
  100. }
  101. prev = v
  102. if v == 1000 {
  103. break
  104. }
  105. if _, err := c.Write(buf); err != nil {
  106. t.Errorf("unexpected Write error: %v", err)
  107. break
  108. }
  109. }
  110. if err := c.Close(); err != nil {
  111. t.Errorf("unexpected Close error: %v", err)
  112. }
  113. }
  114. wg.Add(2)
  115. go pingPonger(c1)
  116. go pingPonger(c2)
  117. // Start off the chain reaction.
  118. if _, err := c1.Write(make([]byte, 8)); err != nil {
  119. t.Errorf("unexpected c1.Write error: %v", err)
  120. }
  121. }
  122. // testRacyRead tests that it is safe to mutate the input Read buffer
  123. // immediately after cancelation has occurred.
  124. func testRacyRead(t *testing.T, c1, c2 net.Conn) {
  125. go chunkedCopy(c2, rand.New(rand.NewSource(0)))
  126. var wg sync.WaitGroup
  127. defer wg.Wait()
  128. c1.SetReadDeadline(time.Now().Add(time.Millisecond))
  129. for i := 0; i < 10; i++ {
  130. wg.Add(1)
  131. go func() {
  132. defer wg.Done()
  133. b1 := make([]byte, 1024)
  134. b2 := make([]byte, 1024)
  135. for j := 0; j < 100; j++ {
  136. _, err := c1.Read(b1)
  137. copy(b1, b2) // Mutate b1 to trigger potential race
  138. if err != nil {
  139. checkForTimeoutError(t, err)
  140. c1.SetReadDeadline(time.Now().Add(time.Millisecond))
  141. }
  142. }
  143. }()
  144. }
  145. }
  146. // testRacyWrite tests that it is safe to mutate the input Write buffer
  147. // immediately after cancelation has occurred.
  148. func testRacyWrite(t *testing.T, c1, c2 net.Conn) {
  149. go chunkedCopy(ioutil.Discard, c2)
  150. var wg sync.WaitGroup
  151. defer wg.Wait()
  152. c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
  153. for i := 0; i < 10; i++ {
  154. wg.Add(1)
  155. go func() {
  156. defer wg.Done()
  157. b1 := make([]byte, 1024)
  158. b2 := make([]byte, 1024)
  159. for j := 0; j < 100; j++ {
  160. _, err := c1.Write(b1)
  161. copy(b1, b2) // Mutate b1 to trigger potential race
  162. if err != nil {
  163. checkForTimeoutError(t, err)
  164. c1.SetWriteDeadline(time.Now().Add(time.Millisecond))
  165. }
  166. }
  167. }()
  168. }
  169. }
  170. // testReadTimeout tests that Read timeouts do not affect Write.
  171. func testReadTimeout(t *testing.T, c1, c2 net.Conn) {
  172. go chunkedCopy(ioutil.Discard, c2)
  173. c1.SetReadDeadline(aLongTimeAgo)
  174. _, err := c1.Read(make([]byte, 1024))
  175. checkForTimeoutError(t, err)
  176. if _, err := c1.Write(make([]byte, 1024)); err != nil {
  177. t.Errorf("unexpected Write error: %v", err)
  178. }
  179. }
  180. // testWriteTimeout tests that Write timeouts do not affect Read.
  181. func testWriteTimeout(t *testing.T, c1, c2 net.Conn) {
  182. go chunkedCopy(c2, rand.New(rand.NewSource(0)))
  183. c1.SetWriteDeadline(aLongTimeAgo)
  184. _, err := c1.Write(make([]byte, 1024))
  185. checkForTimeoutError(t, err)
  186. if _, err := c1.Read(make([]byte, 1024)); err != nil {
  187. t.Errorf("unexpected Read error: %v", err)
  188. }
  189. }
  190. // testPastTimeout tests that a deadline set in the past immediately times out
  191. // Read and Write requests.
  192. func testPastTimeout(t *testing.T, c1, c2 net.Conn) {
  193. go chunkedCopy(c2, c2)
  194. testRoundtrip(t, c1)
  195. c1.SetDeadline(aLongTimeAgo)
  196. n, err := c1.Write(make([]byte, 1024))
  197. if n != 0 {
  198. t.Errorf("unexpected Write count: got %d, want 0", n)
  199. }
  200. checkForTimeoutError(t, err)
  201. n, err = c1.Read(make([]byte, 1024))
  202. if n != 0 {
  203. t.Errorf("unexpected Read count: got %d, want 0", n)
  204. }
  205. checkForTimeoutError(t, err)
  206. testRoundtrip(t, c1)
  207. }
  208. // testPresentTimeout tests that a deadline set while there are pending
  209. // Read and Write operations immediately times out those operations.
  210. func testPresentTimeout(t *testing.T, c1, c2 net.Conn) {
  211. var wg sync.WaitGroup
  212. defer wg.Wait()
  213. wg.Add(3)
  214. deadlineSet := make(chan bool, 1)
  215. go func() {
  216. defer wg.Done()
  217. time.Sleep(100 * time.Millisecond)
  218. deadlineSet <- true
  219. c1.SetReadDeadline(aLongTimeAgo)
  220. c1.SetWriteDeadline(aLongTimeAgo)
  221. }()
  222. go func() {
  223. defer wg.Done()
  224. n, err := c1.Read(make([]byte, 1024))
  225. if n != 0 {
  226. t.Errorf("unexpected Read count: got %d, want 0", n)
  227. }
  228. checkForTimeoutError(t, err)
  229. if len(deadlineSet) == 0 {
  230. t.Error("Read timed out before deadline is set")
  231. }
  232. }()
  233. go func() {
  234. defer wg.Done()
  235. var err error
  236. for err == nil {
  237. _, err = c1.Write(make([]byte, 1024))
  238. }
  239. checkForTimeoutError(t, err)
  240. if len(deadlineSet) == 0 {
  241. t.Error("Write timed out before deadline is set")
  242. }
  243. }()
  244. }
  245. // testFutureTimeout tests that a future deadline will eventually time out
  246. // Read and Write operations.
  247. func testFutureTimeout(t *testing.T, c1, c2 net.Conn) {
  248. var wg sync.WaitGroup
  249. wg.Add(2)
  250. c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
  251. go func() {
  252. defer wg.Done()
  253. _, err := c1.Read(make([]byte, 1024))
  254. checkForTimeoutError(t, err)
  255. }()
  256. go func() {
  257. defer wg.Done()
  258. var err error
  259. for err == nil {
  260. _, err = c1.Write(make([]byte, 1024))
  261. }
  262. checkForTimeoutError(t, err)
  263. }()
  264. wg.Wait()
  265. go chunkedCopy(c2, c2)
  266. resyncConn(t, c1)
  267. testRoundtrip(t, c1)
  268. }
  269. // testCloseTimeout tests that calling Close immediately times out pending
  270. // Read and Write operations.
  271. func testCloseTimeout(t *testing.T, c1, c2 net.Conn) {
  272. go chunkedCopy(c2, c2)
  273. var wg sync.WaitGroup
  274. defer wg.Wait()
  275. wg.Add(3)
  276. // Test for cancelation upon connection closure.
  277. c1.SetDeadline(neverTimeout)
  278. go func() {
  279. defer wg.Done()
  280. time.Sleep(100 * time.Millisecond)
  281. c1.Close()
  282. }()
  283. go func() {
  284. defer wg.Done()
  285. var err error
  286. buf := make([]byte, 1024)
  287. for err == nil {
  288. _, err = c1.Read(buf)
  289. }
  290. }()
  291. go func() {
  292. defer wg.Done()
  293. var err error
  294. buf := make([]byte, 1024)
  295. for err == nil {
  296. _, err = c1.Write(buf)
  297. }
  298. }()
  299. }
  300. // testConcurrentMethods tests that the methods of net.Conn can safely
  301. // be called concurrently.
  302. func testConcurrentMethods(t *testing.T, c1, c2 net.Conn) {
  303. if runtime.GOOS == "plan9" {
  304. t.Skip("skipping on plan9; see https://golang.org/issue/20489")
  305. }
  306. go chunkedCopy(c2, c2)
  307. // The results of the calls may be nonsensical, but this should
  308. // not trigger a race detector warning.
  309. var wg sync.WaitGroup
  310. for i := 0; i < 100; i++ {
  311. wg.Add(7)
  312. go func() {
  313. defer wg.Done()
  314. c1.Read(make([]byte, 1024))
  315. }()
  316. go func() {
  317. defer wg.Done()
  318. c1.Write(make([]byte, 1024))
  319. }()
  320. go func() {
  321. defer wg.Done()
  322. c1.SetDeadline(time.Now().Add(10 * time.Millisecond))
  323. }()
  324. go func() {
  325. defer wg.Done()
  326. c1.SetReadDeadline(aLongTimeAgo)
  327. }()
  328. go func() {
  329. defer wg.Done()
  330. c1.SetWriteDeadline(aLongTimeAgo)
  331. }()
  332. go func() {
  333. defer wg.Done()
  334. c1.LocalAddr()
  335. }()
  336. go func() {
  337. defer wg.Done()
  338. c1.RemoteAddr()
  339. }()
  340. }
  341. wg.Wait() // At worst, the deadline is set 10ms into the future
  342. resyncConn(t, c1)
  343. testRoundtrip(t, c1)
  344. }
  345. // checkForTimeoutError checks that the error satisfies the Error interface
  346. // and that Timeout returns true.
  347. func checkForTimeoutError(t *testing.T, err error) {
  348. if nerr, ok := err.(net.Error); ok {
  349. if !nerr.Timeout() {
  350. t.Errorf("err.Timeout() = false, want true")
  351. }
  352. } else {
  353. t.Errorf("got %T, want net.Error", err)
  354. }
  355. }
  356. // testRoundtrip writes something into c and reads it back.
  357. // It assumes that everything written into c is echoed back to itself.
  358. func testRoundtrip(t *testing.T, c net.Conn) {
  359. if err := c.SetDeadline(neverTimeout); err != nil {
  360. t.Errorf("roundtrip SetDeadline error: %v", err)
  361. }
  362. const s = "Hello, world!"
  363. buf := []byte(s)
  364. if _, err := c.Write(buf); err != nil {
  365. t.Errorf("roundtrip Write error: %v", err)
  366. }
  367. if _, err := io.ReadFull(c, buf); err != nil {
  368. t.Errorf("roundtrip Read error: %v", err)
  369. }
  370. if string(buf) != s {
  371. t.Errorf("roundtrip data mismatch: got %q, want %q", buf, s)
  372. }
  373. }
  374. // resyncConn resynchronizes the connection into a sane state.
  375. // It assumes that everything written into c is echoed back to itself.
  376. // It assumes that 0xff is not currently on the wire or in the read buffer.
  377. func resyncConn(t *testing.T, c net.Conn) {
  378. c.SetDeadline(neverTimeout)
  379. errCh := make(chan error)
  380. go func() {
  381. _, err := c.Write([]byte{0xff})
  382. errCh <- err
  383. }()
  384. buf := make([]byte, 1024)
  385. for {
  386. n, err := c.Read(buf)
  387. if n > 0 && bytes.IndexByte(buf[:n], 0xff) == n-1 {
  388. break
  389. }
  390. if err != nil {
  391. t.Errorf("unexpected Read error: %v", err)
  392. break
  393. }
  394. }
  395. if err := <-errCh; err != nil {
  396. t.Errorf("unexpected Write error: %v", err)
  397. }
  398. }
  399. // chunkedCopy copies from r to w in fixed-width chunks to avoid
  400. // causing a Write that exceeds the maximum packet size for packet-based
  401. // connections like "unixpacket".
  402. // We assume that the maximum packet size is at least 1024.
  403. func chunkedCopy(w io.Writer, r io.Reader) error {
  404. b := make([]byte, 1024)
  405. _, err := io.CopyBuffer(struct{ io.Writer }{w}, struct{ io.Reader }{r}, b)
  406. return err
  407. }