caddy/caddyhttp/templates/templates_test.go
Matt Holt 4b1b329edb templates: Execute template loaded by later middlewares (#1649)
* templates: Execute template loaded by later middlewares

This is the beginning of an attempt to make the staticfiles file server
the only middleware that hits the disk and loads content. This may have
unknown implications. But the goal is to reduce duplication without
sacrificing performance. (We now call ServeContent here.)

This change loses about 15% of the req/sec of the old way of doing it,
but this way is arguably more correct since the file server is good at
serving static files; duplicating that logic in every middleware that
needs to hit the disk is not practical.

* httpserver: Introduce ResponseRecorder as per Tw's suggestions

It implements io.ReaderFrom and has some allocation-reducing
optimizations baked into it

* templates: Increase execution speed by ~10-15% after perf regression

By using httpserver.ResponseBuffer, we can reduce allocations and still
get what we want. It's a little tricky but it works so far.
2017-08-24 07:13:53 -06:00

148 lines
4.1 KiB
Go

package templates
import (
"bytes"
"context"
"net/http"
"net/http/httptest"
"sync"
"testing"
"github.com/mholt/caddy/caddyhttp/httpserver"
"github.com/mholt/caddy/caddyhttp/staticfiles"
)
func TestTemplates(t *testing.T) {
siteRoot := "./testdata"
tmpl := Templates{
Next: staticfiles.FileServer{Root: http.Dir(siteRoot)},
Rules: []Rule{
{
Extensions: []string{".html"},
IndexFiles: []string{"index.html"},
Path: "/photos",
},
{
Extensions: []string{".html", ".htm"},
IndexFiles: []string{"index.html", "index.htm"},
Path: "/images",
Delims: [2]string{"{%", "%}"},
},
},
Root: siteRoot,
FileSys: http.Dir(siteRoot),
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
}
tmplroot := Templates{
Next: staticfiles.FileServer{Root: http.Dir(siteRoot)},
Rules: []Rule{
{
Extensions: []string{".html"},
IndexFiles: []string{"index.html"},
Path: "/",
},
},
Root: siteRoot,
FileSys: http.Dir(siteRoot),
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
}
// Test tmpl on /photos/test.html
req, err := http.NewRequest("GET", "/photos/test.html", nil)
if err != nil {
t.Fatalf("Test: Could not create HTTP request: %v", err)
}
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
rec := httptest.NewRecorder()
tmpl.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
}
respBody := rec.Body.String()
expectedBody := `<!DOCTYPE html><html><head><title>test page</title></head><body><h1>Header title</h1>
</body></html>
`
if respBody != expectedBody {
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
}
// Test tmpl on /images/img.htm
req, err = http.NewRequest("GET", "/images/img.htm", nil)
if err != nil {
t.Fatalf("Could not create HTTP request: %v", err)
}
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
rec = httptest.NewRecorder()
tmpl.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
}
respBody = rec.Body.String()
expectedBody = `<!DOCTYPE html><html><head><title>img</title></head><body><h1>Header title</h1>
</body></html>
`
if respBody != expectedBody {
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
}
// Test tmpl on /images/img2.htm
req, err = http.NewRequest("GET", "/images/img2.htm", nil)
if err != nil {
t.Fatalf("Could not create HTTP request: %v", err)
}
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
rec = httptest.NewRecorder()
tmpl.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
}
respBody = rec.Body.String()
expectedBody = `<!DOCTYPE html><html><head><title>img</title></head><body>{{.Include "header.html"}}</body></html>
`
if respBody != expectedBody {
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
}
// Test tmplroot on /root.html
req, err = http.NewRequest("GET", "/root.html", nil)
if err != nil {
t.Fatalf("Could not create HTTP request: %v", err)
}
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
rec = httptest.NewRecorder()
// register custom function which is used in template
httpserver.TemplateFuncs["root"] = func() string { return "root" }
tmplroot.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
}
respBody = rec.Body.String()
expectedBody = `<!DOCTYPE html><html><head><title>root</title></head><body><h1>Header title</h1>
</body></html>
`
if respBody != expectedBody {
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
}
}