writev_test.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. //go:build !js
  5. package net
  6. import (
  7. "bytes"
  8. "fmt"
  9. "internal/poll"
  10. "io"
  11. "reflect"
  12. "runtime"
  13. "sync"
  14. "testing"
  15. )
  16. func TestBuffers_read(t *testing.T) {
  17. const story = "once upon a time in Gopherland ... "
  18. buffers := Buffers{
  19. []byte("once "),
  20. []byte("upon "),
  21. []byte("a "),
  22. []byte("time "),
  23. []byte("in "),
  24. []byte("Gopherland ... "),
  25. }
  26. got, err := io.ReadAll(&buffers)
  27. if err != nil {
  28. t.Fatal(err)
  29. }
  30. if string(got) != story {
  31. t.Errorf("read %q; want %q", got, story)
  32. }
  33. if len(buffers) != 0 {
  34. t.Errorf("len(buffers) = %d; want 0", len(buffers))
  35. }
  36. }
  37. func TestBuffers_consume(t *testing.T) {
  38. tests := []struct {
  39. in Buffers
  40. consume int64
  41. want Buffers
  42. }{
  43. {
  44. in: Buffers{[]byte("foo"), []byte("bar")},
  45. consume: 0,
  46. want: Buffers{[]byte("foo"), []byte("bar")},
  47. },
  48. {
  49. in: Buffers{[]byte("foo"), []byte("bar")},
  50. consume: 2,
  51. want: Buffers{[]byte("o"), []byte("bar")},
  52. },
  53. {
  54. in: Buffers{[]byte("foo"), []byte("bar")},
  55. consume: 3,
  56. want: Buffers{[]byte("bar")},
  57. },
  58. {
  59. in: Buffers{[]byte("foo"), []byte("bar")},
  60. consume: 4,
  61. want: Buffers{[]byte("ar")},
  62. },
  63. {
  64. in: Buffers{nil, nil, nil, []byte("bar")},
  65. consume: 1,
  66. want: Buffers{[]byte("ar")},
  67. },
  68. {
  69. in: Buffers{nil, nil, nil, []byte("foo")},
  70. consume: 0,
  71. want: Buffers{[]byte("foo")},
  72. },
  73. {
  74. in: Buffers{nil, nil, nil},
  75. consume: 0,
  76. want: Buffers{},
  77. },
  78. }
  79. for i, tt := range tests {
  80. in := tt.in
  81. in.consume(tt.consume)
  82. if !reflect.DeepEqual(in, tt.want) {
  83. t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
  84. }
  85. }
  86. }
  87. func TestBuffers_WriteTo(t *testing.T) {
  88. for _, name := range []string{"WriteTo", "Copy"} {
  89. for _, size := range []int{0, 10, 1023, 1024, 1025} {
  90. t.Run(fmt.Sprintf("%s/%d", name, size), func(t *testing.T) {
  91. testBuffer_writeTo(t, size, name == "Copy")
  92. })
  93. }
  94. }
  95. }
  96. func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
  97. oldHook := poll.TestHookDidWritev
  98. defer func() { poll.TestHookDidWritev = oldHook }()
  99. var writeLog struct {
  100. sync.Mutex
  101. log []int
  102. }
  103. poll.TestHookDidWritev = func(size int) {
  104. writeLog.Lock()
  105. writeLog.log = append(writeLog.log, size)
  106. writeLog.Unlock()
  107. }
  108. var want bytes.Buffer
  109. for i := 0; i < chunks; i++ {
  110. want.WriteByte(byte(i))
  111. }
  112. withTCPConnPair(t, func(c *TCPConn) error {
  113. buffers := make(Buffers, chunks)
  114. for i := range buffers {
  115. buffers[i] = want.Bytes()[i : i+1]
  116. }
  117. var n int64
  118. var err error
  119. if useCopy {
  120. n, err = io.Copy(c, &buffers)
  121. } else {
  122. n, err = buffers.WriteTo(c)
  123. }
  124. if err != nil {
  125. return err
  126. }
  127. if len(buffers) != 0 {
  128. return fmt.Errorf("len(buffers) = %d; want 0", len(buffers))
  129. }
  130. if n != int64(want.Len()) {
  131. return fmt.Errorf("Buffers.WriteTo returned %d; want %d", n, want.Len())
  132. }
  133. return nil
  134. }, func(c *TCPConn) error {
  135. all, err := io.ReadAll(c)
  136. if !bytes.Equal(all, want.Bytes()) || err != nil {
  137. return fmt.Errorf("client read %q, %v; want %q, nil", all, err, want.Bytes())
  138. }
  139. writeLog.Lock() // no need to unlock
  140. var gotSum int
  141. for _, v := range writeLog.log {
  142. gotSum += v
  143. }
  144. var wantSum int
  145. switch runtime.GOOS {
  146. case "android", "darwin", "ios", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd":
  147. var wantMinCalls int
  148. wantSum = want.Len()
  149. v := chunks
  150. for v > 0 {
  151. wantMinCalls++
  152. v -= 1024
  153. }
  154. if len(writeLog.log) < wantMinCalls {
  155. t.Errorf("write calls = %v < wanted min %v", len(writeLog.log), wantMinCalls)
  156. }
  157. case "windows":
  158. var wantCalls int
  159. wantSum = want.Len()
  160. if wantSum > 0 {
  161. wantCalls = 1 // windows will always do 1 syscall, unless sending empty buffer
  162. }
  163. if len(writeLog.log) != wantCalls {
  164. t.Errorf("write calls = %v; want %v", len(writeLog.log), wantCalls)
  165. }
  166. }
  167. if gotSum != wantSum {
  168. t.Errorf("writev call sum = %v; want %v", gotSum, wantSum)
  169. }
  170. return nil
  171. })
  172. }
  173. func TestWritevError(t *testing.T) {
  174. if runtime.GOOS == "windows" {
  175. t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
  176. }
  177. ln := newLocalListener(t, "tcp")
  178. defer ln.Close()
  179. ch := make(chan Conn, 1)
  180. go func() {
  181. defer close(ch)
  182. c, err := ln.Accept()
  183. if err != nil {
  184. t.Error(err)
  185. return
  186. }
  187. ch <- c
  188. }()
  189. c1, err := Dial("tcp", ln.Addr().String())
  190. if err != nil {
  191. t.Fatal(err)
  192. }
  193. defer c1.Close()
  194. c2 := <-ch
  195. if c2 == nil {
  196. t.Fatal("no server side connection")
  197. }
  198. c2.Close()
  199. // 1 GB of data should be enough to notice the connection is gone.
  200. // Just a few bytes is not enough.
  201. // Arrange to reuse the same 1 MB buffer so that we don't allocate much.
  202. buf := make([]byte, 1<<20)
  203. buffers := make(Buffers, 1<<10)
  204. for i := range buffers {
  205. buffers[i] = buf
  206. }
  207. if _, err := buffers.WriteTo(c1); err == nil {
  208. t.Fatal("Buffers.WriteTo(closed conn) succeeded, want error")
  209. }
  210. }