test(11-07): cover lighthouse realtime and the Centrifugo driver

- lighthouse: TestSuppression (Widget silenced, Gadget not, nesting,
  stale outer ctx), TestBulkEmitsOnce, TestBroadcastEdges (zero-key batch,
  update actor, id-only delete, method contract, multi-channel, savepoint),
  TestBroadcastPublishFailure, TestFromSelectsDriver, TestMountSurfaces,
  TestRegistry under -race, drivers, args JSON, Bind (coverage 91.7%)
- centrifugo: TestTokenClaims, TestTokenHandler, TestClientRequests,
  TestClientLoadConfig and a TestProxy table porting the WinterCMS WS-005,
  WS-007 and WS-013 cases (coverage 92.4%)
This commit is contained in:
Jakub Zych
2026-09-30 14:21:03 +02:00
parent 35ac96d664
commit 33194a1f98
9 changed files with 1593 additions and 33 deletions

View File

@@ -0,0 +1,142 @@
package lighthouse
import (
"context"
"encoding/json"
"net/http"
"strings"
"testing"
"git.golem15.com/golem15/summercms/modules/pact"
)
// recRouter records the groups and routes Mount registers.
type recRouter struct {
groups []recGroup
routes []string
}
type recGroup struct {
raw bool
prefix string
middleware []string
routes []string
}
func (r *recRouter) group(raw bool, prefix string, mw []string, fn func(pact.Router)) {
inner := &recRouter{}
fn(inner)
r.groups = append(r.groups, recGroup{raw: raw, prefix: prefix, middleware: append([]string(nil), mw...), routes: inner.routes})
}
func (r *recRouter) Group(prefix string, mw []string, fn func(pact.Router)) {
r.group(false, prefix, mw, fn)
}
func (r *recRouter) GroupRaw(prefix string, mw []string, fn func(pact.Router)) {
r.group(true, prefix, mw, fn)
}
func (r *recRouter) add(m, p string) { r.routes = append(r.routes, m+" "+p) }
func (r *recRouter) Get(p string, _ http.HandlerFunc, _ ...string) { r.add("GET", p) }
func (r *recRouter) Post(p string, _ http.HandlerFunc, _ ...string) { r.add("POST", p) }
func (r *recRouter) Put(p string, _ http.HandlerFunc, _ ...string) { r.add("PUT", p) }
func (r *recRouter) Patch(p string, _ http.HandlerFunc, _ ...string) { r.add("PATCH", p) }
func (r *recRouter) Delete(p string, _ http.HandlerFunc, _ ...string) { r.add("DELETE", p) }
func (r *recRouter) Where(string, string) {}
func (r *recRouter) WhereIn(string, ...string) {}
// routeDriver is a driver that declares the given routes.
type routeDriver struct{ routes []Route }
func (d routeDriver) Name() string { return "acme" }
func (d routeDriver) Routes() []Route { return d.routes }
func (routeDriver) Publish(context.Context, string, string, json.RawMessage) error {
return nil
}
func (routeDriver) Broadcast(context.Context, []string, string, json.RawMessage) error {
return nil
}
func okHandler(http.ResponseWriter, *http.Request) {}
// TestMountSurfaces covers D-13 and T-11-19: UserAuth and Public routes
// mount in a group with the surface middleware then the shared middleware,
// ServerToServer routes in a raw group, every method is registered, a
// UserAuth route without a guard is refused before anything is mounted,
// and a nil driver or the null driver mounts nothing.
func TestMountSurfaces(t *testing.T) {
s := Surfaces{UserAuth: []string{"jwt.auth"}, ServerToServer: []string{"acme.s2s"}, Public: []string{"acme.public"}, Middleware: []string{"throttle:ws-api"}}
d := routeDriver{routes: []Route{
{Name: "token", Method: "get", Path: "/api/rt/token", Surface: UserAuth, Handler: okHandler},
{Name: "subscribe", Method: http.MethodPost, Path: "/api/rt/subscribe", Surface: ServerToServer, Handler: okHandler},
{Name: "put", Method: http.MethodPut, Path: "/api/rt/p", Surface: Public, Handler: okHandler},
{Name: "patch", Method: http.MethodPatch, Path: "/api/rt/p", Surface: Public, Handler: okHandler},
{Name: "delete", Method: http.MethodDelete, Path: "/api/rt/p", Surface: Public, Handler: okHandler},
}}
r := &recRouter{}
if err := Mount(r, d, s); err != nil {
t.Fatal(err)
}
want := []recGroup{
{false, "/", []string{"jwt.auth", "throttle:ws-api"}, []string{"GET /api/rt/token"}},
{true, "/", []string{"acme.s2s", "throttle:ws-api"}, []string{"POST /api/rt/subscribe"}},
{false, "/", []string{"acme.public", "throttle:ws-api"}, []string{"PUT /api/rt/p"}},
{false, "/", []string{"acme.public", "throttle:ws-api"}, []string{"PATCH /api/rt/p"}},
{false, "/", []string{"acme.public", "throttle:ws-api"}, []string{"DELETE /api/rt/p"}},
}
if len(r.groups) != len(want) {
t.Fatalf("groups = %+v", r.groups)
}
for i, w := range want {
g := r.groups[i]
if g.raw != w.raw || g.prefix != w.prefix || strings.Join(g.middleware, ",") != strings.Join(w.middleware, ",") || strings.Join(g.routes, ",") != strings.Join(w.routes, ",") {
t.Errorf("group %d = %+v, want %+v", i, g, w)
}
}
if len(s.UserAuth) != 1 || s.UserAuth[0] != "jwt.auth" {
t.Fatal("Mount mutated the caller's surface middleware")
}
refusals := []struct {
name string
route Route
s Surfaces
want string
}{
{"user_route_without_guard", Route{Name: "token", Method: "GET", Path: "/t", Surface: UserAuth, Handler: okHandler}, Surfaces{Middleware: []string{"throttle"}}, "Surfaces.UserAuth is empty"},
{"no_handler", Route{Name: "x", Method: "GET", Path: "/t", Surface: Public}, s, "has no handler"},
{"relative_path", Route{Name: "x", Method: "GET", Path: "t", Surface: Public, Handler: okHandler}, s, "must be absolute"},
{"bad_method", Route{Name: "x", Method: "TRACE", Path: "/t", Surface: Public, Handler: okHandler}, s, "unsupported method"},
{"unknown_surface", Route{Name: "x", Method: "GET", Path: "/t", Surface: Surface(9), Handler: okHandler}, s, "unknown surface Surface(9)"},
}
for _, c := range refusals {
t.Run(c.name, func(t *testing.T) {
r := &recRouter{}
// A valid route first: nothing may be mounted when a later one
// is invalid.
valid := Route{Name: "ok", Method: "POST", Path: "/ok", Surface: ServerToServer, Handler: okHandler}
err := Mount(r, routeDriver{routes: []Route{valid, c.route}}, c.s)
if err == nil || !strings.Contains(err.Error(), c.want) || !strings.Contains(err.Error(), "driver acme route") {
t.Fatalf("err = %v, want %q", err, c.want)
}
if len(r.groups) != 0 {
t.Fatalf("mounted %d group(s) before refusing", len(r.groups))
}
})
}
if err := Mount(nil, d, s); err == nil {
t.Fatal("nil router accepted")
}
r = &recRouter{}
if err := Mount(r, nil, s); err != nil || len(r.groups) != 0 {
t.Fatalf("nil driver: err %v, groups %d", err, len(r.groups))
}
if err := Mount(r, nullDriver{}, Surfaces{}); err != nil || len(r.groups) != 0 {
t.Fatalf("null driver: err %v, groups %d", err, len(r.groups))
}
for surface, name := range map[Surface]string{UserAuth: "UserAuth", ServerToServer: "ServerToServer", Public: "Public", Surface(0): "Surface(0)"} {
if surface.String() != name {
t.Errorf("Surface(%d).String() = %q", int(surface), surface.String())
}
}
}