1
0
mirror of https://github.com/golang/go synced 2024-11-25 08:07:57 -07:00

httptest: introduce TempServer, clean up tests

This also breaks fs_test into two parts
as the range tests test http's private httpRange
and I had to change the fs_test package from
"http" to "http_test" to use httptest which otherwise
has a cyclic depedency back on http.

Aside: we should start exposing the Range
stuff in the future.

R=rsc
CC=golang-dev
https://golang.org/cl/4261047
This commit is contained in:
Brad Fitzpatrick 2011-03-05 13:51:35 -08:00
parent 5f54c807f1
commit f88abdad0f
5 changed files with 120 additions and 93 deletions

View File

@ -2,89 +2,22 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package http package http_test
import ( import (
"fmt" "fmt"
. "http"
"http/httptest"
"io/ioutil" "io/ioutil"
"net"
"os" "os"
"sync"
"testing" "testing"
) )
var ParseRangeTests = []struct {
s string
length int64
r []httpRange
}{
{"", 0, nil},
{"foo", 0, nil},
{"bytes=", 0, nil},
{"bytes=5-4", 10, nil},
{"bytes=0-2,5-4", 10, nil},
{"bytes=0-9", 10, []httpRange{{0, 10}}},
{"bytes=0-", 10, []httpRange{{0, 10}}},
{"bytes=5-", 10, []httpRange{{5, 5}}},
{"bytes=0-20", 10, []httpRange{{0, 10}}},
{"bytes=15-,0-5", 10, nil},
{"bytes=-5", 10, []httpRange{{5, 5}}},
{"bytes=-15", 10, []httpRange{{0, 10}}},
{"bytes=0-499", 10000, []httpRange{{0, 500}}},
{"bytes=500-999", 10000, []httpRange{{500, 500}}},
{"bytes=-500", 10000, []httpRange{{9500, 500}}},
{"bytes=9500-", 10000, []httpRange{{9500, 500}}},
{"bytes=0-0,-1", 10000, []httpRange{{0, 1}, {9999, 1}}},
{"bytes=500-600,601-999", 10000, []httpRange{{500, 101}, {601, 399}}},
{"bytes=500-700,601-999", 10000, []httpRange{{500, 201}, {601, 399}}},
}
func TestParseRange(t *testing.T) {
for _, test := range ParseRangeTests {
r := test.r
ranges, err := parseRange(test.s, test.length)
if err != nil && r != nil {
t.Errorf("parseRange(%q) returned error %q", test.s, err)
}
if len(ranges) != len(r) {
t.Errorf("len(parseRange(%q)) = %d, want %d", test.s, len(ranges), len(r))
continue
}
for i := range r {
if ranges[i].start != r[i].start {
t.Errorf("parseRange(%q)[%d].start = %d, want %d", test.s, i, ranges[i].start, r[i].start)
}
if ranges[i].length != r[i].length {
t.Errorf("parseRange(%q)[%d].length = %d, want %d", test.s, i, ranges[i].length, r[i].length)
}
}
}
}
const ( const (
testFile = "testdata/file" testFile = "testdata/file"
testFileLength = 11 testFileLength = 11
) )
var (
serverOnce sync.Once
serverAddr string
)
func startServer(t *testing.T) {
serverOnce.Do(func() {
HandleFunc("/ServeFile", func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
})
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal("listen:", err)
}
serverAddr = l.Addr().String()
go Serve(l, nil)
})
}
var ServeFileRangeTests = []struct { var ServeFileRangeTests = []struct {
start, end int start, end int
r string r string
@ -99,7 +32,11 @@ var ServeFileRangeTests = []struct {
} }
func TestServeFile(t *testing.T) { func TestServeFile(t *testing.T) {
startServer(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
var err os.Error var err os.Error
file, err := ioutil.ReadFile(testFile) file, err := ioutil.ReadFile(testFile)
@ -110,7 +47,7 @@ func TestServeFile(t *testing.T) {
// set up the Request (re-used for all tests) // set up the Request (re-used for all tests)
var req Request var req Request
req.Header = make(Header) req.Header = make(Header)
if req.URL, err = ParseURL("http://" + serverAddr + "/ServeFile"); err != nil { if req.URL, err = ParseURL(ts.URL); err != nil {
t.Fatal("ParseURL:", err) t.Fatal("ParseURL:", err)
} }
req.Method = "GET" req.Method = "GET"
@ -149,7 +86,7 @@ func TestServeFile(t *testing.T) {
} }
func getBody(t *testing.T, req Request) (*Response, []byte) { func getBody(t *testing.T, req Request) (*Response, []byte) {
r, err := send(&req, DefaultTransport) r, err := DefaultClient.Do(&req)
if err != nil { if err != nil {
t.Fatal(req.URL.String(), "send:", err) t.Fatal(req.URL.String(), "send:", err)
} }

View File

@ -7,5 +7,6 @@ include ../../../Make.inc
TARG=http/httptest TARG=http/httptest
GOFILES=\ GOFILES=\
recorder.go\ recorder.go\
server.go\
include ../../../Make.pkg include ../../../Make.pkg

View File

@ -0,0 +1,42 @@
// Copyright 2011 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.
// Implementation of TempServer
package httptest
import (
"fmt"
"http"
"net"
)
// A Server is an HTTP server listening on a system-chosen port on the
// local loopback interface, for use in end-to-end HTTP tests.
type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener
}
// NewServer starts and returns a new Server.
// The caller should call Close when finished, to shut it down.
func NewServer(handler http.Handler) *Server {
ts := new(Server)
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
}
}
ts.Listener = l
ts.URL = "http://" + l.Addr().String()
server := &http.Server{Handler: handler}
go server.Serve(l)
return ts
}
// Close shuts down the temporary server.
func (s *Server) Close() {
s.Listener.Close()
}

View File

@ -0,0 +1,57 @@
// Copyright 2011 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.
package http
import (
"testing"
)
var ParseRangeTests = []struct {
s string
length int64
r []httpRange
}{
{"", 0, nil},
{"foo", 0, nil},
{"bytes=", 0, nil},
{"bytes=5-4", 10, nil},
{"bytes=0-2,5-4", 10, nil},
{"bytes=0-9", 10, []httpRange{{0, 10}}},
{"bytes=0-", 10, []httpRange{{0, 10}}},
{"bytes=5-", 10, []httpRange{{5, 5}}},
{"bytes=0-20", 10, []httpRange{{0, 10}}},
{"bytes=15-,0-5", 10, nil},
{"bytes=-5", 10, []httpRange{{5, 5}}},
{"bytes=-15", 10, []httpRange{{0, 10}}},
{"bytes=0-499", 10000, []httpRange{{0, 500}}},
{"bytes=500-999", 10000, []httpRange{{500, 500}}},
{"bytes=-500", 10000, []httpRange{{9500, 500}}},
{"bytes=9500-", 10000, []httpRange{{9500, 500}}},
{"bytes=0-0,-1", 10000, []httpRange{{0, 1}, {9999, 1}}},
{"bytes=500-600,601-999", 10000, []httpRange{{500, 101}, {601, 399}}},
{"bytes=500-700,601-999", 10000, []httpRange{{500, 201}, {601, 399}}},
}
func TestParseRange(t *testing.T) {
for _, test := range ParseRangeTests {
r := test.r
ranges, err := parseRange(test.s, test.length)
if err != nil && r != nil {
t.Errorf("parseRange(%q) returned error %q", test.s, err)
}
if len(ranges) != len(r) {
t.Errorf("len(parseRange(%q)) = %d, want %d", test.s, len(ranges), len(r))
continue
}
for i := range r {
if ranges[i].start != r[i].start {
t.Errorf("parseRange(%q)[%d].start = %d, want %d", test.s, i, ranges[i].start, r[i].start)
}
if ranges[i].length != r[i].length {
t.Errorf("parseRange(%q)[%d].length = %d, want %d", test.s, i, ranges[i].length, r[i].length)
}
}
}
}

View File

@ -171,13 +171,10 @@ func TestHostHandlers(t *testing.T) {
for _, h := range handlers { for _, h := range handlers {
Handle(h.pattern, stringHandler(h.msg)) Handle(h.pattern, stringHandler(h.msg))
} }
l, err := net.Listen("tcp", "127.0.0.1:0") // any port ts := httptest.NewServer(nil)
if err != nil { defer ts.Close()
t.Fatal(err)
} conn, err := net.Dial("tcp", "", ts.Listener.Addr().String())
defer l.Close()
go Serve(l, nil)
conn, err := net.Dial("tcp", "", l.Addr().String())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -296,13 +293,6 @@ func TestServerTimeouts(t *testing.T) {
// TestIdentityResponse verifies that a handler can unset // TestIdentityResponse verifies that a handler can unset
func TestIdentityResponse(t *testing.T) { func TestIdentityResponse(t *testing.T) {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("failed to listen on a port: %v", err)
}
defer l.Close()
urlBase := "http://" + l.Addr().String() + "/"
handler := HandlerFunc(func(rw ResponseWriter, req *Request) { handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
rw.SetHeader("Content-Length", "3") rw.SetHeader("Content-Length", "3")
rw.SetHeader("Transfer-Encoding", req.FormValue("te")) rw.SetHeader("Transfer-Encoding", req.FormValue("te"))
@ -320,15 +310,15 @@ func TestIdentityResponse(t *testing.T) {
} }
}) })
server := &Server{Handler: handler} ts := httptest.NewServer(handler)
go server.Serve(l) defer ts.Close()
// Note: this relies on the assumption (which is true) that // Note: this relies on the assumption (which is true) that
// Get sends HTTP/1.1 or greater requests. Otherwise the // Get sends HTTP/1.1 or greater requests. Otherwise the
// server wouldn't have the choice to send back chunked // server wouldn't have the choice to send back chunked
// responses. // responses.
for _, te := range []string{"", "identity"} { for _, te := range []string{"", "identity"} {
url := urlBase + "?te=" + te url := ts.URL + "/?te=" + te
res, _, err := Get(url) res, _, err := Get(url)
if err != nil { if err != nil {
t.Fatalf("error with Get of %s: %v", url, err) t.Fatalf("error with Get of %s: %v", url, err)
@ -346,15 +336,15 @@ func TestIdentityResponse(t *testing.T) {
} }
// Verify that ErrContentLength is returned // Verify that ErrContentLength is returned
url := urlBase + "?overwrite=1" url := ts.URL + "/?overwrite=1"
_, _, err = Get(url) _, _, err := Get(url)
if err != nil { if err != nil {
t.Fatalf("error with Get of %s: %v", url, err) t.Fatalf("error with Get of %s: %v", url, err)
} }
// Verify that the connection is closed when the declared Content-Length // Verify that the connection is closed when the declared Content-Length
// is larger than what the handler wrote. // is larger than what the handler wrote.
conn, err := net.Dial("tcp", "", l.Addr().String()) conn, err := net.Dial("tcp", "", ts.Listener.Addr().String())
if err != nil { if err != nil {
t.Fatalf("error dialing: %v", err) t.Fatalf("error dialing: %v", err)
} }