| // Copyright 2016 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build !js |
| |
| package net |
| |
| import ( |
| "bytes" |
| "crypto/sha256" |
| "encoding/hex" |
| "fmt" |
| "io" |
| "os" |
| "testing" |
| ) |
| |
| const ( |
| newton = "../testdata/Isaac.Newton-Opticks.txt" |
| newtonLen = 567198 |
| newtonSHA256 = "d4a9ac22462b35e7821a4f2706c211093da678620a8f9997989ee7cf8d507bbd" |
| ) |
| |
| func TestSendfile(t *testing.T) { |
| ln, err := newLocalListener("tcp") |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer ln.Close() |
| |
| errc := make(chan error, 1) |
| go func(ln Listener) { |
| // Wait for a connection. |
| conn, err := ln.Accept() |
| if err != nil { |
| errc <- err |
| close(errc) |
| return |
| } |
| |
| go func() { |
| defer close(errc) |
| defer conn.Close() |
| |
| f, err := os.Open(newton) |
| if err != nil { |
| errc <- err |
| return |
| } |
| defer f.Close() |
| |
| // Return file data using io.Copy, which should use |
| // sendFile if available. |
| sbytes, err := io.Copy(conn, f) |
| if err != nil { |
| errc <- err |
| return |
| } |
| |
| if sbytes != newtonLen { |
| errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, newtonLen) |
| return |
| } |
| }() |
| }(ln) |
| |
| // Connect to listener to retrieve file and verify digest matches |
| // expected. |
| c, err := Dial("tcp", ln.Addr().String()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer c.Close() |
| |
| h := sha256.New() |
| rbytes, err := io.Copy(h, c) |
| if err != nil { |
| t.Error(err) |
| } |
| |
| if rbytes != newtonLen { |
| t.Errorf("received %d bytes; expected %d", rbytes, newtonLen) |
| } |
| |
| if res := hex.EncodeToString(h.Sum(nil)); res != newtonSHA256 { |
| t.Error("retrieved data hash did not match") |
| } |
| |
| for err := range errc { |
| t.Error(err) |
| } |
| } |
| |
| func TestSendfileParts(t *testing.T) { |
| ln, err := newLocalListener("tcp") |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer ln.Close() |
| |
| errc := make(chan error, 1) |
| go func(ln Listener) { |
| // Wait for a connection. |
| conn, err := ln.Accept() |
| if err != nil { |
| errc <- err |
| close(errc) |
| return |
| } |
| |
| go func() { |
| defer close(errc) |
| defer conn.Close() |
| |
| f, err := os.Open(newton) |
| if err != nil { |
| errc <- err |
| return |
| } |
| defer f.Close() |
| |
| for i := 0; i < 3; i++ { |
| // Return file data using io.CopyN, which should use |
| // sendFile if available. |
| _, err = io.CopyN(conn, f, 3) |
| if err != nil { |
| errc <- err |
| return |
| } |
| } |
| }() |
| }(ln) |
| |
| c, err := Dial("tcp", ln.Addr().String()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer c.Close() |
| |
| buf := new(bytes.Buffer) |
| buf.ReadFrom(c) |
| |
| if want, have := "Produced ", buf.String(); have != want { |
| t.Errorf("unexpected server reply %q, want %q", have, want) |
| } |
| |
| for err := range errc { |
| t.Error(err) |
| } |
| } |
| |
| func TestSendfileSeeked(t *testing.T) { |
| ln, err := newLocalListener("tcp") |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer ln.Close() |
| |
| const seekTo = 65 << 10 |
| const sendSize = 10 << 10 |
| |
| errc := make(chan error, 1) |
| go func(ln Listener) { |
| // Wait for a connection. |
| conn, err := ln.Accept() |
| if err != nil { |
| errc <- err |
| close(errc) |
| return |
| } |
| |
| go func() { |
| defer close(errc) |
| defer conn.Close() |
| |
| f, err := os.Open(newton) |
| if err != nil { |
| errc <- err |
| return |
| } |
| defer f.Close() |
| if _, err := f.Seek(seekTo, os.SEEK_SET); err != nil { |
| errc <- err |
| return |
| } |
| |
| _, err = io.CopyN(conn, f, sendSize) |
| if err != nil { |
| errc <- err |
| return |
| } |
| }() |
| }(ln) |
| |
| c, err := Dial("tcp", ln.Addr().String()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| defer c.Close() |
| |
| buf := new(bytes.Buffer) |
| buf.ReadFrom(c) |
| |
| if buf.Len() != sendSize { |
| t.Errorf("Got %d bytes; want %d", buf.Len(), sendSize) |
| } |
| |
| for err := range errc { |
| t.Error(err) |
| } |
| } |