summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/templates/tplcontext_test.go
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-06-18 11:13:12 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-06-18 11:13:12 -0600
commit6706c9225a8dcb976785bdf2c35eb151d54ac18c (patch)
tree1e278a1261e826d0bda3c924bd179aabd0af2e92 /modules/caddyhttp/templates/tplcontext_test.go
parent5137859e47678aae81e178ca7d164f9e2b4e3121 (diff)
Implement templates handler; various minor cleanups and bug fixes
Diffstat (limited to 'modules/caddyhttp/templates/tplcontext_test.go')
-rw-r--r--modules/caddyhttp/templates/tplcontext_test.go420
1 files changed, 420 insertions, 0 deletions
diff --git a/modules/caddyhttp/templates/tplcontext_test.go b/modules/caddyhttp/templates/tplcontext_test.go
new file mode 100644
index 0000000..af4ad4e
--- /dev/null
+++ b/modules/caddyhttp/templates/tplcontext_test.go
@@ -0,0 +1,420 @@
+// Copyright 2015 Light Code Labs, LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package templates
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestMarkdown(t *testing.T) {
+ context := getContextOrFail(t)
+
+ for i, test := range []struct {
+ body string
+ expect string
+ }{
+ {
+ body: "- str1\n- str2\n",
+ expect: "<ul>\n<li>str1</li>\n<li>str2</li>\n</ul>\n",
+ },
+ } {
+ result := context.Markdown(test.body)
+ if result != test.expect {
+ t.Errorf("Test %d: expected '%s' but got '%s'", i, test.expect, result)
+ }
+ }
+}
+
+func TestCookie(t *testing.T) {
+ for i, test := range []struct {
+ cookie *http.Cookie
+ cookieName string
+ expect string
+ }{
+ {
+ // happy path
+ cookie: &http.Cookie{Name: "cookieName", Value: "cookieValue"},
+ cookieName: "cookieName",
+ expect: "cookieValue",
+ },
+ {
+ // try to get a non-existing cookie
+ cookie: &http.Cookie{Name: "cookieName", Value: "cookieValue"},
+ cookieName: "notExisting",
+ expect: "",
+ },
+ {
+ // partial name match
+ cookie: &http.Cookie{Name: "cookie", Value: "cookieValue"},
+ cookieName: "cook",
+ expect: "",
+ },
+ {
+ // cookie with optional fields
+ cookie: &http.Cookie{Name: "cookie", Value: "cookieValue", Path: "/path", Domain: "https://localhost", Expires: (time.Now().Add(10 * time.Minute)), MaxAge: 120},
+ cookieName: "cookie",
+ expect: "cookieValue",
+ },
+ } {
+ context := getContextOrFail(t)
+ context.Req.AddCookie(test.cookie)
+ actual := context.Cookie(test.cookieName)
+ if actual != test.expect {
+ t.Errorf("Test %d: Expected cookie value '%s' but got '%s' for cookie with name '%s'",
+ i, test.expect, actual, test.cookieName)
+ }
+ }
+}
+
+func TestCookieMultipleCookies(t *testing.T) {
+ context := getContextOrFail(t)
+
+ cookieNameBase, cookieValueBase := "cookieName", "cookieValue"
+
+ for i := 0; i < 10; i++ {
+ context.Req.AddCookie(&http.Cookie{
+ Name: fmt.Sprintf("%s%d", cookieNameBase, i),
+ Value: fmt.Sprintf("%s%d", cookieValueBase, i),
+ })
+ }
+
+ for i := 0; i < 10; i++ {
+ expectedCookieVal := fmt.Sprintf("%s%d", cookieValueBase, i)
+ actualCookieVal := context.Cookie(fmt.Sprintf("%s%d", cookieNameBase, i))
+ if actualCookieVal != expectedCookieVal {
+ t.Errorf("Expected cookie value %s, found %s", expectedCookieVal, actualCookieVal)
+ }
+ }
+}
+
+func TestEnv(t *testing.T) {
+ context := getContextOrFail(t)
+
+ name := "ENV_TEST_NAME"
+ testValue := "TEST_VALUE"
+ os.Setenv(name, testValue)
+
+ notExisting := "ENV_TEST_NOT_EXISTING"
+ os.Unsetenv(notExisting)
+
+ invalidName := "ENV_TEST_INVALID_NAME"
+ os.Setenv("="+invalidName, testValue)
+
+ env := context.Env()
+ if value := env[name]; value != testValue {
+ t.Errorf("Expected env-variable %s value '%s', found '%s'",
+ name, testValue, value)
+ }
+
+ if value, ok := env[notExisting]; ok {
+ t.Errorf("Expected empty env-variable %s, found '%s'",
+ notExisting, value)
+ }
+
+ for k, v := range env {
+ if strings.Contains(k, invalidName) {
+ t.Errorf("Expected invalid name not to be included in Env %s, found in key '%s'", invalidName, k)
+ }
+ if strings.Contains(v, invalidName) {
+ t.Errorf("Expected invalid name not be be included in Env %s, found in value '%s'", invalidName, v)
+ }
+ }
+
+ os.Unsetenv("=" + invalidName)
+}
+
+func TestIP(t *testing.T) {
+ context := getContextOrFail(t)
+ for i, test := range []struct {
+ inputRemoteAddr string
+ expect string
+ }{
+ {"1.1.1.1:1111", "1.1.1.1"},
+ {"1.1.1.1", "1.1.1.1"},
+ {"[::1]:11", "::1"},
+ {"[2001:db8:a0b:12f0::1]", "[2001:db8:a0b:12f0::1]"},
+ {`[fe80:1::3%eth0]:44`, `fe80:1::3%eth0`},
+ } {
+ context.Req.RemoteAddr = test.inputRemoteAddr
+ if actual := context.IP(); actual != test.expect {
+ t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
+ }
+ }
+}
+
+func TestTruncate(t *testing.T) {
+ context := getContextOrFail(t)
+
+ for i, test := range []struct {
+ input string
+ length int
+ expect string
+ }{
+ {
+ input: "string",
+ length: 1,
+ expect: "s",
+ },
+ {
+ input: "string",
+ length: 6,
+ expect: "string",
+ },
+ {
+ input: "string",
+ length: 10,
+ expect: "string",
+ },
+ {
+ input: "string",
+ length: 0,
+ expect: "",
+ },
+ {
+ input: "string",
+ length: -5,
+ expect: "tring",
+ },
+ {
+ input: "string",
+ length: -6,
+ expect: "string",
+ },
+ {
+ input: "string",
+ length: -7,
+ expect: "string",
+ },
+ } {
+ actual := context.Truncate(test.input, test.length)
+ if actual != test.expect {
+ t.Errorf("Test %d: Expected '%s' but got '%s'", i, test.expect, actual)
+ }
+ }
+}
+
+func TestStripHTML(t *testing.T) {
+ context := getContextOrFail(t)
+
+ for i, test := range []struct {
+ input string
+ expect string
+ }{
+ {
+ // no tags
+ input: `h1`,
+ expect: `h1`,
+ },
+ {
+ // happy path
+ input: `<h1>h1</h1>`,
+ expect: `h1`,
+ },
+ {
+ // tag in quotes
+ input: `<h1">">h1</h1>`,
+ expect: `h1`,
+ },
+ {
+ // multiple tags
+ input: `<h1><b>h1</b></h1>`,
+ expect: `h1`,
+ },
+ {
+ // tags not closed
+ input: `<h1`,
+ expect: `<h1`,
+ },
+ {
+ // false start
+ input: `<h1<b>hi`,
+ expect: `<h1hi`,
+ },
+ } {
+ actual := context.StripHTML(test.input)
+ if actual != test.expect {
+ t.Errorf("Test %d: Expected %s, found %s. Input was StripHTML(%s)", i, test.expect, actual, test.input)
+ }
+ }
+}
+
+func TestStripExt(t *testing.T) {
+ context := getContextOrFail(t)
+ tests := []struct {
+ input string
+ expect string
+ }{
+ {
+ input: "",
+ expect: "",
+ },
+ {
+ input: "file.ext",
+ expect: "file",
+ },
+ {
+ input: "file",
+ expect: "file",
+ },
+ {
+ input: "/file",
+ expect: "/file",
+ },
+ {
+ input: "/file.ext",
+ expect: "/file",
+ },
+ {
+ input: "/dir.ext/",
+ expect: "/dir.ext/",
+ },
+ {
+ input: "/dir.ext/file.ext",
+ expect: "/dir.ext/file",
+ },
+ }
+
+ for i, test := range tests {
+ actual := context.StripExt(test.input)
+ if actual != test.expect {
+ t.Errorf("Test %d: Expected %s but got %s", i, test.expect, actual)
+ }
+ }
+}
+
+func TestFileListing(t *testing.T) {
+ for i, test := range []struct {
+ fileNames []string
+ inputBase string
+ shouldErr bool
+ verifyErr func(error) bool
+ }{
+ {
+ // directory and files exist
+ fileNames: []string{"file1", "file2"},
+ shouldErr: false,
+ },
+ {
+ // directory exists, no files
+ fileNames: []string{},
+ shouldErr: false,
+ },
+ {
+ // file or directory does not exist
+ fileNames: nil,
+ inputBase: "doesNotExist",
+ shouldErr: true,
+ verifyErr: os.IsNotExist,
+ },
+ {
+ // directory and files exist, but path to a file
+ fileNames: []string{"file1", "file2"},
+ inputBase: "file1",
+ shouldErr: true,
+ verifyErr: func(err error) bool {
+ return strings.HasSuffix(err.Error(), "is not a directory")
+ },
+ },
+ {
+ // try to escape Context Root
+ fileNames: nil,
+ inputBase: filepath.Join("..", "..", "..", "..", "..", "etc"),
+ shouldErr: true,
+ verifyErr: os.IsNotExist,
+ },
+ } {
+ context := getContextOrFail(t)
+ var dirPath string
+ var err error
+
+ // create files for test case
+ if test.fileNames != nil {
+ dirPath, err = ioutil.TempDir(fmt.Sprintf("%s", context.Root), "caddy_ctxtest")
+ if err != nil {
+ t.Fatalf("Test %d: Expected no error creating directory, got: '%s'", i, err.Error())
+ }
+ for _, name := range test.fileNames {
+ absFilePath := filepath.Join(dirPath, name)
+ if err = ioutil.WriteFile(absFilePath, []byte(""), os.ModePerm); err != nil {
+ os.RemoveAll(dirPath)
+ t.Fatalf("Test %d: Expected no error creating file, got: '%s'", i, err.Error())
+ }
+ }
+ }
+
+ // perform test
+ input := filepath.ToSlash(filepath.Join(filepath.Base(dirPath), test.inputBase))
+ actual, err := context.ListFiles(input)
+ if err != nil {
+ if !test.shouldErr {
+ t.Errorf("Test %d: Expected no error, got: '%s'", i, err)
+ } else if !test.verifyErr(err) {
+ t.Errorf("Test %d: Could not verify error content, got: '%s'", i, err)
+ }
+ } else if test.shouldErr {
+ t.Errorf("Test %d: Expected error but had none", i)
+ } else {
+ numFiles := len(test.fileNames)
+ // reflect.DeepEqual does not consider two empty slices to be equal
+ if numFiles == 0 && len(actual) != 0 {
+ t.Errorf("Test %d: Expected files %v, got: %v",
+ i, test.fileNames, actual)
+ } else {
+ sort.Strings(actual)
+ if numFiles > 0 && !reflect.DeepEqual(test.fileNames, actual) {
+ t.Errorf("Test %d: Expected files %v, got: %v",
+ i, test.fileNames, actual)
+ }
+ }
+ }
+
+ if dirPath != "" {
+ if err := os.RemoveAll(dirPath); err != nil && !os.IsNotExist(err) {
+ t.Fatalf("Test %d: Expected no error removing temporary test directory, got: %v", i, err)
+ }
+ }
+ }
+}
+
+func getContextOrFail(t *testing.T) templateContext {
+ context, err := initTestContext()
+ if err != nil {
+ t.Fatalf("failed to prepare test context: %v", err)
+ }
+ return context
+}
+
+func initTestContext() (templateContext, error) {
+ body := bytes.NewBufferString("request body")
+ request, err := http.NewRequest("GET", "https://example.com/foo/bar", body)
+ if err != nil {
+ return templateContext{}, err
+ }
+ return templateContext{
+ Root: http.Dir(os.TempDir()),
+ Req: request,
+ RespHeader: tplWrappedHeader{make(http.Header)},
+ }, nil
+}