From b8df36182d7321201d3985a4b3d8ca1c0faf63d2 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 14 Feb 2012 09:34:52 +1100 Subject: [PATCH] net/http: add a Linux-only sendfile test I remembered that sendfile support was lacking a test. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/5652079 --- src/pkg/net/http/fs_test.go | 92 +++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/pkg/net/http/fs_test.go b/src/pkg/net/http/fs_test.go index 45059fd5f3..5878f60887 100644 --- a/src/pkg/net/http/fs_test.go +++ b/src/pkg/net/http/fs_test.go @@ -5,14 +5,20 @@ package http_test import ( + "bytes" "fmt" "io" "io/ioutil" + "net" . "net/http" "net/http/httptest" "net/url" "os" + "os/exec" "path/filepath" + "regexp" + "runtime" + "strconv" "strings" "testing" "time" @@ -359,6 +365,68 @@ func TestServeContent(t *testing.T) { } } +// verifies that sendfile is being used on Linux +func TestLinuxSendfile(t *testing.T) { + if runtime.GOOS != "linux" { + t.Logf("skipping; linux-only test") + return + } + _, err := exec.LookPath("strace") + if err != nil { + t.Logf("skipping; strace not found in path") + return + } + + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + lnf, err := ln.(*net.TCPListener).File() + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + child := exec.Command(os.Args[0], "-test.run=TestLinuxSendfileChild") + child.ExtraFiles = append(child.ExtraFiles, lnf) + child.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...) + + err = child.Start() + if err != nil { + t.Fatal(err) + } + + pid := child.Process.Pid + + var buf bytes.Buffer + strace := exec.Command("strace", "-f", "-p", strconv.Itoa(pid)) + strace.Stdout = &buf + strace.Stderr = &buf + err = strace.Start() + if err != nil { + t.Logf("skipping; failed to start strace: %v", err) + return + } + + _, err = Get(fmt.Sprintf("http://%s/", ln.Addr())) + if err != nil { + t.Errorf("http client error: %v", err) + return + } + + // Force child to exit cleanly. + Get(fmt.Sprintf("http://%s/quit", ln.Addr())) + child.Wait() + strace.Wait() + + rx := regexp.MustCompile(`sendfile\(\d+,\s*\d+,\s*NULL,\s*\d+\)\s*=\s*\d+\s*\n`) + rxResume := regexp.MustCompile(`<\.\.\. sendfile resumed> \)\s*=\s*\d+\s*\n`) + out := buf.String() + if !rx.MatchString(out) && !rxResume.MatchString(out) { + t.Errorf("no sendfile system call found in:\n%s", out) + } +} + func getBody(t *testing.T, testName string, req Request) (*Response, []byte) { r, err := DefaultClient.Do(&req) if err != nil { @@ -371,6 +439,30 @@ func getBody(t *testing.T, testName string, req Request) (*Response, []byte) { return r, b } +// TestLinuxSendfileChild isn't a real test. It's used as a helper process +// for TestLinuxSendfile. +func TestLinuxSendfileChild(*testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + defer os.Exit(0) + fd3 := os.NewFile(3, "ephemeral-port-listener") + ln, err := net.FileListener(fd3) + if err != nil { + panic(err) + } + mux := NewServeMux() + mux.Handle("/", FileServer(Dir("testdata"))) + mux.HandleFunc("/quit", func(ResponseWriter, *Request) { + os.Exit(0) + }) + s := &Server{Handler: mux} + err = s.Serve(ln) + if err != nil { + panic(err) + } +} + func equal(a, b []byte) bool { if len(a) != len(b) { return false -- 2.50.0