initial implementation
This commit is contained in:
parent
f8b0abc517
commit
cb373e637b
16 changed files with 777 additions and 1 deletions
169
pkg/router/mux_test.go
Normal file
169
pkg/router/mux_test.go
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func do(t *testing.T, m *Mux, method, target string) *httptest.ResponseRecorder {
|
||||
t.Helper()
|
||||
rr := httptest.NewRecorder()
|
||||
m.ServeHTTP(rr, httptest.NewRequest(method, target, nil))
|
||||
return rr
|
||||
}
|
||||
|
||||
func TestMethodRouting(t *testing.T) {
|
||||
m := New()
|
||||
m.Get("/x", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "get") })
|
||||
m.Post("/x", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "post") })
|
||||
|
||||
if got := do(t, m, http.MethodGet, "/x").Body.String(); got != "get" {
|
||||
t.Errorf("GET /x = %q", got)
|
||||
}
|
||||
if got := do(t, m, http.MethodPost, "/x").Body.String(); got != "post" {
|
||||
t.Errorf("POST /x = %q", got)
|
||||
}
|
||||
if rr := do(t, m, http.MethodPut, "/x"); rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("PUT /x got %d, want 405", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPathValueAcrossMiddleware(t *testing.T) {
|
||||
m := New()
|
||||
m.Use(func(next http.Handler) http.Handler { return next })
|
||||
var got string
|
||||
m.Get("/users/{id}", func(w http.ResponseWriter, r *http.Request) {
|
||||
got = r.PathValue("id")
|
||||
})
|
||||
do(t, m, http.MethodGet, "/users/42")
|
||||
if got != "42" {
|
||||
t.Errorf("PathValue = %q, want 42", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupPrefix(t *testing.T) {
|
||||
m := New()
|
||||
api := m.Group("/api")
|
||||
api.Get("/ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "pong") })
|
||||
|
||||
if got := do(t, m, http.MethodGet, "/api/ping").Body.String(); got != "pong" {
|
||||
t.Errorf("/api/ping = %q", got)
|
||||
}
|
||||
if rr := do(t, m, http.MethodGet, "/ping"); rr.Code != http.StatusNotFound {
|
||||
t.Errorf("unprefixed /ping got %d, want 404", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupNested(t *testing.T) {
|
||||
m := New()
|
||||
api := m.Group("/api")
|
||||
v1 := api.Group("/v1")
|
||||
v1.Get("/ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "pong") })
|
||||
|
||||
if got := do(t, m, http.MethodGet, "/api/v1/ping").Body.String(); got != "pong" {
|
||||
t.Errorf("/api/v1/ping = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupTrailingSlashNormalized(t *testing.T) {
|
||||
m := New()
|
||||
api := m.Group("/api/")
|
||||
api.Get("/ping", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "pong") })
|
||||
|
||||
if got := do(t, m, http.MethodGet, "/api/ping").Body.String(); got != "pong" {
|
||||
t.Errorf("/api/ping = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGroupRootSubtree(t *testing.T) {
|
||||
m := New()
|
||||
api := m.Group("/api")
|
||||
api.Get("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "subtree") })
|
||||
|
||||
if got := do(t, m, http.MethodGet, "/api/").Body.String(); got != "subtree" {
|
||||
t.Errorf("/api/ = %q", got)
|
||||
}
|
||||
if got := do(t, m, http.MethodGet, "/api/anything").Body.String(); got != "subtree" {
|
||||
t.Errorf("/api/anything = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUseAfterGroupDoesNotPropagate(t *testing.T) {
|
||||
m := New()
|
||||
api := m.Group("/api")
|
||||
hits := 0
|
||||
m.Use(func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
hits++
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
})
|
||||
api.Get("/x", func(w http.ResponseWriter, r *http.Request) {})
|
||||
m.Get("/y", func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
do(t, m, http.MethodGet, "/api/x")
|
||||
if hits != 0 {
|
||||
t.Errorf("late Use propagated to api group, hits=%d", hits)
|
||||
}
|
||||
do(t, m, http.MethodGet, "/y")
|
||||
if hits != 1 {
|
||||
t.Errorf("late Use did not apply to root, hits=%d", hits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPerRouteAndGroupMiddlewareStack(t *testing.T) {
|
||||
m := New()
|
||||
var log []string
|
||||
m.Use(tagMW(&log, "use"))
|
||||
api := m.Group("/api", tagMW(&log, "group"))
|
||||
api.Get("/x",
|
||||
func(w http.ResponseWriter, r *http.Request) { log = append(log, "h") },
|
||||
tagMW(&log, "route"),
|
||||
)
|
||||
|
||||
do(t, m, http.MethodGet, "/api/x")
|
||||
want := "use:before,group:before,route:before,h,route:after,group:after,use:after"
|
||||
if got := strings.Join(log, ","); got != want {
|
||||
t.Errorf("\n got %s\nwant %s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAcceptsBarePath(t *testing.T) {
|
||||
m := New()
|
||||
m.Handle("/x", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "any")
|
||||
}))
|
||||
for _, method := range []string{http.MethodGet, http.MethodPost, http.MethodDelete} {
|
||||
if got := do(t, m, method, "/x").Body.String(); got != "any" {
|
||||
t.Errorf("%s /x = %q", method, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAcceptsMethodPattern(t *testing.T) {
|
||||
m := New()
|
||||
m.Handle("DELETE /x", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "del")
|
||||
}))
|
||||
if got := do(t, m, http.MethodDelete, "/x").Body.String(); got != "del" {
|
||||
t.Errorf("DELETE /x = %q", got)
|
||||
}
|
||||
if rr := do(t, m, http.MethodGet, "/x"); rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Errorf("GET /x got %d, want 405", rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConflictingPatternsPanic(t *testing.T) {
|
||||
m := New()
|
||||
m.Get("/x", func(w http.ResponseWriter, r *http.Request) {})
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatal("expected panic on duplicate pattern")
|
||||
}
|
||||
}()
|
||||
m.Get("/x", func(w http.ResponseWriter, r *http.Request) {})
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue