Judge a have with no composition against the module's slice of the declaration the node last applied: equal is unchanged (issue 1945; ADR 0540 clause 9)
The first want at the switch skips the record hold only where it changes nothing on the node. A slice differing only in the bus's user list is marked user-list-only, so no yes waits on it at the switch; any other change at the same fingerprint is judged as any move, against the declaration's digest.
This commit is contained in:
@@ -7,6 +7,8 @@ import (
|
||||
"testing"
|
||||
|
||||
sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/link"
|
||||
)
|
||||
|
||||
// mailOn is a composition of mesh-mail on ace at fingerprint c, from the given resources, each saying its module.
|
||||
@@ -125,3 +127,86 @@ func TestAMoveIsJudgedAgainstWhatTheNodeRuns(t *testing.T) {
|
||||
t.Errorf("against a composition that is gone: %+v", v)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
busServer = `{"id":"nats.server","type":"container","module":"nats","name":"nats","image":"nats@sha256:4444444444444444444444444444444444444444444444444444444444444444"}`
|
||||
busServer2 = `{"id":"nats.server","type":"container","module":"nats","name":"nats","image":"nats@sha256:5555555555555555555555555555555555555555555555555555555555555555"}`
|
||||
busUsers = `{"id":"nats.bus-users","type":"file","module":"nats","path":"/etc/nats/users.conf","content":"users: [a]"}`
|
||||
busUsers2 = `{"id":"nats.bus-users","type":"file","module":"nats","path":"/etc/nats/users.conf","content":"users: [a, b]"}`
|
||||
)
|
||||
|
||||
// busOn is a composition of the bus on ace from the given resources.
|
||||
func busOn(t *testing.T, resources ...string) sdkdelivery.Composed {
|
||||
t.Helper()
|
||||
out := sdkdelivery.Composed{Node: "ace", Module: "nats", FP: sdkdelivery.SourcePrefix2 + strings.Repeat("b", 64)}
|
||||
for _, r := range resources {
|
||||
out.Resources = append(out.Resources, json.RawMessage(r))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ADR 0540 clause 9: a have that names no composition, only a fingerprint (the switch: the node runs the declaration it
|
||||
// last applied), is judged against the module's slice of that declaration, read from the kept stream of declarations:
|
||||
// an equal slice is unchanged; a slice differing only in the bus's user list is that (round 1's A2, so no yes waits on it at the switch); a changed setting is judged as any move; no declaration to read cannot be judged.
|
||||
func TestAHaveWithNoCompositionIsJudgedAgainstTheLastDeclaration(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
other := `{"id":"mesh-calendar.server","type":"container","module":"mesh-calendar","name":"calendar","image":"cal@sha256:3333333333333333333333333333333333333333333333333333333333333333"}`
|
||||
unsaid := `{"id":"mesh-mail.tools","type":"file","path":"/usr/lib/mesh-mail/tools.json","content":"a"}`
|
||||
declared := func(resources ...string) []byte {
|
||||
body, err := json.Marshal(map[string]any{"node": "ace", "resources": json.RawMessage("[" + strings.Join(resources, ",") + "]")})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signed, err := json.Marshal(link.Signed{Declaration: body, Signature: []byte("s")}) // as link.Envelope sent it
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return signed
|
||||
}
|
||||
cases := []struct {
|
||||
name string
|
||||
last []byte // the node's last declaration on the stream; nil when there is none
|
||||
to sdkdelivery.Composed
|
||||
want sdkdelivery.Judgement
|
||||
inWords string
|
||||
userList bool
|
||||
}{
|
||||
{"an equal slice", declared(mailContainer, other, mailSpool, mailTools), mailOn(t, 'b', true, mailContainer, mailSpool, mailTools), sdkdelivery.JudgedUnchanged, "last applied", false},
|
||||
{"a declared resource saying no module is not equal", declared(mailContainer, other, mailSpool, unsaid), mailOn(t, 'b', true, mailContainer, mailSpool, mailTools), sdkdelivery.JudgedNeither, "last applied", false},
|
||||
{"a changed image", declared(mailContainer, other, mailSpool, mailTools), mailOn(t, 'b', true, mailContainer2, mailSpool, mailTools), sdkdelivery.JudgedRecreates, "last applied", false},
|
||||
{"a changed setting in its spool", declared(mailContainer, mailSpool, mailConfig), mailOn(t, 'b', true, mailContainer, mailSpool, mailConfig2), sdkdelivery.JudgedMovesData, "last applied", false},
|
||||
{"a changed tools file", declared(mailContainer, mailSpool, mailTools), mailOn(t, 'b', true, mailContainer, mailSpool, mailTools2), sdkdelivery.JudgedNeither, "last applied", false},
|
||||
{"only the bus's user list", declared(busServer, busUsers, other), busOn(t, busServer, busUsers2), sdkdelivery.JudgedNeither, "only the bus's user list", true},
|
||||
{"the bus's user list and its container", declared(busServer, busUsers), busOn(t, busServer2, busUsers2), sdkdelivery.JudgedRecreates, "last applied", false},
|
||||
{"no declaration kept", nil, mailOn(t, 'b', true, mailContainer, mailSpool, mailTools), sdkdelivery.JudgedCannot, "names no composition", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
at, _, _, haves := aPlace(t, "ace")
|
||||
last := c.last
|
||||
at.lastApplied = func(_ context.Context, module string) ([]json.RawMessage, string, bool, error) {
|
||||
if last == nil {
|
||||
return nil, "", false, nil
|
||||
}
|
||||
return sliceOfDeclaration(last, module)
|
||||
}
|
||||
haves[c.to.Module] = sdkdelivery.Have{FP: sdkdelivery.SourcePrefix2 + strings.Repeat("a", 64), Phase: sdkdelivery.PhaseRunning, Health: sdkdelivery.HealthOK}
|
||||
key, _ := sdkdelivery.ComposedKey("ace", c.to.Module, c.to.FP)
|
||||
digest, err := sdkdelivery.ComposedDigestOf(c.to)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", c.name, err)
|
||||
}
|
||||
got, err := judgeMove(ctx, at, key, c.to, digest)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", c.name, err)
|
||||
}
|
||||
if got.UserListOnly != c.userList {
|
||||
t.Errorf("%s: user list only %v, want %v", c.name, got.UserListOnly, c.userList)
|
||||
}
|
||||
if got.Judgement != c.want || !strings.Contains(got.Words, c.inWords) {
|
||||
t.Errorf("%s: judged %s (%q), want %s", c.name, got.Judgement, got.Words, c.want)
|
||||
}
|
||||
if _, err := sdkdelivery.EncodeComposedDigest(got); err != nil {
|
||||
t.Errorf("%s: the judgement written is refused: %v", c.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user