func nextFunc(shouldGzip bool) middleware.Handler { return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { if shouldGzip { if r.Header.Get("Accept-Encoding") != "" { return 0, fmt.Errorf("Accept-Encoding header not expected") } if w.Header().Get("Content-Encoding") != "gzip" { return 0, fmt.Errorf("Content-Encoding must be gzip, found %v", r.Header.Get("Content-Encoding")) } if _, ok := w.(gzipResponseWriter); !ok { return 0, fmt.Errorf("ResponseWriter should be gzipResponseWriter, found %T", w) } return 0, nil } if r.Header.Get("Accept-Encoding") == "" { return 0, fmt.Errorf("Accept-Encoding header expected") } if w.Header().Get("Content-Encoding") == "gzip" { return 0, fmt.Errorf("Content-Encoding must not be gzip, found gzip") } if _, ok := w.(gzipResponseWriter); ok { return 0, fmt.Errorf("ResponseWriter should not be gzipResponseWriter") } return 0, nil }) }
// GET handles the GET method on browse page func GET(w http.ResponseWriter, r *http.Request, c *config.Config) (int, error) { functions := template.FuncMap{ "CanBeEdited": utils.CanBeEdited, "Defined": utils.Defined, } tpl, err := utils.GetTemplate(r, functions, "browse") if err != nil { return http.StatusInternalServerError, err } b := browse.Browse{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 404, nil }), Root: c.Path, Configs: []browse.Config{ { PathScope: "/", Variables: c, Template: tpl, }, }, IgnoreIndexes: true, } return b.ServeHTTP(w, r) }
func TestExpVar(t *testing.T) { rw := ExpVar{ Next: middleware.HandlerFunc(contentHandler), Resource: "/d/v", } tests := []struct { from string result int }{ {"/d/v", 0}, {"/x/y", http.StatusOK}, } for i, test := range tests { req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request %v", i, err) } rec := httptest.NewRecorder() result, err := rw.ServeHTTP(rec, req) if err != nil { t.Fatalf("Test %d: Could not ServeHTTP %v", i, err) } if result != test.result { t.Errorf("Test %d: Expected Header '%d' but was '%d'", i, test.result, result) } } }
func TestBrowseTemplate(t *testing.T) { tmpl, err := template.ParseFiles("testdata/photos.tpl") if err != nil { t.Fatalf("An error occured while parsing the template: %v", err) } b := Browse{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }), Root: "./testdata", Configs: []Config{ { PathScope: "/photos", Template: tmpl, }, }, } req, err := http.NewRequest("GET", "/photos/", nil) if err != nil { t.Fatalf("Test: Could not create HTTP request: %v", err) } rec := httptest.NewRecorder() code, err := b.ServeHTTP(rec, req) if code != http.StatusOK { t.Fatalf("Wrong status, expected %d, got %d", http.StatusOK, code) } respBody := rec.Body.String() expectedBody := `<!DOCTYPE html> <html> <head> <title>Template</title> </head> <body> <h1>Header</h1> <h1>/photos/</h1> <a href="./test.html">test.html</a><br> <a href="./test2.html">test2.html</a><br> <a href="./test3.html">test3.html</a><br> </body> </html> ` if respBody != expectedBody { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } }
func genErrorHandler(status int, err error, body string) middleware.Handler { return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { if len(body) > 0 { w.Header().Set("Content-Length", strconv.Itoa(len(body))) fmt.Fprint(w, body) } return status, err }) }
func TestBasicAuth(t *testing.T) { rw := BasicAuth{ Next: middleware.HandlerFunc(contentHandler), Rules: []Rule{ {Username: "******", Password: PlainMatcher("ttest"), Resources: []string{"/testing"}}, }, } tests := []struct { from string result int cred string }{ {"/testing", http.StatusUnauthorized, "ttest:test"}, {"/testing", http.StatusOK, "test:ttest"}, {"/testing", http.StatusUnauthorized, ""}, } for i, test := range tests { req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request %v", i, err) } auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(test.cred)) req.Header.Set("Authorization", auth) rec := httptest.NewRecorder() result, err := rw.ServeHTTP(rec, req) if err != nil { t.Fatalf("Test %d: Could not ServeHTTP %v", i, err) } if result != test.result { t.Errorf("Test %d: Expected Header '%d' but was '%d'", i, test.result, result) } if result == http.StatusUnauthorized { headers := rec.Header() if val, ok := headers["Www-Authenticate"]; ok { if val[0] != "Basic" { t.Errorf("Test %d, Www-Authenticate should be %s provided %s", i, "Basic", val[0]) } } else { t.Errorf("Test %d, should provide a header Www-Authenticate", i) } } } }
func nextFunc(shouldMime bool, contentType string) middleware.Handler { return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { if shouldMime { if w.Header().Get("Content-Type") != contentType { return 0, fmt.Errorf("expected Content-Type: %v, found %v", contentType, r.Header.Get("Content-Type")) } return 0, nil } if w.Header().Get("Content-Type") != "" { return 0, fmt.Errorf("Content-Type header not expected") } return 0, nil }) }
func TestHeaders(t *testing.T) { hostname, err := os.Hostname() if err != nil { t.Fatalf("Could not determine hostname: %v", err) } for i, test := range []struct { from string name string value string }{ {"/a", "Foo", "Bar"}, {"/a", "Bar", ""}, {"/a", "Baz", ""}, {"/a", "ServerName", hostname}, {"/b", "Foo", ""}, {"/b", "Bar", "Removed in /a"}, } { he := Headers{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }), Rules: []Rule{ {Path: "/a", Headers: []Header{ {Name: "Foo", Value: "Bar"}, {Name: "ServerName", Value: "{hostname}"}, {Name: "-Bar"}, }}, }, } req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() rec.Header().Set("Bar", "Removed in /a") he.ServeHTTP(rec, req) if got := rec.Header().Get(test.name); got != test.value { t.Errorf("Test %d: Expected %s header to be %q but was %q", i, test.name, test.value, got) } } }
func TestResponseFilterWriter(t *testing.T) { tests := []struct { body string shouldCompress bool }{ {"Hello\t\t\t\n", false}, {"Hello the \t\t\t world is\n\n\n great", true}, {"Hello \t\t\nfrom gzip", true}, {"Hello gzip\n", false}, } filters := []ResponseFilter{ LengthFilter(15), } server := Gzip{Configs: []Config{ {ResponseFilters: filters}, }} for i, ts := range tests { server.Next = middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { w.Header().Set("Content-Length", fmt.Sprint(len(ts.body))) w.Write([]byte(ts.body)) return 200, nil }) r := urlRequest("/") r.Header.Set("Accept-Encoding", "gzip") w := httptest.NewRecorder() server.ServeHTTP(w, r) resp := w.Body.String() if !ts.shouldCompress { if resp != ts.body { t.Errorf("Test %v: No compression expected, found %v", i, resp) } } else { if resp == ts.body { t.Errorf("Test %v: Compression expected, found %v", i, resp) } } } }
func TestRedirect(t *testing.T) { for i, test := range []struct { from string expectedLocation string }{ {"/from", "/to"}, {"/a", "/b"}, {"/aa", ""}, {"/", ""}, {"/a?foo=bar", "/b"}, {"/asdf?foo=bar", ""}, {"/foo#bar", ""}, {"/a#foo", "/b"}, } { var nextCalled bool re := Redirect{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { nextCalled = true return 0, nil }), Rules: []Rule{ {From: "/from", To: "/to"}, {From: "/a", To: "/b"}, }, } req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() re.ServeHTTP(rec, req) if rec.Header().Get("Location") != test.expectedLocation { t.Errorf("Test %d: Expected Location header to be %q but was %q", i, test.expectedLocation, rec.Header().Get("Location")) } if nextCalled && test.expectedLocation != "" { t.Errorf("Test %d: Next handler was unexpectedly called", i) } } }
func TestRealIP(t *testing.T) { for i, test := range []struct { actualIP string headerVal string expectedIP string }{ {"1.2.3.4:123", "", "1.2.3.4:123"}, {"4.4.255.255:123", "", "4.4.255.255:123"}, {"4.5.0.0:123", "1.2.3.4", "1.2.3.4:123"}, {"4.5.2.3:123", "1.2.6.7,5.6.7.8,111.111.111.111", "1.2.6.7:123"}, {"4.5.5.5:123", "NOTANIP", "4.5.5.5:123"}, {"aaaaaa", "1.2.3.4", "aaaaaa"}, {"aaaaaa:123", "1.2.3.4", "aaaaaa:123"}, } { remoteAddr := "" _, ipnet, err := net.ParseCIDR("4.5.0.0/16") // "4.5.x.x" if err != nil { t.Fatal(err) } he := &module{ next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { remoteAddr = r.RemoteAddr return 0, nil }), Header: "X-Real-IP", From: []*net.IPNet{ipnet}, } req, err := http.NewRequest("GET", "http://foo.tld/", nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } req.RemoteAddr = test.actualIP if test.headerVal != "" { req.Header.Set("X-Real-IP", test.headerVal) } rec := httptest.NewRecorder() he.ServeHTTP(rec, req) if remoteAddr != test.expectedIP { t.Errorf("Test %d: Expected '%s', but found '%s'", i, test.expectedIP, remoteAddr) } } }
func TestExtensions(t *testing.T) { rootDir := os.TempDir() // create a temporary page path := filepath.Join(rootDir, "extensions_test.html") _, err := os.Create(path) if err != nil { t.Fatal(err) } defer os.Remove(path) for i, test := range []struct { path string extensions []string expectedURL string }{ {"/extensions_test", []string{".html"}, "/extensions_test.html"}, {"/extensions_test/", []string{".html"}, "/extensions_test/"}, {"/extensions_test", []string{".json"}, "/extensions_test"}, {"/another_test", []string{".html"}, "/another_test"}, {"", []string{".html"}, ""}, } { ex := Ext{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }), Root: rootDir, Extensions: test.extensions, } req, err := http.NewRequest("GET", test.path, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() ex.ServeHTTP(rec, req) if got := req.URL.String(); got != test.expectedURL { t.Fatalf("Test %d: Got unexpected request URL: %q, wanted %q", i, got, test.expectedURL) } } }
func TestMultipleOverlappingRules(t *testing.T) { rw := BasicAuth{ Next: middleware.HandlerFunc(contentHandler), Rules: []Rule{ {Username: "******", Password: PlainMatcher("p1"), Resources: []string{"/t"}}, {Username: "******", Password: PlainMatcher("p2"), Resources: []string{"/t/t"}}, }, } tests := []struct { from string result int cred string }{ {"/t", http.StatusOK, "t:p1"}, {"/t/t", http.StatusOK, "t:p1"}, {"/t/t", http.StatusOK, "t1:p2"}, {"/a", http.StatusOK, "t1:p2"}, {"/t/t", http.StatusUnauthorized, "t1:p3"}, {"/t", http.StatusUnauthorized, "t1:p2"}, } for i, test := range tests { req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request %v", i, err) } auth := "Basic " + base64.StdEncoding.EncodeToString([]byte(test.cred)) req.Header.Set("Authorization", auth) rec := httptest.NewRecorder() result, err := rw.ServeHTTP(rec, req) if err != nil { t.Fatalf("Test %d: Could not ServeHTTP %v", i, err) } if result != test.result { t.Errorf("Test %d: Expected Header '%d' but was '%d'", i, test.result, result) } } }
func nextFunc(shouldGzip bool) middleware.Handler { return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { // write a relatively large text file b, err := ioutil.ReadFile("testdata/test.txt") if err != nil { return 500, err } if _, err := w.Write(b); err != nil { return 500, err } if shouldGzip { if r.Header.Get("Accept-Encoding") != "" { return 0, fmt.Errorf("Accept-Encoding header not expected") } if w.Header().Get("Content-Encoding") != "gzip" { return 0, fmt.Errorf("Content-Encoding must be gzip, found %v", r.Header.Get("Content-Encoding")) } if w.Header().Get("Vary") != "Accept-Encoding" { return 0, fmt.Errorf("Vary must be Accept-Encoding, found %v", r.Header.Get("Vary")) } if _, ok := w.(*gzipResponseWriter); !ok { return 0, fmt.Errorf("ResponseWriter should be gzipResponseWriter, found %T", w) } if strings.Contains(w.Header().Get("Content-Type"), "application/x-gzip") { return 0, fmt.Errorf("Content type should not be gzip.") } return 0, nil } if r.Header.Get("Accept-Encoding") == "" { return 0, fmt.Errorf("Accept-Encoding header expected") } if w.Header().Get("Content-Encoding") == "gzip" { return 0, fmt.Errorf("Content-Encoding must not be gzip, found gzip") } if _, ok := w.(*gzipResponseWriter); ok { return 0, fmt.Errorf("ResponseWriter should not be gzipResponseWriter") } return 0, nil }) }
func TestInternal(t *testing.T) { im := Internal{ Next: middleware.HandlerFunc(internalTestHandlerFunc), Paths: []string{"/internal"}, } tests := []struct { url string expectedCode int expectedBody string }{ {"/internal", http.StatusNotFound, ""}, {"/public", 0, "/public"}, {"/public/internal", 0, "/public/internal"}, {"/redirect", 0, "/internal"}, {"/cycle", http.StatusInternalServerError, ""}, } for i, test := range tests { req, err := http.NewRequest("GET", test.url, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() code, err := im.ServeHTTP(rec, req) if code != test.expectedCode { t.Errorf("Test %d: Expected status code %d for %s, but got %d", i, test.expectedCode, test.url, code) } if rec.Body.String() != test.expectedBody { t.Errorf("Test %d: Expected body '%s' for %s, but got '%s'", i, test.expectedBody, test.url, rec.Body.String()) } } }
func TestServeHTTP(t *testing.T) { h := Handler{ Next: middleware.HandlerFunc(nextHandler), Mux: NewMux(), } w := httptest.NewRecorder() r, err := http.NewRequest("GET", "/debug/pprof", nil) if err != nil { t.Fatal(err) } status, err := h.ServeHTTP(w, r) if status != 0 { t.Errorf("Expected status %d but got %d", 0, status) } if err != nil { t.Errorf("Expected nil error, but got: %v", err) } if w.Body.String() == "content" { t.Errorf("Expected pprof to handle request, but it didn't") } w = httptest.NewRecorder() r, err = http.NewRequest("GET", "/foo", nil) if err != nil { t.Fatal(err) } status, err = h.ServeHTTP(w, r) if status != http.StatusNotFound { t.Errorf("Test two: Expected status %d but got %d", http.StatusNotFound, status) } if err != nil { t.Errorf("Test two: Expected nil error, but got: %v", err) } if w.Body.String() != "content" { t.Errorf("Expected pprof to pass the request thru, but it didn't; got: %s", w.Body.String()) } }
func TestBrowseHTTPMethods(t *testing.T) { tmpl, err := template.ParseFiles("testdata/photos.tpl") if err != nil { t.Fatalf("An error occured while parsing the template: %v", err) } b := Browse{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return http.StatusTeapot, nil // not t.Fatalf, or we will not see what other methods yield }), Configs: []Config{ { PathScope: "/photos", Root: http.Dir("./testdata"), Template: tmpl, }, }, } rec := httptest.NewRecorder() for method, expected := range map[string]int{ http.MethodGet: http.StatusOK, http.MethodHead: http.StatusOK, http.MethodOptions: http.StatusNotImplemented, "PROPFIND": http.StatusNotImplemented, } { req, err := http.NewRequest(method, "/photos/", nil) if err != nil { t.Fatalf("Test: Could not create HTTP request: %v", err) } code, _ := b.ServeHTTP(rec, req) if code != expected { t.Errorf("Wrong status with HTTP Method %s: expected %d, got %d", method, expected, code) } } }
func TestVisibleErrorWithPanic(t *testing.T) { const panicMsg = "I'm a panic" eh := ErrorHandler{ ErrorPages: make(map[int]string), Debug: true, Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { panic(panicMsg) }), } req, err := http.NewRequest("GET", "/", nil) if err != nil { t.Fatal(err) } rec := httptest.NewRecorder() code, err := eh.ServeHTTP(rec, req) if code != 0 { t.Errorf("Expected error handler to return 0 (it should write to response), got status %d", code) } if err != nil { t.Errorf("Expected error handler to return nil error (it should panic!), but got '%v'", err) } body := rec.Body.String() if !strings.Contains(body, "[PANIC /] middleware/errors/errors_test.go") { t.Errorf("Expected response body to contain error log line, but it didn't:\n%s", body) } if !strings.Contains(body, panicMsg) { t.Errorf("Expected response body to contain panic message, but it didn't:\n%s", body) } if len(body) < 500 { t.Errorf("Expected response body to contain stack trace, but it was too short: len=%d", len(body)) } }
func TestHeaders(t *testing.T) { he := handler{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }), } req, err := http.NewRequest("GET", "/", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec := httptest.NewRecorder() he.ServeHTTP(rec, req) if got := rec.Header().Get("X-Request-Id"); got == "" { t.Error("Expected X-Request-Id header from rec but got nothing.") } if got := req.Header.Get("X-Request-Id"); got == "" { t.Error("Expected X-Request-Id header from req but got nothing.") } }
func TestMarkdownStaticGen(t *testing.T) { c := NewTestController(`markdown /blog { ext .md template tpl_with_include.html sitegen }`) c.Root = "./testdata" mid, err := Markdown(c) if err != nil { t.Errorf("Expected no errors, got: %v", err) } if mid == nil { t.Fatal("Expected middleware, was nil instead") } for _, start := range c.Startup { err := start() if err != nil { t.Errorf("Startup error: %v", err) } } next := middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }) hndlr := mid(next) mkdwn, ok := hndlr.(markdown.Markdown) if !ok { t.Fatalf("Was expecting a markdown.Markdown but got %T", hndlr) } expectedStaticFiles := map[string]string{"/blog/first_post.md": "testdata/generated_site/blog/first_post.md/index.html"} if fmt.Sprint(expectedStaticFiles) != fmt.Sprint(mkdwn.Configs[0].StaticFiles) { t.Fatalf("Test expected StaticFiles to be %s, but got %s", fmt.Sprint(expectedStaticFiles), fmt.Sprint(mkdwn.Configs[0].StaticFiles)) } filePath := "testdata/generated_site/blog/first_post.md/index.html" if _, err := os.Stat(filePath); err != nil { t.Fatalf("An error occured when getting the file information: %v", err) } html, err := ioutil.ReadFile(filePath) if err != nil { t.Fatalf("An error occured when getting the file content: %v", err) } expectedBody := `<!DOCTYPE html> <html> <head> <title>first_post</title> </head> <body> <h1>Header title</h1> <h1>Test h1</h1> </body> </html> ` if string(html) != expectedBody { t.Fatalf("Expected file content: %v got: %v", expectedBody, html) } fp := filepath.Join(c.Root, markdown.DefaultStaticDir) if err = os.RemoveAll(fp); err != nil { t.Errorf("Error while removing the generated static files: %v", err) } }
func genErrorHandler(status int, err error, body string) middleware.Handler { return middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { fmt.Fprint(w, body) return status, err }) }
func TestMarkdown(t *testing.T) { rootDir := "./testdata" f := func(filename string) string { return filepath.ToSlash(rootDir + string(filepath.Separator) + filename) } md := Markdown{ Root: rootDir, FileSys: http.Dir(rootDir), Configs: []*Config{ { Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/blog", Extensions: map[string]struct{}{ ".md": {}, }, Styles: []string{}, Scripts: []string{}, Template: setDefaultTemplate(f("markdown_tpl.html")), }, { Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/docflags", Extensions: map[string]struct{}{ ".md": {}, }, Styles: []string{}, Scripts: []string{}, Template: setDefaultTemplate(f("docflags/template.txt")), }, { Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/log", Extensions: map[string]struct{}{ ".md": {}, }, Styles: []string{"/resources/css/log.css", "/resources/css/default.css"}, Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"}, Template: GetDefaultTemplate(), }, { Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/og", Extensions: map[string]struct{}{ ".md": {}, }, Styles: []string{}, Scripts: []string{}, Template: setDefaultTemplate(f("markdown_tpl.html")), }, }, IndexFiles: []string{"index.html"}, Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }), } req, err := http.NewRequest("GET", "/blog/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec := httptest.NewRecorder() md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody := rec.Body.String() expectedBody := `<!DOCTYPE html> <html> <head> <title>Markdown test 1</title> </head> <body> <h1>Header for: Markdown test 1</h1> Welcome to A Caddy website! <h2>Welcome on the blog</h2> <p>Body</p> <pre><code class="language-go">func getTrue() bool { return true } </code></pre> </body> </html> ` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } req, err = http.NewRequest("GET", "/docflags/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec = httptest.NewRecorder() md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody = rec.Body.String() expectedBody = `Doc.var_string hello Doc.var_bool <no value> DocFlags.var_string <no value> DocFlags.var_bool true` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } req, err = http.NewRequest("GET", "/log/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec = httptest.NewRecorder() md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody = rec.Body.String() expectedBody = `<!DOCTYPE html> <html> <head> <title>Markdown test 2</title> <meta charset="utf-8"> <link rel="stylesheet" href="/resources/css/log.css"> <link rel="stylesheet" href="/resources/css/default.css"> <script src="/resources/js/log.js"></script> <script src="/resources/js/default.js"></script> </head> <body> <h2>Welcome on the blog</h2> <p>Body</p> <pre><code class="language-go">func getTrue() bool { return true } </code></pre> </body> </html>` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } req, err = http.NewRequest("GET", "/og/first.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec = httptest.NewRecorder() currenttime := time.Now().Local().Add(-time.Second) _ = os.Chtimes("testdata/og/first.md", currenttime, currenttime) currenttime = time.Now().Local() _ = os.Chtimes("testdata/og_static/og/first.md/index.html", currenttime, currenttime) time.Sleep(time.Millisecond * 200) md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody = rec.Body.String() expectedBody = `<!DOCTYPE html> <html> <head> <title>first_post</title> </head> <body> <h1>Header for: first_post</h1> Welcome to title! <h1>Test h1</h1> </body> </html>` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } }
func Test(t *testing.T) { tmpl := Templates{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }), 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: "./testdata", FileSys: http.Dir("./testdata"), } tmplroot := Templates{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }), Rules: []Rule{ { Extensions: []string{".html"}, IndexFiles: []string{"index.html"}, Path: "/", }, }, Root: "./testdata", FileSys: http.Dir("./testdata"), } /* * 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) } 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) } 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) } 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) } rec = httptest.NewRecorder() 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) } }
// // Used primarily for testing but needs to be exported so // add-ons can use this as a convenience. Does not initialize // the server-block-related fields. func NewTestController(input string) *Controller { return &Controller{ Config: &server.Config{ Root: ".", }, Dispenser: parse.NewDispenser("Testfile", strings.NewReader(input)), } } // EmptyNext is a no-op function that can be passed into // middleware.Middleware functions so that the assignment // to the Next field of the Handler can be tested. // // Used primarily for testing but needs to be exported so // add-ons can use this as a convenience. var EmptyNext = middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { return 0, nil }) // SameNext does a pointer comparison between next1 and next2. // // Used primarily for testing but needs to be exported so // add-ons can use this as a convenience. func SameNext(next1, next2 middleware.Handler) bool { return fmt.Sprintf("%v", next1) == fmt.Sprintf("%v", next2) }
func TestRewrite(t *testing.T) { rw := Rewrite{ Next: middleware.HandlerFunc(urlPrinter), Rules: []Rule{ NewSimpleRule("/from", "/to"), NewSimpleRule("/a", "/b"), NewSimpleRule("/b", "/b{uri}"), }, FileSys: http.Dir("."), } regexps := [][]string{ {"/reg/", ".*", "/to", ""}, {"/r/", "[a-z]+", "/toaz", "!.html|"}, {"/url/", "a([a-z0-9]*)s([A-Z]{2})", "/to/{path}", ""}, {"/ab/", "ab", "/ab?{query}", ".txt|"}, {"/ab/", "ab", "/ab?type=html&{query}", ".html|"}, {"/abc/", "ab", "/abc/{file}", ".html|"}, {"/abcd/", "ab", "/a/{dir}/{file}", ".html|"}, {"/abcde/", "ab", "/a#{fragment}", ".html|"}, {"/ab/", `.*\.jpg`, "/ajpg", ""}, {"/reggrp", `/ad/([0-9]+)([a-z]*)`, "/a{1}/{2}", ""}, {"/reg2grp", `(.*)`, "/{1}", ""}, {"/reg3grp", `(.*)/(.*)/(.*)`, "/{1}{2}{3}", ""}, } for _, regexpRule := range regexps { var ext []string if s := strings.Split(regexpRule[3], "|"); len(s) > 1 { ext = s[:len(s)-1] } rule, err := NewComplexRule(regexpRule[0], regexpRule[1], regexpRule[2], 0, ext, nil) if err != nil { t.Fatal(err) } rw.Rules = append(rw.Rules, rule) } tests := []struct { from string expectedTo string }{ {"/from", "/to"}, {"/a", "/b"}, {"/b", "/b/b"}, {"/aa", "/aa"}, {"/", "/"}, {"/a?foo=bar", "/b?foo=bar"}, {"/asdf?foo=bar", "/asdf?foo=bar"}, {"/foo#bar", "/foo#bar"}, {"/a#foo", "/b#foo"}, {"/reg/foo", "/to"}, {"/re", "/re"}, {"/r/", "/r/"}, {"/r/123", "/r/123"}, {"/r/a123", "/toaz"}, {"/r/abcz", "/toaz"}, {"/r/z", "/toaz"}, {"/r/z.html", "/r/z.html"}, {"/r/z.js", "/toaz"}, {"/url/asAB", "/to/url/asAB"}, {"/url/aBsAB", "/url/aBsAB"}, {"/url/a00sAB", "/to/url/a00sAB"}, {"/url/a0z0sAB", "/to/url/a0z0sAB"}, {"/ab/aa", "/ab/aa"}, {"/ab/ab", "/ab/ab"}, {"/ab/ab.txt", "/ab"}, {"/ab/ab.txt?name=name", "/ab?name=name"}, {"/ab/ab.html?name=name", "/ab?type=html&name=name"}, {"/abc/ab.html", "/abc/ab.html"}, {"/abcd/abcd.html", "/a/abcd/abcd.html"}, {"/abcde/abcde.html", "/a"}, {"/abcde/abcde.html#1234", "/a#1234"}, {"/ab/ab.jpg", "/ajpg"}, {"/reggrp/ad/12", "/a12"}, {"/reggrp/ad/124a", "/a124/a"}, {"/reggrp/ad/124abc", "/a124/abc"}, {"/reg2grp/ad/124abc", "/ad/124abc"}, {"/reg3grp/ad/aa/66", "/adaa66"}, {"/reg3grp/ad612/n1n/ab", "/ad612n1nab"}, } for i, test := range tests { req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() rw.ServeHTTP(rec, req) if rec.Body.String() != test.expectedTo { t.Errorf("Test %d: Expected URL to be '%s' but was '%s'", i, test.expectedTo, rec.Body.String()) } } statusTests := []struct { status int base string to string regexp string statusExpected bool }{ {400, "/status", "", "", true}, {400, "/ignore", "", "", false}, {400, "/", "", "^/ignore", false}, {400, "/", "", "(.*)", true}, {400, "/status", "", "", true}, } for i, s := range statusTests { urlPath := fmt.Sprintf("/status%d", i) rule, err := NewComplexRule(s.base, s.regexp, s.to, s.status, nil, nil) if err != nil { t.Fatalf("Test %d: No error expected for rule but found %v", i, err) } rw.Rules = []Rule{rule} req, err := http.NewRequest("GET", urlPath, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() code, err := rw.ServeHTTP(rec, req) if err != nil { t.Fatalf("Test %d: No error expected for handler but found %v", i, err) } if s.statusExpected { if rec.Body.String() != "" { t.Errorf("Test %d: Expected empty body but found %s", i, rec.Body.String()) } if code != s.status { t.Errorf("Test %d: Expected status code %d found %d", i, s.status, code) } } else { if code != 0 { t.Errorf("Test %d: Expected no status code found %d", i, code) } } } }
func TestBrowseJson(t *testing.T) { b := Browse{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }), Root: "./testdata", Configs: []Config{ Config{ PathScope: "/photos", }, }, } req, err := http.NewRequest("GET", "/photos/", nil) if err != nil { t.Fatalf("Test: Could not create HTTP request: %v", err) } req.Header.Set("Accept", "application/json") rec := httptest.NewRecorder() b.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected %d, got %d", http.StatusOK, rec.Code) } if rec.HeaderMap.Get("Content-Type") != "application/json; charset=utf-8" { t.Fatalf("Expected Content type to be application/json; charset=utf-8, but got %s ", rec.HeaderMap.Get("Content-Type")) } actualJsonResponseString := rec.Body.String() //generating the listing to compare it with the response body file, err := os.Open(b.Root + req.URL.Path) if err != nil { if os.IsPermission(err) { t.Fatalf("Os Permission Error") } } defer file.Close() files, err := file.Readdir(-1) if err != nil { t.Fatalf("Unable to Read Contents of the directory") } var fileinfos []FileInfo for _, f := range files { name := f.Name() if f.IsDir() { name += "/" } url := url.URL{Path: name} fileinfos = append(fileinfos, FileInfo{ IsDir: f.IsDir(), Name: f.Name(), Size: f.Size(), URL: url.String(), ModTime: f.ModTime(), Mode: f.Mode(), }) } listing := Listing{ Items: fileinfos, } listing.Sort = "name" listing.Order = "asc" listing.applySort() marsh, err := json.Marshal(listing.Items) if err != nil { t.Fatalf("Unable to Marshal the listing ") } expectedJsonString := string(marsh) if actualJsonResponseString != expectedJsonString { t.Errorf("Json response string doesnt match the expected Json response ") } }
func TestRewrite(t *testing.T) { rw := Rewrite{ Next: middleware.HandlerFunc(urlPrinter), Rules: []Rule{ NewSimpleRule("/from", "/to"), NewSimpleRule("/a", "/b"), }, } regexpRules := [][]string{ []string{"/reg/", ".*", "/to", ""}, []string{"/r/", "[a-z]+", "/toaz", "!.html|"}, []string{"/url/", "a([a-z0-9]*)s([A-Z]{2})", "/to/{path}", ""}, []string{"/ab/", "ab", "/ab?{query}", ".txt|"}, []string{"/ab/", "ab", "/ab?type=html&{query}", ".html|"}, []string{"/abc/", "ab", "/abc/{file}", ".html|"}, []string{"/abcd/", "ab", "/a/{dir}/{file}", ".html|"}, []string{"/abcde/", "ab", "/a#{frag}", ".html|"}, []string{"/ab/", `.*\.jpg`, "/ajpg", ""}, } for _, regexpRule := range regexpRules { var ext []string if s := strings.Split(regexpRule[3], "|"); len(s) > 1 { ext = s[:len(s)-1] } rule, err := NewRegexpRule(regexpRule[0], regexpRule[1], regexpRule[2], ext) if err != nil { t.Fatal(err) } rw.Rules = append(rw.Rules, rule) } tests := []struct { from string expectedTo string }{ {"/from", "/to"}, {"/a", "/b"}, {"/aa", "/aa"}, {"/", "/"}, {"/a?foo=bar", "/b?foo=bar"}, {"/asdf?foo=bar", "/asdf?foo=bar"}, {"/foo#bar", "/foo#bar"}, {"/a#foo", "/b#foo"}, {"/reg/foo", "/to"}, {"/re", "/re"}, {"/r/", "/r/"}, {"/r/123", "/r/123"}, {"/r/a123", "/toaz"}, {"/r/abcz", "/toaz"}, {"/r/z", "/toaz"}, {"/r/z.html", "/r/z.html"}, {"/r/z.js", "/toaz"}, {"/url/asAB", "/to/url/asAB"}, {"/url/aBsAB", "/url/aBsAB"}, {"/url/a00sAB", "/to/url/a00sAB"}, {"/url/a0z0sAB", "/to/url/a0z0sAB"}, {"/ab/aa", "/ab/aa"}, {"/ab/ab", "/ab/ab"}, {"/ab/ab.txt", "/ab"}, {"/ab/ab.txt?name=name", "/ab?name=name"}, {"/ab/ab.html?name=name", "/ab?type=html&name=name"}, {"/abc/ab.html", "/abc/ab.html"}, {"/abcd/abcd.html", "/a/abcd/abcd.html"}, {"/abcde/abcde.html", "/a"}, {"/abcde/abcde.html#1234", "/a#1234"}, {"/ab/ab.jpg", "/ajpg"}, } for i, test := range tests { req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } rec := httptest.NewRecorder() rw.ServeHTTP(rec, req) if rec.Body.String() != test.expectedTo { t.Errorf("Test %d: Expected URL to be '%s' but was '%s'", i, test.expectedTo, rec.Body.String()) } } }
func TestRedirect(t *testing.T) { for i, test := range []struct { from string expectedLocation string expectedCode int }{ {"http://localhost/from", "/to", http.StatusMovedPermanently}, {"http://localhost/a", "/b", http.StatusTemporaryRedirect}, {"http://localhost/aa", "", http.StatusOK}, {"http://localhost/", "", http.StatusOK}, {"http://localhost/a?foo=bar", "/b", http.StatusTemporaryRedirect}, {"http://localhost/asdf?foo=bar", "", http.StatusOK}, {"http://localhost/foo#bar", "", http.StatusOK}, {"http://localhost/a#foo", "/b", http.StatusTemporaryRedirect}, // The scheme checks that were added to this package don't actually // help with redirects because of Caddy's design: a redirect middleware // for http will always be different than the redirect middleware for // https because they have to be on different listeners. These tests // just go to show extra bulletproofing, I guess. {"http://localhost/scheme", "https://localhost/scheme", http.StatusMovedPermanently}, {"https://localhost/scheme", "", http.StatusOK}, {"https://localhost/scheme2", "http://localhost/scheme2", http.StatusMovedPermanently}, {"http://localhost/scheme2", "", http.StatusOK}, {"http://localhost/scheme3", "https://localhost/scheme3", http.StatusMovedPermanently}, {"https://localhost/scheme3", "", http.StatusOK}, } { var nextCalled bool re := Redirect{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { nextCalled = true return 0, nil }), Rules: []Rule{ {FromPath: "/from", To: "/to", Code: http.StatusMovedPermanently}, {FromPath: "/a", To: "/b", Code: http.StatusTemporaryRedirect}, // These http and https schemes would never actually be mixed in the same // redirect rule with Caddy because http and https schemes have different listeners, // so they don't share a redirect rule. So although these tests prove something // impossible with Caddy, it's extra bulletproofing at very little cost. {FromScheme: "http", FromPath: "/scheme", To: "https://localhost/scheme", Code: http.StatusMovedPermanently}, {FromScheme: "https", FromPath: "/scheme2", To: "http://localhost/scheme2", Code: http.StatusMovedPermanently}, {FromScheme: "", FromPath: "/scheme3", To: "https://localhost/scheme3", Code: http.StatusMovedPermanently}, }, } req, err := http.NewRequest("GET", test.from, nil) if err != nil { t.Fatalf("Test %d: Could not create HTTP request: %v", i, err) } if strings.HasPrefix(test.from, "https://") { req.TLS = new(tls.ConnectionState) // faux HTTPS } rec := httptest.NewRecorder() re.ServeHTTP(rec, req) if rec.Header().Get("Location") != test.expectedLocation { t.Errorf("Test %d: Expected Location header to be %q but was %q", i, test.expectedLocation, rec.Header().Get("Location")) } if rec.Code != test.expectedCode { t.Errorf("Test %d: Expected status code to be %d but was %d", i, test.expectedCode, rec.Code) } if nextCalled && test.expectedLocation != "" { t.Errorf("Test %d: Next handler was unexpectedly called", i) } } }
func TestMarkdown(t *testing.T) { templates := make(map[string]string) templates[DefaultTemplate] = "testdata/markdown_tpl.html" md := Markdown{ Root: "./testdata", FileSys: http.Dir("./testdata"), Configs: []*Config{ &Config{ Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/blog", Extensions: []string{".md"}, Styles: []string{}, Scripts: []string{}, Templates: templates, StaticDir: DefaultStaticDir, StaticFiles: make(map[string]string), }, &Config{ Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/log", Extensions: []string{".md"}, Styles: []string{"/resources/css/log.css", "/resources/css/default.css"}, Scripts: []string{"/resources/js/log.js", "/resources/js/default.js"}, Templates: make(map[string]string), StaticDir: DefaultStaticDir, StaticFiles: make(map[string]string), }, &Config{ Renderer: blackfriday.HtmlRenderer(0, "", ""), PathScope: "/og", Extensions: []string{".md"}, Styles: []string{}, Scripts: []string{}, Templates: templates, StaticDir: "testdata/og_static", StaticFiles: map[string]string{"/og/first.md": "testdata/og_static/og/first.md/index.html"}, Links: []PageLink{ PageLink{ Title: "first", Summary: "", Date: time.Now(), URL: "/og/first.md", }, }, }, }, IndexFiles: []string{"index.html"}, Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }), } for i := range md.Configs { c := md.Configs[i] if err := GenerateStatic(md, c); err != nil { t.Fatalf("Error: %v", err) } Watch(md, c, time.Millisecond*100) } req, err := http.NewRequest("GET", "/blog/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec := httptest.NewRecorder() md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody := rec.Body.String() expectedBody := `<!DOCTYPE html> <html> <head> <title>Markdown test</title> </head> <body> <h1>Header</h1> Welcome to A Caddy website! <h2>Welcome on the blog</h2> <p>Body</p> <p><code>go func getTrue() bool { return true } </code></p> </body> </html> ` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } req, err = http.NewRequest("GET", "/log/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec = httptest.NewRecorder() md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody = rec.Body.String() expectedBody = `<!DOCTYPE html> <html> <head> <title>Markdown test</title> <meta charset="utf-8"> <link rel="stylesheet" href="/resources/css/log.css"> <link rel="stylesheet" href="/resources/css/default.css"> <script src="/resources/js/log.js"></script> <script src="/resources/js/default.js"></script> </head> <body> <h2>Welcome on the blog</h2> <p>Body</p> <p><code>go func getTrue() bool { return true } </code></p> </body> </html>` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } req, err = http.NewRequest("GET", "/og/first.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec = httptest.NewRecorder() currenttime := time.Now().Local().Add(-time.Second) err = os.Chtimes("testdata/og/first.md", currenttime, currenttime) currenttime = time.Now().Local() err = os.Chtimes("testdata/og_static/og/first.md/index.html", currenttime, currenttime) time.Sleep(time.Millisecond * 200) md.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("Wrong status, expected: %d and got %d", http.StatusOK, rec.Code) } respBody = rec.Body.String() expectedBody = `<!DOCTYPE html> <html> <head> <title>first_post</title> </head> <body> <h1>Header</h1> Welcome to title! <h1>Test h1</h1> </body> </html>` if !equalStrings(respBody, expectedBody) { t.Fatalf("Expected body: %v got: %v", expectedBody, respBody) } expectedLinks := []string{ "/blog/test.md", "/log/test.md", } for i, c := range md.Configs[:2] { log.Printf("Test number: %d, configuration links: %v, config: %v", i, c.Links, c) if c.Links[0].URL != expectedLinks[i] { t.Fatalf("Expected %v got %v", expectedLinks[i], c.Links[0].URL) } } // attempt to trigger race conditions var w sync.WaitGroup f := func() { req, err := http.NewRequest("GET", "/log/test.md", nil) if err != nil { t.Fatalf("Could not create HTTP request: %v", err) } rec := httptest.NewRecorder() md.ServeHTTP(rec, req) w.Done() } for i := 0; i < 5; i++ { w.Add(1) go f() } w.Wait() f = func() { GenerateStatic(md, md.Configs[0]) w.Done() } for i := 0; i < 5; i++ { w.Add(1) go f() } w.Wait() if err = os.RemoveAll(DefaultStaticDir); err != nil { t.Errorf("Error while removing the generated static files: %v", err) } }
func TestBrowseJson(t *testing.T) { b := Browse{ Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { t.Fatalf("Next shouldn't be called") return 0, nil }), Root: "./testdata", Configs: []Config{ { PathScope: "/photos/", }, }, } //Getting the listing from the ./testdata/photos, the listing returned will be used to validate test results testDataPath := b.Root + "/photos/" file, err := os.Open(testDataPath) if err != nil { if os.IsPermission(err) { t.Fatalf("Os Permission Error") } } defer file.Close() files, err := file.Readdir(-1) if err != nil { t.Fatalf("Unable to Read Contents of the directory") } var fileinfos []FileInfo for i, f := range files { name := f.Name() // Tests fail in CI environment because all file mod times are the same for // some reason, making the sorting unpredictable. To hack around this, // we ensure here that each file has a different mod time. chTime := f.ModTime().Add(-(time.Duration(i) * time.Second)) if err := os.Chtimes(filepath.Join(testDataPath, name), chTime, chTime); err != nil { t.Fatal(err) } if f.IsDir() { name += "/" } url := url.URL{Path: "./" + name} fileinfos = append(fileinfos, FileInfo{ IsDir: f.IsDir(), Name: f.Name(), Size: f.Size(), URL: url.String(), ModTime: chTime, Mode: f.Mode(), }) } listing := Listing{Items: fileinfos} // this listing will be used for validation inside the tests tests := []struct { QueryURL string SortBy string OrderBy string Limit int shouldErr bool expectedResult []FileInfo }{ //test case 1: testing for default sort and order and without the limit parameter, default sort is by name and the default order is ascending //without the limit query entire listing will be produced {"/", "", "", -1, false, listing.Items}, //test case 2: limit is set to 1, orderBy and sortBy is default {"/?limit=1", "", "", 1, false, listing.Items[:1]}, //test case 3 : if the listing request is bigger than total size of listing then it should return everything {"/?limit=100000000", "", "", 100000000, false, listing.Items}, //test case 4 : testing for negative limit {"/?limit=-1", "", "", -1, false, listing.Items}, //test case 5 : testing with limit set to -1 and order set to descending {"/?limit=-1&order=desc", "", "desc", -1, false, listing.Items}, //test case 6 : testing with limit set to 2 and order set to descending {"/?limit=2&order=desc", "", "desc", 2, false, listing.Items}, //test case 7 : testing with limit set to 3 and order set to descending {"/?limit=3&order=desc", "", "desc", 3, false, listing.Items}, //test case 8 : testing with limit set to 3 and order set to ascending {"/?limit=3&order=asc", "", "asc", 3, false, listing.Items}, //test case 9 : testing with limit set to 1111111 and order set to ascending {"/?limit=1111111&order=asc", "", "asc", 1111111, false, listing.Items}, //test case 10 : testing with limit set to default and order set to ascending and sorting by size {"/?order=asc&sort=size", "size", "asc", -1, false, listing.Items}, //test case 11 : testing with limit set to default and order set to ascending and sorting by last modified {"/?order=asc&sort=time", "time", "asc", -1, false, listing.Items}, //test case 12 : testing with limit set to 1 and order set to ascending and sorting by last modified {"/?order=asc&sort=time&limit=1", "time", "asc", 1, false, listing.Items}, //test case 13 : testing with limit set to -100 and order set to ascending and sorting by last modified {"/?order=asc&sort=time&limit=-100", "time", "asc", -100, false, listing.Items}, //test case 14 : testing with limit set to -100 and order set to ascending and sorting by size {"/?order=asc&sort=size&limit=-100", "size", "asc", -100, false, listing.Items}, } for i, test := range tests { var marsh []byte req, err := http.NewRequest("GET", "/photos"+test.QueryURL, nil) if err == nil && test.shouldErr { t.Errorf("Test %d didn't error, but it should have", i) } else if err != nil && !test.shouldErr { t.Errorf("Test %d errored, but it shouldn't have; got '%v'", i, err) } req.Header.Set("Accept", "application/json") rec := httptest.NewRecorder() code, err := b.ServeHTTP(rec, req) if code != http.StatusOK { t.Fatalf("Wrong status, expected %d, got %d", http.StatusOK, code) } if rec.HeaderMap.Get("Content-Type") != "application/json; charset=utf-8" { t.Fatalf("Expected Content type to be application/json; charset=utf-8, but got %s ", rec.HeaderMap.Get("Content-Type")) } actualJSONResponse := rec.Body.String() copyOflisting := listing if test.SortBy == "" { copyOflisting.Sort = "name" } else { copyOflisting.Sort = test.SortBy } if test.OrderBy == "" { copyOflisting.Order = "asc" } else { copyOflisting.Order = test.OrderBy } copyOflisting.applySort() limit := test.Limit if limit <= len(copyOflisting.Items) && limit > 0 { marsh, err = json.Marshal(copyOflisting.Items[:limit]) } else { // if the 'limit' query is empty, or has the wrong value, list everything marsh, err = json.Marshal(copyOflisting.Items) } if err != nil { t.Fatalf("Unable to Marshal the listing ") } expectedJSON := string(marsh) if actualJSONResponse != expectedJSON { t.Errorf("JSON response doesn't match the expected for test number %d with sort=%s, order=%s\nExpected response %s\nActual response = %s\n", i+1, test.SortBy, test.OrderBy, expectedJSON, actualJSONResponse) } } }