Replaces TestTurnstileRoutesSmoke: empty adds nothing; open, closed and a
space-padded closed add turnstile:{mode} to POST login and register only,
every other route keeps its middleware; invalid values fail naming the key.
159 lines
4.8 KiB
Go
159 lines
4.8 KiB
Go
package user
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/pact"
|
|
)
|
|
|
|
// recordedRoute is one registration seen by recordingRouter.
|
|
type recordedRoute struct {
|
|
method string
|
|
path string
|
|
middleware []string
|
|
}
|
|
|
|
// recordingRouter is a pact.Router that records each registration with its
|
|
// full path and the group plus route middleware. The plugin requires a
|
|
// framework whose surf does not know the turnstile:* names, so the smoke test
|
|
// checks the declared middleware instead of assembling a real router.
|
|
type recordingRouter struct {
|
|
prefix string
|
|
middleware []string
|
|
routes *[]recordedRoute
|
|
}
|
|
|
|
func newRecordingRouter() *recordingRouter {
|
|
return &recordingRouter{routes: &[]recordedRoute{}}
|
|
}
|
|
|
|
func (r *recordingRouter) Group(prefix string, middleware []string, fn func(pact.Router)) {
|
|
fn(&recordingRouter{
|
|
prefix: r.prefix + prefix,
|
|
middleware: append(append([]string{}, r.middleware...), middleware...),
|
|
routes: r.routes,
|
|
})
|
|
}
|
|
|
|
func (r *recordingRouter) GroupRaw(prefix string, middleware []string, fn func(pact.Router)) {
|
|
r.Group(prefix, middleware, fn)
|
|
}
|
|
|
|
func (r *recordingRouter) add(method, path string, middleware []string) {
|
|
*r.routes = append(*r.routes, recordedRoute{
|
|
method: method,
|
|
path: r.prefix + path,
|
|
middleware: append(append([]string{}, r.middleware...), middleware...),
|
|
})
|
|
}
|
|
|
|
func (r *recordingRouter) Get(path string, _ http.HandlerFunc, mw ...string) {
|
|
r.add(http.MethodGet, path, mw)
|
|
}
|
|
func (r *recordingRouter) Post(path string, _ http.HandlerFunc, mw ...string) {
|
|
r.add(http.MethodPost, path, mw)
|
|
}
|
|
func (r *recordingRouter) Put(path string, _ http.HandlerFunc, mw ...string) {
|
|
r.add(http.MethodPut, path, mw)
|
|
}
|
|
func (r *recordingRouter) Patch(path string, _ http.HandlerFunc, mw ...string) {
|
|
r.add(http.MethodPatch, path, mw)
|
|
}
|
|
func (r *recordingRouter) Delete(path string, _ http.HandlerFunc, mw ...string) {
|
|
r.add(http.MethodDelete, path, mw)
|
|
}
|
|
func (r *recordingRouter) Where(string, string) {}
|
|
func (r *recordingRouter) WhereIn(string, ...string) {}
|
|
|
|
func recordUserRoutes(t *testing.T, mode string) ([]recordedRoute, error) {
|
|
t.Helper()
|
|
app := bareApp(t)
|
|
if err := app.Config.Set("golem15.user.turnstile", mode); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rec := newRecordingRouter()
|
|
err := (&Plugin{app: app}).Routes(rec)
|
|
return *rec.routes, err
|
|
}
|
|
|
|
func turnstileOf(route recordedRoute) []string {
|
|
var out []string
|
|
for _, name := range route.middleware {
|
|
if strings.HasPrefix(name, "turnstile") {
|
|
out = append(out, name)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// TestTurnstileRoutes pins golem15.user.turnstile (D-07): empty adds no
|
|
// middleware; open and closed (surrounding spaces trimmed) append
|
|
// turnstile:{mode} to POST /_user/api/v1/login and /register only, leaving
|
|
// every other route's middleware as it is with the key empty; any other
|
|
// value fails Routes naming the key.
|
|
func TestTurnstileRoutes(t *testing.T) {
|
|
off, err := recordUserRoutes(t, "")
|
|
if err != nil {
|
|
t.Fatalf("empty turnstile: Routes error %v", err)
|
|
}
|
|
if len(off) == 0 {
|
|
t.Fatal("no routes recorded")
|
|
}
|
|
guarded := map[string]bool{
|
|
http.MethodPost + " /_user/api/v1/login": true,
|
|
http.MethodPost + " /_user/api/v1/register": true,
|
|
}
|
|
seen := 0
|
|
for _, route := range off {
|
|
if got := turnstileOf(route); len(got) > 0 {
|
|
t.Errorf("empty turnstile: %s %s carries %v", route.method, route.path, got)
|
|
}
|
|
if guarded[route.method+" "+route.path] {
|
|
seen++
|
|
}
|
|
}
|
|
if seen != len(guarded) {
|
|
t.Fatalf("found %d of the guarded routes, want %d", seen, len(guarded))
|
|
}
|
|
|
|
cases := []struct {
|
|
name, mode, want string
|
|
}{
|
|
{name: "open", mode: "open", want: "turnstile:open"},
|
|
{name: "closed", mode: "closed", want: "turnstile:closed"},
|
|
{name: "closed with spaces", mode: " closed ", want: "turnstile:closed"},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
got, err := recordUserRoutes(t, c.mode)
|
|
if err != nil {
|
|
t.Fatalf("Routes error %v", err)
|
|
}
|
|
if len(got) != len(off) {
|
|
t.Fatalf("%d routes, want %d", len(got), len(off))
|
|
}
|
|
for i, route := range got {
|
|
base := off[i]
|
|
if route.method != base.method || route.path != base.path {
|
|
t.Fatalf("route %d is %s %s, want %s %s", i, route.method, route.path, base.method, base.path)
|
|
}
|
|
want := base.middleware
|
|
if guarded[route.method+" "+route.path] {
|
|
want = append(append([]string{}, base.middleware...), c.want)
|
|
}
|
|
if strings.Join(route.middleware, ",") != strings.Join(want, ",") {
|
|
t.Errorf("%s %s middleware %v, want %v", route.method, route.path, route.middleware, want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
for _, bad := range []string{"bogus", "Closed", "on", "true"} {
|
|
if _, err := recordUserRoutes(t, bad); err == nil || !strings.Contains(err.Error(), "golem15.user.turnstile") {
|
|
t.Errorf("turnstile %q: error %v, want one naming golem15.user.turnstile", bad, err)
|
|
}
|
|
}
|
|
}
|