Its want names a composition (ADR 0539 clauses 1 and 6), so a module whose needs others meet must still have one at its fingerprint, or no want could ever be written for it. Found by the served test.
130 lines
5.7 KiB
Go
130 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
|
"github.com/novox/mesh-controller/internal/builderkeys"
|
|
)
|
|
|
|
// stepsFor are doneKeySteps over a module registered at registered, whose trunk value names fp at commit, assigned to
|
|
// nodes, the bus held on holder; every act is written to acts in order.
|
|
func stepsFor(acts *[]string, registered, commit, fp string, nodes []string, holder string) doneKeySteps {
|
|
return doneKeySteps{
|
|
held: func(_ context.Context, module string) (bool, error) { return module == "mesh-mail", nil },
|
|
trunk: func(context.Context, string) (sdkdelivery.Module, error) {
|
|
if fp == "" {
|
|
return sdkdelivery.Module{}, builderkeys.ErrNoValue
|
|
}
|
|
return sdkdelivery.Module{Commit: commit, FP2: fp}, nil
|
|
},
|
|
registeredAt: func(_ context.Context, _ string, c string) (bool, error) { return c == registered, nil },
|
|
takeIn: func(_ context.Context, module string, trunk sdkdelivery.Module) error {
|
|
*acts = append(*acts, "take in "+module+" at "+trunk.Commit)
|
|
return nil
|
|
},
|
|
nodesOf: func(context.Context, string) ([]string, error) { return nodes, nil },
|
|
busHolder: func(context.Context) (string, error) { return holder, nil },
|
|
compose: func(_ context.Context, ns []string) error {
|
|
*acts = append(*acts, "compose "+strings.Join(ns, ","))
|
|
return nil
|
|
},
|
|
grants: func(context.Context) error { *acts = append(*acts, "grants"); return nil },
|
|
}
|
|
}
|
|
|
|
// 1945/AC3 (unit half): a done key of a new fingerprint of an assigned module is taken in, then the module's nodes are
|
|
// composed, then the node holding the bus (its user list), then the grants: the grant and the composition exist
|
|
// before the assigner's rules let a want name the fingerprint. A module registered at the trunk's commit already is
|
|
// composed and granted without a second take-in; one assigned nowhere, unregistered, or with no trunk value is left
|
|
// alone.
|
|
func TestADoneKeyIsTakenInComposedAndGranted(t *testing.T) {
|
|
fp := sdkdelivery.SourcePrefix2 + strings.Repeat("c", 64)
|
|
var acts []string
|
|
said, err := stepsFor(&acts, "old", "new", fp, []string{"ace", "g14"}, "novox").take(context.Background(), "mesh-mail")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := strings.Join(acts, "; "); got != "take in mesh-mail at new; compose ace,g14; compose novox; grants" {
|
|
t.Errorf("the acts were %q", got)
|
|
}
|
|
if !strings.Contains(said, "registered from the builder's done key") {
|
|
t.Errorf("said %q", said)
|
|
}
|
|
|
|
acts = nil
|
|
if _, err := stepsFor(&acts, "new", "new", fp, []string{"novox"}, "novox").take(context.Background(), "mesh-mail"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := strings.Join(acts, "; "); got != "compose novox; grants" {
|
|
t.Errorf("a module registered at its trunk already: %q", got)
|
|
}
|
|
|
|
for name, s := range map[string]doneKeySteps{
|
|
"assigned nowhere": stepsFor(&acts, "old", "new", fp, nil, "novox"),
|
|
"no trunk value": stepsFor(&acts, "old", "new", "", []string{"ace"}, "novox"),
|
|
} {
|
|
acts = nil
|
|
if _, err := s.take(context.Background(), "mesh-mail"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if name == "assigned nowhere" && strings.Join(acts, "; ") != "take in mesh-mail at new" {
|
|
t.Errorf("%s: %v", name, acts)
|
|
}
|
|
if name == "no trunk value" && len(acts) != 0 {
|
|
t.Errorf("%s: %v", name, acts)
|
|
}
|
|
}
|
|
acts = nil
|
|
if _, err := stepsFor(&acts, "old", "new", fp, []string{"ace"}, "novox").take(context.Background(), "unknown"); err != nil || len(acts) != 0 {
|
|
t.Errorf("a module the catalogue does not hold: %v %v", acts, err)
|
|
}
|
|
}
|
|
|
|
// 1945/AC4: the bus's user list is a file of the bus module's composition (ADR 0539 clause 7): a change of the composed
|
|
// users is a new revision of that composition alone, every other composition of the node keeping its digest.
|
|
func TestAChangedUserListIsANewRevisionOfTheBusModulesCompositionAlone(t *testing.T) {
|
|
body, fps := capturedBody(t, "g14")
|
|
fps["nats"] = sdkdelivery.SourcePrefix2 + strings.Repeat("e", 64)
|
|
withUsers := func(users string) map[string]sdkdelivery.Composed {
|
|
var d map[string]any
|
|
if err := json.Unmarshal(body, &d); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// As the composer writes it for the module holding mesh-broker (mesh-sdk catalogue: BusUsersID, owned by the module).
|
|
d["resources"] = append(d["resources"].([]any), map[string]any{"id": "nats.bus-users", "type": "file",
|
|
"module": "nats", "path": "/var/lib/mesh/nats/users.conf", "content": users, "mode": "0600"})
|
|
raw, _ := json.Marshal(d)
|
|
comps, _, err := compositionsOf("g14", raw, fps, nil, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return comps
|
|
}
|
|
before, after := withUsers("authorization { users = [ {user: a} ] }\n"), withUsers("authorization { users = [ {user: a}, {user: b} ] }\n")
|
|
natsKey, _ := sdkdelivery.ComposedKey("g14", "nats", fps["nats"])
|
|
for key, c := range before {
|
|
d1, _ := sdkdelivery.ComposedDigestOf(c)
|
|
d2, _ := sdkdelivery.ComposedDigestOf(after[key])
|
|
if changed := d1 != d2; changed != (key == natsKey) {
|
|
t.Errorf("%s changed %v; only the bus module's composition changes with its user list", key, changed)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1945 (the review's D1): a grant that is not written is the take-in's error, never swallowed: with no send left,
|
|
// nothing else would write it, and no want could name the fingerprint.
|
|
func TestAGrantNotWrittenIsTheTakeInsError(t *testing.T) {
|
|
fp := sdkdelivery.SourcePrefix2 + strings.Repeat("c", 64)
|
|
var acts []string
|
|
s := stepsFor(&acts, "old", "new", fp, []string{"ace"}, "novox")
|
|
s.grants = func(context.Context) error { return errors.New("the bucket mesh-controller_grants: not found") }
|
|
if _, err := s.take(context.Background(), "mesh-mail"); err == nil || !strings.Contains(err.Error(), "grants") {
|
|
t.Errorf("a grant not written: %v", err)
|
|
}
|
|
}
|