Source file
src/net/sendfile_test.go
Documentation: net
1
2
3
4
5 package net
6
7 import (
8 "bytes"
9 "context"
10 "crypto/sha256"
11 "encoding/hex"
12 "errors"
13 "fmt"
14 "io"
15 "os"
16 "runtime"
17 "sync"
18 "testing"
19 "time"
20 )
21
22 const (
23 newton = "../testdata/Isaac.Newton-Opticks.txt"
24 newtonLen = 567198
25 newtonSHA256 = "d4a9ac22462b35e7821a4f2706c211093da678620a8f9997989ee7cf8d507bbd"
26 )
27
28 func TestSendfile(t *testing.T) {
29 ln := newLocalListener(t, "tcp")
30 defer ln.Close()
31
32 errc := make(chan error, 1)
33 go func(ln Listener) {
34
35 conn, err := ln.Accept()
36 if err != nil {
37 errc <- err
38 close(errc)
39 return
40 }
41
42 go func() {
43 defer close(errc)
44 defer conn.Close()
45
46 f, err := os.Open(newton)
47 if err != nil {
48 errc <- err
49 return
50 }
51 defer f.Close()
52
53
54
55 sbytes, err := io.Copy(conn, f)
56 if err != nil {
57 errc <- err
58 return
59 }
60
61 if sbytes != newtonLen {
62 errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, newtonLen)
63 return
64 }
65 }()
66 }(ln)
67
68
69
70 c, err := Dial("tcp", ln.Addr().String())
71 if err != nil {
72 t.Fatal(err)
73 }
74 defer c.Close()
75
76 h := sha256.New()
77 rbytes, err := io.Copy(h, c)
78 if err != nil {
79 t.Error(err)
80 }
81
82 if rbytes != newtonLen {
83 t.Errorf("received %d bytes; expected %d", rbytes, newtonLen)
84 }
85
86 if res := hex.EncodeToString(h.Sum(nil)); res != newtonSHA256 {
87 t.Error("retrieved data hash did not match")
88 }
89
90 for err := range errc {
91 t.Error(err)
92 }
93 }
94
95 func TestSendfileParts(t *testing.T) {
96 ln := newLocalListener(t, "tcp")
97 defer ln.Close()
98
99 errc := make(chan error, 1)
100 go func(ln Listener) {
101
102 conn, err := ln.Accept()
103 if err != nil {
104 errc <- err
105 close(errc)
106 return
107 }
108
109 go func() {
110 defer close(errc)
111 defer conn.Close()
112
113 f, err := os.Open(newton)
114 if err != nil {
115 errc <- err
116 return
117 }
118 defer f.Close()
119
120 for i := 0; i < 3; i++ {
121
122
123 _, err = io.CopyN(conn, f, 3)
124 if err != nil {
125 errc <- err
126 return
127 }
128 }
129 }()
130 }(ln)
131
132 c, err := Dial("tcp", ln.Addr().String())
133 if err != nil {
134 t.Fatal(err)
135 }
136 defer c.Close()
137
138 buf := new(bytes.Buffer)
139 buf.ReadFrom(c)
140
141 if want, have := "Produced ", buf.String(); have != want {
142 t.Errorf("unexpected server reply %q, want %q", have, want)
143 }
144
145 for err := range errc {
146 t.Error(err)
147 }
148 }
149
150 func TestSendfileSeeked(t *testing.T) {
151 ln := newLocalListener(t, "tcp")
152 defer ln.Close()
153
154 const seekTo = 65 << 10
155 const sendSize = 10 << 10
156
157 errc := make(chan error, 1)
158 go func(ln Listener) {
159
160 conn, err := ln.Accept()
161 if err != nil {
162 errc <- err
163 close(errc)
164 return
165 }
166
167 go func() {
168 defer close(errc)
169 defer conn.Close()
170
171 f, err := os.Open(newton)
172 if err != nil {
173 errc <- err
174 return
175 }
176 defer f.Close()
177 if _, err := f.Seek(seekTo, io.SeekStart); err != nil {
178 errc <- err
179 return
180 }
181
182 _, err = io.CopyN(conn, f, sendSize)
183 if err != nil {
184 errc <- err
185 return
186 }
187 }()
188 }(ln)
189
190 c, err := Dial("tcp", ln.Addr().String())
191 if err != nil {
192 t.Fatal(err)
193 }
194 defer c.Close()
195
196 buf := new(bytes.Buffer)
197 buf.ReadFrom(c)
198
199 if buf.Len() != sendSize {
200 t.Errorf("Got %d bytes; want %d", buf.Len(), sendSize)
201 }
202
203 for err := range errc {
204 t.Error(err)
205 }
206 }
207
208
209 func TestSendfilePipe(t *testing.T) {
210 switch runtime.GOOS {
211 case "plan9", "windows", "js", "wasip1":
212
213 t.Skipf("skipping on %s", runtime.GOOS)
214 }
215
216 t.Parallel()
217
218 ln := newLocalListener(t, "tcp")
219 defer ln.Close()
220
221 r, w, err := os.Pipe()
222 if err != nil {
223 t.Fatal(err)
224 }
225 defer w.Close()
226 defer r.Close()
227
228 copied := make(chan bool)
229
230 var wg sync.WaitGroup
231 wg.Add(1)
232 go func() {
233
234
235 defer wg.Done()
236 conn, err := ln.Accept()
237 if err != nil {
238 t.Error(err)
239 return
240 }
241 defer conn.Close()
242 _, err = io.CopyN(conn, r, 1)
243 if err != nil {
244 t.Error(err)
245 return
246 }
247
248 close(copied)
249 }()
250
251 wg.Add(1)
252 go func() {
253
254 defer wg.Done()
255 _, err := w.Write([]byte{'a'})
256 if err != nil {
257 t.Error(err)
258 }
259 }()
260
261 wg.Add(1)
262 go func() {
263
264
265 defer wg.Done()
266 conn, err := Dial("tcp", ln.Addr().String())
267 if err != nil {
268 t.Error(err)
269 return
270 }
271 defer conn.Close()
272 io.Copy(io.Discard, conn)
273 }()
274
275
276
277 <-copied
278
279
280 if err := r.SetDeadline(time.Now().Add(time.Microsecond)); err != nil {
281 t.Fatal(err)
282 }
283
284 wg.Add(1)
285 go func() {
286
287
288 defer wg.Done()
289 time.Sleep(50 * time.Millisecond)
290 w.Write([]byte{'b'})
291 }()
292
293
294
295 _, err = r.Read(make([]byte, 1))
296 if err == nil {
297 t.Error("Read did not time out")
298 } else if !os.IsTimeout(err) {
299 t.Errorf("got error %v, expected a time out", err)
300 }
301
302 wg.Wait()
303 }
304
305
306 func TestSendfileOnWriteTimeoutExceeded(t *testing.T) {
307 ln := newLocalListener(t, "tcp")
308 defer ln.Close()
309
310 errc := make(chan error, 1)
311 go func(ln Listener) (retErr error) {
312 defer func() {
313 errc <- retErr
314 close(errc)
315 }()
316
317 conn, err := ln.Accept()
318 if err != nil {
319 return err
320 }
321 defer conn.Close()
322
323
324
325 if err := conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)); err != nil {
326 return err
327 }
328
329 f, err := os.Open(newton)
330 if err != nil {
331 return err
332 }
333 defer f.Close()
334
335 _, err = io.Copy(conn, f)
336 if errors.Is(err, os.ErrDeadlineExceeded) {
337 return nil
338 }
339
340 if err == nil {
341 err = fmt.Errorf("expected ErrDeadlineExceeded, but got nil")
342 }
343 return err
344 }(ln)
345
346 conn, err := Dial("tcp", ln.Addr().String())
347 if err != nil {
348 t.Fatal(err)
349 }
350 defer conn.Close()
351
352 n, err := io.Copy(io.Discard, conn)
353 if err != nil {
354 t.Fatalf("expected nil error, but got %v", err)
355 }
356 if n != 0 {
357 t.Fatalf("expected receive zero, but got %d byte(s)", n)
358 }
359
360 if err := <-errc; err != nil {
361 t.Fatal(err)
362 }
363 }
364
365 func BenchmarkSendfileZeroBytes(b *testing.B) {
366 var (
367 wg sync.WaitGroup
368 ctx, cancel = context.WithCancel(context.Background())
369 )
370
371 defer wg.Wait()
372
373 ln := newLocalListener(b, "tcp")
374 defer ln.Close()
375
376 tempFile, err := os.CreateTemp(b.TempDir(), "test.txt")
377 if err != nil {
378 b.Fatalf("failed to create temp file: %v", err)
379 }
380 defer tempFile.Close()
381
382 fileName := tempFile.Name()
383
384 dataSize := b.N
385 wg.Add(1)
386 go func(f *os.File) {
387 defer wg.Done()
388
389 for i := 0; i < dataSize; i++ {
390 if _, err := f.Write([]byte{1}); err != nil {
391 b.Errorf("failed to write: %v", err)
392 return
393 }
394 if i%1000 == 0 {
395 f.Sync()
396 }
397 }
398 }(tempFile)
399
400 b.ResetTimer()
401 b.ReportAllocs()
402
403 wg.Add(1)
404 go func(ln Listener, fileName string) {
405 defer wg.Done()
406
407 conn, err := ln.Accept()
408 if err != nil {
409 b.Errorf("failed to accept: %v", err)
410 return
411 }
412 defer conn.Close()
413
414 f, err := os.OpenFile(fileName, os.O_RDONLY, 0660)
415 if err != nil {
416 b.Errorf("failed to open file: %v", err)
417 return
418 }
419 defer f.Close()
420
421 for {
422 if ctx.Err() != nil {
423 return
424 }
425
426 if _, err := io.Copy(conn, f); err != nil {
427 b.Errorf("failed to copy: %v", err)
428 return
429 }
430 }
431 }(ln, fileName)
432
433 conn, err := Dial("tcp", ln.Addr().String())
434 if err != nil {
435 b.Fatalf("failed to dial: %v", err)
436 }
437 defer conn.Close()
438
439 n, err := io.CopyN(io.Discard, conn, int64(dataSize))
440 if err != nil {
441 b.Fatalf("failed to copy: %v", err)
442 }
443 if n != int64(dataSize) {
444 b.Fatalf("expected %d copied bytes, but got %d", dataSize, n)
445 }
446
447 cancel()
448 }
449
View as plain text