- 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
83 lines
2.5 KiB
Go
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)
|
|
}
|
|
}
|