/backend/vendor/src/github.com/zenazn/goji/web/router_test.go
https://github.com/coreroller/coreroller · Go · 326 lines · 275 code · 42 blank · 9 comment · 27 complexity · 024a3a36983cc3df4c6ffcf34d7041df MD5 · raw file
- package web
- import (
- "net/http"
- "net/http/httptest"
- "reflect"
- "regexp"
- "testing"
- "time"
- )
- // These tests can probably be DRY'd up a bunch
- func chHandler(ch chan string, s string) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ch <- s
- })
- }
- var methods = []string{"CONNECT", "DELETE", "GET", "HEAD", "OPTIONS", "PATCH",
- "POST", "PUT", "TRACE", "OTHER"}
- func TestMethods(t *testing.T) {
- t.Parallel()
- m := New()
- ch := make(chan string, 1)
- m.Connect("/", chHandler(ch, "CONNECT"))
- m.Delete("/", chHandler(ch, "DELETE"))
- m.Head("/", chHandler(ch, "HEAD"))
- m.Get("/", chHandler(ch, "GET"))
- m.Options("/", chHandler(ch, "OPTIONS"))
- m.Patch("/", chHandler(ch, "PATCH"))
- m.Post("/", chHandler(ch, "POST"))
- m.Put("/", chHandler(ch, "PUT"))
- m.Trace("/", chHandler(ch, "TRACE"))
- m.Handle("/", chHandler(ch, "OTHER"))
- for _, method := range methods {
- r, _ := http.NewRequest(method, "/", nil)
- w := httptest.NewRecorder()
- m.ServeHTTP(w, r)
- select {
- case val := <-ch:
- if val != method {
- t.Errorf("Got %q, expected %q", val, method)
- }
- case <-time.After(5 * time.Millisecond):
- t.Errorf("Timeout waiting for method %q", method)
- }
- }
- }
- type testPattern struct{}
- func (t testPattern) Prefix() string {
- return ""
- }
- func (t testPattern) Match(r *http.Request, c *C) bool {
- return true
- }
- func (t testPattern) Run(r *http.Request, c *C) {
- }
- var _ Pattern = testPattern{}
- func TestPatternTypes(t *testing.T) {
- t.Parallel()
- m := New()
- m.Get("/hello/carl", http.NotFound)
- m.Get("/hello/:name", http.NotFound)
- m.Get(regexp.MustCompile(`^/hello/(?P<name>.+)$`), http.NotFound)
- m.Get(testPattern{}, http.NotFound)
- }
- type testHandler chan string
- func (t testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- t <- "http"
- }
- func (t testHandler) ServeHTTPC(c C, w http.ResponseWriter, r *http.Request) {
- t <- "httpc"
- }
- var testHandlerTable = map[string]string{
- "/a": "http fn",
- "/b": "http handler",
- "/c": "web fn",
- "/d": "web handler",
- "/e": "httpc",
- }
- func TestHandlerTypes(t *testing.T) {
- t.Parallel()
- m := New()
- ch := make(chan string, 1)
- m.Get("/a", func(w http.ResponseWriter, r *http.Request) {
- ch <- "http fn"
- })
- m.Get("/b", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- ch <- "http handler"
- }))
- m.Get("/c", func(c C, w http.ResponseWriter, r *http.Request) {
- ch <- "web fn"
- })
- m.Get("/d", HandlerFunc(func(c C, w http.ResponseWriter, r *http.Request) {
- ch <- "web handler"
- }))
- m.Get("/e", testHandler(ch))
- for route, response := range testHandlerTable {
- r, _ := http.NewRequest("GET", route, nil)
- w := httptest.NewRecorder()
- m.ServeHTTP(w, r)
- select {
- case resp := <-ch:
- if resp != response {
- t.Errorf("Got %q, expected %q", resp, response)
- }
- case <-time.After(5 * time.Millisecond):
- t.Errorf("Timeout waiting for path %q", route)
- }
- }
- }
- // The idea behind this test is to comprehensively test if routes are being
- // applied in the right order. We define a special pattern type that always
- // matches so long as it's greater than or equal to the global test index. By
- // incrementing this index, we can invalidate all routes up to some point, and
- // therefore test the routing guarantee that Goji provides: for any path P, if
- // both A and B match P, and if A was inserted before B, then Goji will route to
- // A before it routes to B.
- var rsRoutes = []string{
- "/",
- "/a",
- "/a",
- "/b",
- "/ab",
- "/",
- "/ba",
- "/b",
- "/a",
- }
- var rsTests = []struct {
- key string
- results []int
- }{
- {"/", []int{0, 5, 5, 5, 5, 5, -1, -1, -1, -1}},
- {"/a", []int{0, 1, 2, 5, 5, 5, 8, 8, 8, -1}},
- {"/b", []int{0, 3, 3, 3, 5, 5, 7, 7, -1, -1}},
- {"/ab", []int{0, 1, 2, 4, 4, 5, 8, 8, 8, -1}},
- {"/ba", []int{0, 3, 3, 3, 5, 5, 6, 7, -1, -1}},
- {"/c", []int{0, 5, 5, 5, 5, 5, -1, -1, -1, -1}},
- {"nope", []int{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
- }
- type rsPattern struct {
- i int
- counter *int
- prefix string
- ichan chan int
- }
- func (rs rsPattern) Prefix() string {
- return rs.prefix
- }
- func (rs rsPattern) Match(_ *http.Request, _ *C) bool {
- return rs.i >= *rs.counter
- }
- func (rs rsPattern) Run(_ *http.Request, _ *C) {
- }
- func (rs rsPattern) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {
- rs.ichan <- rs.i
- }
- var _ Pattern = rsPattern{}
- var _ http.Handler = rsPattern{}
- func TestRouteSelection(t *testing.T) {
- t.Parallel()
- m := New()
- counter := 0
- ichan := make(chan int, 1)
- m.NotFound(func(w http.ResponseWriter, r *http.Request) {
- ichan <- -1
- })
- for i, s := range rsRoutes {
- pat := rsPattern{
- i: i,
- counter: &counter,
- prefix: s,
- ichan: ichan,
- }
- m.Get(pat, pat)
- }
- for _, test := range rsTests {
- var n int
- for counter, n = range test.results {
- r, _ := http.NewRequest("GET", test.key, nil)
- w := httptest.NewRecorder()
- m.ServeHTTP(w, r)
- actual := <-ichan
- if n != actual {
- t.Errorf("Expected %q @ %d to be %d, got %d",
- test.key, counter, n, actual)
- }
- }
- }
- }
- func TestNotFound(t *testing.T) {
- t.Parallel()
- m := New()
- r, _ := http.NewRequest("post", "/", nil)
- w := httptest.NewRecorder()
- m.ServeHTTP(w, r)
- if w.Code != 404 {
- t.Errorf("Expected 404, got %d", w.Code)
- }
- m.NotFound(func(w http.ResponseWriter, r *http.Request) {
- http.Error(w, "I'm a teapot!", http.StatusTeapot)
- })
- r, _ = http.NewRequest("POST", "/", nil)
- w = httptest.NewRecorder()
- m.ServeHTTP(w, r)
- if w.Code != http.StatusTeapot {
- t.Errorf("Expected a teapot, got %d", w.Code)
- }
- }
- func TestPrefix(t *testing.T) {
- t.Parallel()
- m := New()
- ch := make(chan string, 1)
- m.Handle("/hello/*", func(w http.ResponseWriter, r *http.Request) {
- ch <- r.URL.Path
- })
- r, _ := http.NewRequest("GET", "/hello/world", nil)
- w := httptest.NewRecorder()
- m.ServeHTTP(w, r)
- select {
- case val := <-ch:
- if val != "/hello/world" {
- t.Errorf("Got %q, expected /hello/world", val)
- }
- case <-time.After(5 * time.Millisecond):
- t.Errorf("Timeout waiting for hello")
- }
- }
- var validMethodsTable = map[string][]string{
- "/hello/carl": {"DELETE", "GET", "HEAD", "PATCH", "POST", "PUT"},
- "/hello/bob": {"DELETE", "GET", "HEAD", "PATCH", "PUT"},
- "/hola/carl": {"DELETE", "GET", "HEAD", "PUT"},
- "/hola/bob": {"DELETE"},
- "/does/not/compute": {},
- }
- func TestValidMethods(t *testing.T) {
- t.Parallel()
- m := New()
- ch := make(chan []string, 1)
- m.NotFound(func(c C, w http.ResponseWriter, r *http.Request) {
- if c.Env == nil {
- ch <- []string{}
- return
- }
- methods, ok := c.Env[ValidMethodsKey]
- if !ok {
- ch <- []string{}
- return
- }
- ch <- methods.([]string)
- })
- m.Get("/hello/carl", http.NotFound)
- m.Post("/hello/carl", http.NotFound)
- m.Head("/hello/bob", http.NotFound)
- m.Get("/hello/:name", http.NotFound)
- m.Put("/hello/:name", http.NotFound)
- m.Patch("/hello/:name", http.NotFound)
- m.Get("/:greet/carl", http.NotFound)
- m.Put("/:greet/carl", http.NotFound)
- m.Delete("/:greet/:anyone", http.NotFound)
- for path, eMethods := range validMethodsTable {
- r, _ := http.NewRequest("BOGUS", path, nil)
- m.ServeHTTP(httptest.NewRecorder(), r)
- aMethods := <-ch
- if !reflect.DeepEqual(eMethods, aMethods) {
- t.Errorf("For %q, expected %v, got %v", path, eMethods,
- aMethods)
- }
- }
- // This should also work when c.Env has already been initalized
- m.Use(func(c *C, h http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- c.Env = make(map[interface{}]interface{})
- h.ServeHTTP(w, r)
- })
- })
- for path, eMethods := range validMethodsTable {
- r, _ := http.NewRequest("BOGUS", path, nil)
- m.ServeHTTP(httptest.NewRecorder(), r)
- aMethods := <-ch
- if !reflect.DeepEqual(eMethods, aMethods) {
- t.Errorf("For %q, expected %v, got %v", path, eMethods,
- aMethods)
- }
- }
- }