Merge main (upgrade safety's declared packages, issue 1840) and pin the R4e mesh-sdk member's final head 875c680d, re-vendored here and in modules/route-proxy; the controller announces declared-packages readable (issue 1790, D1; E)

This commit is contained in:
2026-10-22 20:44:59 +02:00
34 changed files with 1133 additions and 28 deletions
+5 -2
View File
@@ -57,10 +57,13 @@ var (
// mesh-config publishes as its own (design 57 K3).
Predefined = Mirror{Name: broker.MirrorPredefined, Bucket: broker.PredefinedBucket,
Event: link.KeyPredefinedChanged}
// DeclaredPackages is each node's packages its modules declare, keyed by the node (ADR 0507 §5). It raises no event:
// the seat's emits, which the SDK states, do not name one, and a reader reads the bucket when it is asked.
DeclaredPackages = Mirror{Name: broker.MirrorDeclaredPackages, Bucket: broker.DeclaredPackagesBucket}
)
// Mirrors is every mirror this package writes, in the order they are written.
func Mirrors() []Mirror { return []Mirror{DeclaredConfig, Predefined} }
func Mirrors() []Mirror { return []Mirror{DeclaredConfig, Predefined, DeclaredPackages} }
// The changes an event says.
const (
@@ -251,7 +254,7 @@ func (w *Writer) put(ctx context.Context, key string, value []byte, before kept,
// say raises one write's event, tried once more when refused and then counted as lost.
func (w *Writer) say(ctx context.Context, key, change string, fields []string, revision uint64) {
if w.Announce == nil {
if w.Announce == nil || w.Mirror.Event == "" {
return
}
e := Event{Mirror: w.Mirror.Name, Key: key, Change: change, Fields: fields, Revision: revision, At: w.now().UTC()}
@@ -9,6 +9,7 @@ import (
"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"
)
@@ -246,3 +247,49 @@ func TestNatsARemovalWithoutTheLeaseRemovesNothing(t *testing.T) {
t.Errorf("the key was removed without the lease: %v", err)
}
}
// 1840/AC5 (ADR 0507 §5, ADR 0289 §1): the declared-packages mirror, keyed by the node, writes a node's value once; a second
// pass over the same declaration writes nothing (the bucket takes no message); a package newly declared changes the one key;
// a node gone removes its key. It raises no event: the seat's emits name none for it.
func TestNatsTheDeclaredPackagesMirrorWritesOnlyOnAChange(t *testing.T) {
js, api := aMirrorBus(t)
events := listen(t, js.Conn(), "mesh.seat."+broker.ControllerSeat+".event.>")
w := aWriter(t, js, api, DeclaredPackages)
ctx := t.Context()
value := func(node string, resources ...map[string]any) []byte {
t.Helper()
owner := map[string]string{}
for _, r := range resources {
owner[r["id"].(string)] = "web"
}
v, err := inventory.DeclaredPackagesValue(node, resources, owner)
if err != nil {
t.Fatal(err)
}
return v
}
curl := map[string]any{"id": "web.curl", "type": "package", "package": "curl"}
nano := map[string]any{"id": "web.nano", "type": "package", "package": "nano", "absent": true}
if r, err := w.Sync(ctx, map[string][]byte{"one": value("one", curl), "two": value("two")}); err != nil ||
r != (Result{Written: 2}) {
t.Fatalf("the first pass wrote %+v (%v)", r, err)
}
before := writes(t, api, DeclaredPackages.Bucket)
if r, err := w.Sync(ctx, map[string][]byte{"one": value("one", curl), "two": value("two")}); err != nil || r != (Result{}) {
t.Errorf("a pass over the same declarations wrote %+v (%v)", r, err)
}
if got := writes(t, api, DeclaredPackages.Bucket) - before; got != 0 {
t.Errorf("a pass over the same declarations put %d messages in the bucket", got)
}
if r, err := w.Sync(ctx, map[string][]byte{"one": value("one", curl, nano), "two": value("two")}); err != nil ||
r != (Result{Written: 1}) {
t.Errorf("a package newly declared wrote %+v (%v)", r, err)
}
if r, err := w.Sync(ctx, map[string][]byte{"one": value("one", curl, nano)}); err != nil || r != (Result{Removed: 1}) {
t.Errorf("a node gone wrote %+v (%v)", r, err)
}
if said := settle(events, 1); len(said) != 0 {
t.Errorf("the declared-packages mirror raised %+v", said)
}
}