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