blob: a258d523dcd6e74babe25a14a152eadff2405f8c [file] [log] [blame]
// Copyright 2013 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 or at
// https://developers.google.com/open-source/licenses/bsd.
package httputil_test
import (
"crypto/sha1"
"encoding/hex"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strconv"
"testing"
"time"
"github.com/golang/gddo/httputil"
"github.com/google/go-cmp/cmp"
)
var (
testHash = computeTestHash()
testEtag = `"` + testHash + `"`
testContentLength = computeTestContentLength()
)
func mustParseURL(urlStr string) *url.URL {
u, err := url.Parse(urlStr)
if err != nil {
panic(err)
}
return u
}
func computeTestHash() string {
p, err := ioutil.ReadFile("static_test.go")
if err != nil {
panic(err)
}
w := sha1.New()
w.Write(p)
return hex.EncodeToString(w.Sum(nil))
}
func computeTestContentLength() string {
info, err := os.Stat("static_test.go")
if err != nil {
panic(err)
}
return strconv.FormatInt(info.Size(), 10)
}
var fileServerTests = []*struct {
name string // test name for log
ss *httputil.StaticServer
r *http.Request
header http.Header // expected response headers
status int // expected response status
empty bool // true if response body not expected.
}{
{
name: "get",
ss: &httputil.StaticServer{MaxAge: 3 * time.Second},
r: &http.Request{
URL: mustParseURL("/dir/static_test.go"),
Method: "GET",
},
status: http.StatusOK,
header: http.Header{
"Etag": {testEtag},
"Cache-Control": {"public, max-age=3"},
"Content-Length": {testContentLength},
"Content-Type": {"application/octet-stream"},
},
},
{
name: "get .",
ss: &httputil.StaticServer{Dir: ".", MaxAge: 3 * time.Second},
r: &http.Request{
URL: mustParseURL("/dir/static_test.go"),
Method: "GET",
},
status: http.StatusOK,
header: http.Header{
"Etag": {testEtag},
"Cache-Control": {"public, max-age=3"},
"Content-Length": {testContentLength},
"Content-Type": {"application/octet-stream"},
},
},
{
name: "get with ?v=",
ss: &httputil.StaticServer{MaxAge: 3 * time.Second},
r: &http.Request{
URL: mustParseURL("/dir/static_test.go?v=xxxxx"),
Method: "GET",
},
status: http.StatusOK,
header: http.Header{
"Etag": {testEtag},
"Cache-Control": {"public, max-age=31536000"},
"Content-Length": {testContentLength},
"Content-Type": {"application/octet-stream"},
},
},
{
name: "head",
ss: &httputil.StaticServer{MaxAge: 3 * time.Second},
r: &http.Request{
URL: mustParseURL("/dir/static_test.go"),
Method: "HEAD",
},
status: http.StatusOK,
header: http.Header{
"Etag": {testEtag},
"Cache-Control": {"public, max-age=3"},
"Content-Length": {testContentLength},
"Content-Type": {"application/octet-stream"},
},
empty: true,
},
{
name: "if-none-match",
ss: &httputil.StaticServer{MaxAge: 3 * time.Second},
r: &http.Request{
URL: mustParseURL("/dir/static_test.go"),
Method: "GET",
Header: http.Header{"If-None-Match": {testEtag}},
},
status: http.StatusNotModified,
header: http.Header{
"Cache-Control": {"public, max-age=3"},
"Etag": {testEtag},
},
empty: true,
},
}
func testStaticServer(t *testing.T, f func(*httputil.StaticServer) http.Handler) {
for _, tt := range fileServerTests {
w := httptest.NewRecorder()
h := f(tt.ss)
h.ServeHTTP(w, tt.r)
if w.Code != tt.status {
t.Errorf("%s, status=%d, want %d", tt.name, w.Code, tt.status)
}
if !cmp.Equal(w.HeaderMap, tt.header) {
t.Errorf("%s\n\theader=%v,\n\twant %v", tt.name, w.HeaderMap, tt.header)
}
empty := w.Body.Len() == 0
if empty != tt.empty {
t.Errorf("%s empty=%v, want %v", tt.name, empty, tt.empty)
}
}
}
func TestFileHandler(t *testing.T) {
testStaticServer(t, func(ss *httputil.StaticServer) http.Handler { return ss.FileHandler("static_test.go") })
}
func TestDirectoryHandler(t *testing.T) {
testStaticServer(t, func(ss *httputil.StaticServer) http.Handler { return ss.DirectoryHandler("/dir", ".") })
}
func TestFilesHandler(t *testing.T) {
testStaticServer(t, func(ss *httputil.StaticServer) http.Handler { return ss.FilesHandler("static_test.go") })
}