Files
sm-bm-plugin/realtime_materials_test.go
Jakub Zych 2a47186a7a feat: announce material revisions on materials:{id}
- every revision bump (API writes and /bmadmin saves) enqueues
  updated.jz.bm.material with {material_id, revision} in a savepoint
- the materials namespace authorizer allows a subscribe only to a
  visible material the user may manage
- api.ManagesMaterials and api.CanWatchMaterial
2026-11-09 01:12:49 +01:00

83 lines
2.5 KiB
Go

package bm
import (
"context"
"errors"
"testing"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/compass"
"gorm.io/gorm"
)
// watchPlugin builds jz.bm on an app with a published (fake) database
// unless noDB, and the given materials channel check.
func watchPlugin(t *testing.T, noDB bool, watch func(context.Context, *gorm.DB, uint, uint) (bool, error)) *Plugin {
t.Helper()
cfg, err := compass.Open(compass.Options{Dir: t.TempDir(), Environ: []string{"SUMMER_ENV=testing"}})
if err != nil {
t.Fatal(err)
}
app := backpack.New(cfg)
if !noDB {
if err := app.Publish[*gorm.DB](&gorm.DB{}); err != nil {
t.Fatal(err)
}
}
return &Plugin{app: app, watchMaterial: watch}
}
func TestAuthorizeMaterial(t *testing.T) {
ctx := context.Background()
type call struct{ userID, id uint }
var calls []call
watch := func(_ context.Context, _ *gorm.DB, userID, id uint) (bool, error) {
calls = append(calls, call{userID, id})
switch userID {
case 7:
return true, nil
case 13:
return false, errors.New("database down")
}
return false, nil
}
p := watchPlugin(t, false, watch)
if res := p.authorizeMaterial(ctx, 7, "materials:5"); !res.Allowed {
t.Errorf("manager on materials:5 denied: %s", res.Reason())
}
if len(calls) != 1 || calls[0] != (call{7, 5}) {
t.Errorf("seam calls %v, want [{7 5}]", calls)
}
for _, ch := range []string{"materials:5abc", "materials:05", "materials:0", "materials:5:x", "presence:materials:5", "materials:", "materials"} {
calls = nil
res := p.authorizeMaterial(ctx, 7, ch)
if res.Allowed {
t.Errorf("%q allowed", ch)
}
if res.Reason() != "malformed material channel" {
t.Errorf("%q: reason %q", ch, res.Reason())
}
if len(calls) != 0 {
t.Errorf("%q called the seam: %v", ch, calls)
}
}
if res := p.authorizeMaterial(ctx, 13, "materials:5"); res.Allowed || res.Reason() != "material lookup failed" {
t.Errorf("seam error: allowed %v, reason %q", res.Allowed, res.Reason())
}
if res := p.authorizeMaterial(ctx, 8, "materials:5"); res.Allowed || res.Reason() != "not the material's manager" {
t.Errorf("non-manager: allowed %v, reason %q", res.Allowed, res.Reason())
}
calls = nil
noDB := watchPlugin(t, true, watch)
if res := noDB.authorizeMaterial(ctx, 7, "materials:5"); res.Allowed || res.Reason() != "database unavailable" {
t.Errorf("no database: allowed %v, reason %q", res.Allowed, res.Reason())
}
if len(calls) != 0 {
t.Errorf("no database called the seam: %v", calls)
}
}