119 lines
4.1 KiB
Go
119 lines
4.1 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"slices"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/announce"
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"github.com/nats-io/nats.go/jetstream"
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
"github.com/novox/mesh-controller/internal/testbus"
|
|
)
|
|
|
|
// D1-D3 whole against a real bus and the store (ADR 0495 checks §2, §3, §5; ADR 0513 §3; issue 1790): the controller
|
|
// says what it keeps and keeps what every module says; a reader of a state its owner announced readable is granted it,
|
|
// one its owner announced and did not make readable is refused and said, and one of an owner that announced nothing
|
|
// yet is granted as before and named as not yet announced.
|
|
func TestTheStatesAnnouncedGrantTheReads(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
inv := open.inventory
|
|
js, err := broker.Dial(testbus.URL(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(js.Close)
|
|
if err := broker.AssertMeshStreams(js); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := js.EnsureControllerBuckets(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
servingBus.Store(js)
|
|
t.Cleanup(func() { servingBus.Store(nil) })
|
|
was := inventory.Announcements
|
|
inventory.Announcements = readAnnouncements
|
|
t.Cleanup(func() { inventory.Announcements = was })
|
|
|
|
// The owner keeps two states, one readable; the reader reads both and a state of a module that says nothing.
|
|
register := func(m catalogue.Manifest) {
|
|
t.Helper()
|
|
if err := inv.RegisterModule(ctx, m, inventory.Source{Repository: "novox/mesh-catalog", Seat: "git",
|
|
Path: "modules/" + m.Module, BuiltFrom: "c0"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
register(catalogue.Manifest{Module: "owner", Version: "1", State: []catalogue.StateDeclaration{{Name: "open"}, {Name: "closed"}}})
|
|
register(catalogue.Manifest{Module: "quiet", Version: "1", State: []catalogue.StateDeclaration{{Name: "any"}}})
|
|
register(catalogue.Manifest{Module: "reader", Version: "1", Reads: []string{"owner.open", "owner.closed", "quiet.any"}})
|
|
if _, err := inv.AddNode(ctx, "one"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, m := range []string{"owner", "quiet", "reader"} {
|
|
if _, err := inv.Assign(ctx, "one", m); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
watching, stop := context.WithCancel(context.Background())
|
|
t.Cleanup(stop)
|
|
if err := announceOwnStates(ctx, js); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := keepAnnouncements(watching, js, open); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
api, _ := jetstream.New(js.Conn())
|
|
word, _ := announce.Encode(announce.States{Module: "owner", Node: "one",
|
|
States: []announce.State{{Name: "open", Readable: true}, {Name: "closed"}}})
|
|
if _, err := api.Publish(ctx, announce.Subject("owner"), word); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
becomes(t, 10*time.Second, "both words kept", func() bool {
|
|
a, err := readAnnouncements(ctx)
|
|
return err == nil && len(a) == 2 && a["owner"].Readable("open") && a[broker.ControllerSeat].Readable(broker.PlansBuilding)
|
|
})
|
|
|
|
records, err := inv.BusRecords(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var reader broker.Declared
|
|
for _, d := range records.Assigned["one"] {
|
|
if d.Module == "reader" {
|
|
reader = d
|
|
}
|
|
}
|
|
if !slices.Equal(reader.Reads, []string{"owner.open", "quiet.any"}) || !slices.Equal(reader.ReadsRefused, []string{"owner.closed"}) {
|
|
t.Fatalf("0495 §3: the reader is granted %v and refused %v", reader.Reads, reader.ReadsRefused)
|
|
}
|
|
if got := broker.NotAnnounced(records); !slices.Equal(got, []string{"quiet"}) {
|
|
t.Fatalf("not yet announced: %v", got)
|
|
}
|
|
users, err := broker.Users(records)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, u := range users {
|
|
if u.Kind != broker.KindModule || u.Module != "reader" {
|
|
continue
|
|
}
|
|
perms, err := broker.PermissionsFor(u)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if slices.ContainsFunc(perms.Publish, func(s string) bool { return s == "$JS.API.DIRECT.GET.KV_owner_closed.>" }) {
|
|
t.Fatal("0495 §3: the reader may read the state its owner did not announce readable")
|
|
}
|
|
if !slices.Contains(perms.Publish, "$JS.API.DIRECT.GET.KV_owner_open.>") {
|
|
t.Fatal("0495 §3: the reader may not read the state its owner announced readable")
|
|
}
|
|
}
|
|
}
|