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.
24 newton = "../testdata/Isaac.Newton-Opticks.txt"
26 newtonSHA256 = "d4a9ac22462b35e7821a4f2706c211093da678620a8f9997989ee7cf8d507bbd"
29 func TestSendfile(t *testing.T) {
30 ln, err := newLocalListener("tcp")
36 errc := make(chan error, 1)
37 go func(ln Listener) {
38 // Wait for a connection.
39 conn, err := ln.Accept()
50 f, err := os.Open(newton)
57 // Return file data using io.Copy, which should use
58 // sendFile if available.
59 sbytes, err := io.Copy(conn, f)
65 if sbytes != newtonLen {
66 errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, newtonLen)
72 // Connect to listener to retrieve file and verify digest matches
74 c, err := Dial("tcp", ln.Addr().String())
81 rbytes, err := io.Copy(h, c)
86 if rbytes != newtonLen {
87 t.Errorf("received %d bytes; expected %d", rbytes, newtonLen)
90 if res := hex.EncodeToString(h.Sum(nil)); res != newtonSHA256 {
91 t.Error("retrieved data hash did not match")
94 for err := range errc {
99 func TestSendfileParts(t *testing.T) {
100 ln, err := newLocalListener("tcp")
106 errc := make(chan error, 1)
107 go func(ln Listener) {
108 // Wait for a connection.
109 conn, err := ln.Accept()
120 f, err := os.Open(newton)
127 for i := 0; i < 3; i++ {
128 // Return file data using io.CopyN, which should use
129 // sendFile if available.
130 _, err = io.CopyN(conn, f, 3)
139 c, err := Dial("tcp", ln.Addr().String())
145 buf := new(bytes.Buffer)
148 if want, have := "Produced ", buf.String(); have != want {
149 t.Errorf("unexpected server reply %q, want %q", have, want)
152 for err := range errc {
157 func TestSendfileSeeked(t *testing.T) {
158 ln, err := newLocalListener("tcp")
164 const seekTo = 65 << 10
165 const sendSize = 10 << 10
167 errc := make(chan error, 1)
168 go func(ln Listener) {
169 // Wait for a connection.
170 conn, err := ln.Accept()
181 f, err := os.Open(newton)
187 if _, err := f.Seek(seekTo, os.SEEK_SET); err != nil {
192 _, err = io.CopyN(conn, f, sendSize)
200 c, err := Dial("tcp", ln.Addr().String())
206 buf := new(bytes.Buffer)
209 if buf.Len() != sendSize {
210 t.Errorf("Got %d bytes; want %d", buf.Len(), sendSize)
213 for err := range errc {
218 // Test that sendfile doesn't put a pipe into blocking mode.
219 func TestSendfilePipe(t *testing.T) {
220 switch runtime.GOOS {
221 case "nacl", "plan9", "windows":
222 // These systems don't support deadlines on pipes.
223 t.Skipf("skipping on %s", runtime.GOOS)
228 ln, err := newLocalListener("tcp")
234 r, w, err := os.Pipe()
241 copied := make(chan bool)
243 var wg sync.WaitGroup
246 // Accept a connection and copy 1 byte from the read end of
247 // the pipe to the connection. This will call into sendfile.
249 conn, err := ln.Accept()
255 _, err = io.CopyN(conn, r, 1)
260 // Signal the main goroutine that we've copied the byte.
266 // Write 1 byte to the write end of the pipe.
268 _, err := w.Write([]byte{'a'})
276 // Connect to the server started two goroutines up and
277 // discard any data that it writes.
279 conn, err := Dial("tcp", ln.Addr().String())
285 io.Copy(ioutil.Discard, conn)
288 // Wait for the byte to be copied, meaning that sendfile has
289 // been called on the pipe.
292 // Set a very short deadline on the read end of the pipe.
293 if err := r.SetDeadline(time.Now().Add(time.Microsecond)); err != nil {
299 // Wait for much longer than the deadline and write a byte
302 time.Sleep(50 * time.Millisecond)
306 // If this read does not time out, the pipe was incorrectly
307 // put into blocking mode.
308 _, err = r.Read(make([]byte, 1))
310 t.Error("Read did not time out")
311 } else if !os.IsTimeout(err) {
312 t.Errorf("got error %v, expected a time out", err)