1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-03-19 22:19:23 +02:00
pocketbase/tools/router/router_test.go

254 lines
5.5 KiB
Go

package router_test
import (
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/pocketbase/pocketbase/tools/hook"
"github.com/pocketbase/pocketbase/tools/router"
)
func TestRouter(t *testing.T) {
calls := ""
r := router.NewRouter(func(w http.ResponseWriter, r *http.Request) (*router.Event, router.EventCleanupFunc) {
return &router.Event{
Response: w,
Request: r,
},
func() {
calls += ":cleanup"
}
})
r.BindFunc(func(e *router.Event) error {
calls += "root_m:"
err := e.Next()
if err != nil {
calls += "/error"
}
return err
})
r.Any("/any", func(e *router.Event) error {
calls += "/any"
return nil
})
r.GET("/a", func(e *router.Event) error {
calls += "/a"
return nil
})
g1 := r.Group("/a/b").BindFunc(func(e *router.Event) error {
calls += "a_b_group_m:"
return e.Next()
})
g1.GET("/1", func(e *router.Event) error {
calls += "/1_get"
return nil
}).BindFunc(func(e *router.Event) error {
calls += "1_get_m:"
return e.Next()
})
g1.POST("/1", func(e *router.Event) error {
calls += "/1_post"
return nil
})
g1.GET("/{param}", func(e *router.Event) error {
calls += "/" + e.Request.PathValue("param")
return errors.New("test") // should be normalized to an ApiError
})
mux, err := r.BuildMux()
if err != nil {
t.Fatal(err)
}
ts := httptest.NewServer(mux)
defer ts.Close()
client := ts.Client()
scenarios := []struct {
method string
path string
calls string
}{
{http.MethodGet, "/any", "root_m:/any:cleanup"},
{http.MethodOptions, "/any", "root_m:/any:cleanup"},
{http.MethodPatch, "/any", "root_m:/any:cleanup"},
{http.MethodPut, "/any", "root_m:/any:cleanup"},
{http.MethodPost, "/any", "root_m:/any:cleanup"},
{http.MethodDelete, "/any", "root_m:/any:cleanup"},
// ---
{http.MethodPost, "/a", "root_m:/error:cleanup"}, // missing
{http.MethodGet, "/a", "root_m:/a:cleanup"},
{http.MethodHead, "/a", "root_m:/a:cleanup"}, // auto registered with the GET
{http.MethodGet, "/a/b/1", "root_m:a_b_group_m:1_get_m:/1_get:cleanup"},
{http.MethodHead, "/a/b/1", "root_m:a_b_group_m:1_get_m:/1_get:cleanup"},
{http.MethodPost, "/a/b/1", "root_m:a_b_group_m:/1_post:cleanup"},
{http.MethodGet, "/a/b/456", "root_m:a_b_group_m:/456/error:cleanup"},
}
for _, s := range scenarios {
t.Run(s.method+"_"+s.path, func(t *testing.T) {
calls = "" // reset
req, err := http.NewRequest(s.method, ts.URL+s.path, nil)
if err != nil {
t.Fatal(err)
}
_, err = client.Do(req)
if err != nil {
t.Fatal(err)
}
if calls != s.calls {
t.Fatalf("Expected calls\n%q\ngot\n%q", s.calls, calls)
}
})
}
}
func TestRouterUnbind(t *testing.T) {
calls := ""
r := router.NewRouter(func(w http.ResponseWriter, r *http.Request) (*router.Event, router.EventCleanupFunc) {
return &router.Event{
Response: w,
Request: r,
},
func() {
calls += ":cleanup"
}
})
r.Bind(&hook.Handler[*router.Event]{
Id: "root_1",
Func: func(e *router.Event) error {
calls += "root_1:"
return e.Next()
},
})
r.Bind(&hook.Handler[*router.Event]{
Id: "root_2",
Func: func(e *router.Event) error {
calls += "root_2:"
return e.Next()
},
})
r.Bind(&hook.Handler[*router.Event]{
Id: "root_3",
Func: func(e *router.Event) error {
calls += "root_3:"
return e.Next()
},
})
r.GET("/action", func(e *router.Event) error {
calls += "root_action"
return nil
}).Unbind("root_1")
ga := r.Group("/group_a")
ga.Unbind("root_1")
ga.Bind(&hook.Handler[*router.Event]{
Id: "group_a_1",
Func: func(e *router.Event) error {
calls += "group_a_1:"
return e.Next()
},
})
ga.Bind(&hook.Handler[*router.Event]{
Id: "group_a_2",
Func: func(e *router.Event) error {
calls += "group_a_2:"
return e.Next()
},
})
ga.Bind(&hook.Handler[*router.Event]{
Id: "group_a_3",
Func: func(e *router.Event) error {
calls += "group_a_3:"
return e.Next()
},
})
ga.GET("/action", func(e *router.Event) error {
calls += "group_a_action"
return nil
}).Unbind("root_2", "group_b_1", "group_a_1")
gb := r.Group("/group_b")
gb.Unbind("root_2")
gb.Bind(&hook.Handler[*router.Event]{
Id: "group_b_1",
Func: func(e *router.Event) error {
calls += "group_b_1:"
return e.Next()
},
})
gb.Bind(&hook.Handler[*router.Event]{
Id: "group_b_2",
Func: func(e *router.Event) error {
calls += "group_b_2:"
return e.Next()
},
})
gb.Bind(&hook.Handler[*router.Event]{
Id: "group_b_3",
Func: func(e *router.Event) error {
calls += "group_b_3:"
return e.Next()
},
})
gb.GET("/action", func(e *router.Event) error {
calls += "group_b_action"
return nil
}).Unbind("group_b_3", "group_a_3", "root_3")
mux, err := r.BuildMux()
if err != nil {
t.Fatal(err)
}
ts := httptest.NewServer(mux)
defer ts.Close()
client := ts.Client()
scenarios := []struct {
method string
path string
calls string
}{
{http.MethodGet, "/action", "root_2:root_3:root_action:cleanup"},
{http.MethodGet, "/group_a/action", "root_3:group_a_2:group_a_3:group_a_action:cleanup"},
{http.MethodGet, "/group_b/action", "root_1:group_b_1:group_b_2:group_b_action:cleanup"},
}
for _, s := range scenarios {
t.Run(s.method+"_"+s.path, func(t *testing.T) {
calls = "" // reset
req, err := http.NewRequest(s.method, ts.URL+s.path, nil)
if err != nil {
t.Fatal(err)
}
_, err = client.Do(req)
if err != nil {
t.Fatal(err)
}
if calls != s.calls {
t.Fatalf("Expected calls\n%q\ngot\n%q", s.calls, calls)
}
})
}
}