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