A provider waiting for a yes said why only in its have's words; nobody could read the composition that waits beside what runs. The engine's read verb composition answers that, and ChangedResources lists what a move changes, a received file naming the consumers that join or leave.
95 lines
7.1 KiB
Go
95 lines
7.1 KiB
Go
package delivery
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func composedOf(module string, c byte, data bool, resources ...string) Composed {
|
|
out := Composed{Node: "ace", Module: module, FP: SourcePrefix2 + strings.Repeat(string(c), 64), Data: data}
|
|
for _, r := range resources {
|
|
out.Resources = append(out.Resources, json.RawMessage(r))
|
|
}
|
|
return out
|
|
}
|
|
|
|
// The pairs mesh-controller's composed_judge_test.go captured (issue 1945 AC12), and the bus's user list, judged as the
|
|
// controller judges them (ADR 0377 §3, ADR 0539 §7), by the node agent's function (ADR 0547 §3, issue 1126 S8).
|
|
func TestJudgeMove(t *testing.T) {
|
|
const (
|
|
container = `{"id":"mesh-mail.server","type":"container","module":"mesh-mail","name":"mail","image":"mail@sha256:1111111111111111111111111111111111111111111111111111111111111111","volumes":["/var/lib/mesh-mail/spool:/spool"]}`
|
|
container2 = `{"id":"mesh-mail.server","type":"container","module":"mesh-mail","name":"mail","image":"mail@sha256:2222222222222222222222222222222222222222222222222222222222222222","volumes":["/var/lib/mesh-mail/spool:/spool"]}`
|
|
spool = `{"id":"mesh-mail.spool","type":"directory","module":"mesh-mail","path":"/var/lib/mesh-mail/spool"}`
|
|
spoolMoved = `{"id":"mesh-mail.spool","type":"directory","module":"mesh-mail","path":"/srv/mesh-mail/spool"}`
|
|
tools = `{"id":"mesh-mail.tools","type":"file","module":"mesh-mail","path":"/usr/lib/mesh-mail/tools.json","content":"a"}`
|
|
tools2 = `{"id":"mesh-mail.tools","type":"file","module":"mesh-mail","path":"/usr/lib/mesh-mail/tools.json","content":"b"}`
|
|
config = `{"id":"mesh-mail.conf","type":"file","module":"mesh-mail","path":"/var/lib/mesh-mail/spool/conf","content":"a"}`
|
|
config2 = `{"id":"mesh-mail.conf","type":"file","module":"mesh-mail","path":"/var/lib/mesh-mail/spool/conf","content":"b"}`
|
|
process = `{"id":"mesh-mail.daemon","type":"process","module":"mesh-mail","exec":"/usr/bin/a"}`
|
|
process2 = `{"id":"mesh-mail.daemon","type":"process","module":"mesh-mail","exec":"/usr/bin/b"}`
|
|
received = `{"id":"mesh-mail.received-smtp","type":"file","module":"mesh-mail","path":"/var/lib/mesh-mail/spool/received.json","content":"{\"given\":[{\"from\":\"cloud\",\"node\":\"novox\"},{\"from\":\"photos\",\"node\":\"novox\"}]}"}`
|
|
received2 = `{"id":"mesh-mail.received-smtp","type":"file","module":"mesh-mail","path":"/var/lib/mesh-mail/spool/received.json","content":"{\"given\":[{\"from\":\"photos\",\"node\":\"novox\"},{\"from\":\"wiki\",\"node\":\"ace\"}]}"}`
|
|
users = `{"id":"nats.bus-users","type":"file","module":"nats","path":"/etc/nats/users","content":"a"}`
|
|
users2 = `{"id":"nats.bus-users","type":"file","module":"nats","path":"/etc/nats/users","content":"b"}`
|
|
natsConf = `{"id":"nats.conf","type":"file","module":"nats","path":"/etc/nats/conf","content":"a"}`
|
|
natsConf2 = `{"id":"nats.conf","type":"file","module":"nats","path":"/etc/nats/conf","content":"b"}`
|
|
)
|
|
mail := func(c byte, data bool, rs ...string) *Composed {
|
|
m := composedOf("mesh-mail", c, data, rs...)
|
|
return &m
|
|
}
|
|
bus := func(rs ...string) *Composed { m := composedOf("nats", 'b', false, rs...); return &m }
|
|
for _, c := range []struct {
|
|
name string
|
|
from, to *Composed
|
|
want Judgement
|
|
userList bool
|
|
words string // what the words must say, when given
|
|
}{
|
|
{"a new image", mail('a', true, container, spool, tools), mail('b', true, container2, spool, tools), JudgedRecreates, false, ""},
|
|
{"a container gone", mail('a', true, container, spool), mail('b', true, spool), JudgedRecreates, false, ""},
|
|
{"its spool moved", mail('a', true, container, spool), mail('b', true, container, spoolMoved), JudgedMovesData, false, ""},
|
|
{"a file in its spool", mail('a', true, container, spool, config), mail('b', true, container, spool, config2), JudgedMovesData, false, "it changes where its data is kept: mesh-mail.conf"},
|
|
// A received file the mesh makes, in its data's place, names its consumers joining or leaving, not its data moving
|
|
// (issue 774, 2026-10-31: postgres asked a yes for "where its data is kept" when nextcloud left its grants).
|
|
{"a consumer leaves", mail('a', true, container, spool, received), mail('b', true, container, spool, received2), JudgedMovesData, false,
|
|
"consumers join or leave: cloud on novox leaves smtp, wiki on ace joins smtp"},
|
|
{"a consumer leaves and a file moves", mail('a', true, container, spool, received, config), mail('b', true, container, spool, received2, config2), JudgedMovesData, false,
|
|
"it changes where its data is kept: mesh-mail.conf; consumers join or leave: cloud on novox leaves smtp, wiki on ace joins smtp"},
|
|
{"its data flag alone", mail('a', false, container, spool), mail('b', true, container, spool), JudgedNeither, false, ""},
|
|
{"its data flag and its spool", mail('a', false, container, spool), mail('b', true, container, spoolMoved), JudgedMovesData, false, ""},
|
|
{"a process of a module with data", mail('a', true, spool, process), mail('b', true, spool, process2), JudgedMovesData, false, ""},
|
|
{"a process of a module without", mail('a', false, process), mail('b', false, process2), JudgedNeither, false, ""},
|
|
{"its tools only", mail('a', true, container, spool, tools), mail('b', true, container, spool, tools2), JudgedNeither, false, ""},
|
|
{"never ran", nil, mail('b', true, container), JudgedNeither, false, ""},
|
|
{"equal, written otherwise", mail('a', true, `{"type":"directory","id":"mesh-mail.spool","module":"mesh-mail","path":"/var/lib/mesh-mail/spool"}`), mail('b', true, spool), JudgedUnchanged, false, ""},
|
|
{"only the user list", bus(natsConf, users), bus(natsConf, users2), JudgedNeither, true, ""},
|
|
{"the user list and more", bus(natsConf, users), bus(natsConf2, users2), JudgedNeither, false, ""},
|
|
} {
|
|
got := JudgeMove(c.from, *c.to)
|
|
if got.Judgement != c.want || got.UserListOnly != c.userList || got.Words == "" {
|
|
t.Errorf("%s: %+v, want %s (user list only %v)", c.name, got, c.want, c.userList)
|
|
}
|
|
if c.words != "" && got.Words != c.words {
|
|
t.Errorf("%s: says %q, want %q", c.name, got.Words, c.words)
|
|
}
|
|
if strings.Contains(c.name, "data flag alone") && !strings.Contains(got.Words, "WARNING: its data flag differs") {
|
|
t.Errorf("%s: the flag's difference is not said: %q", c.name, got.Words)
|
|
}
|
|
}
|
|
// The resources that differ, as the engine's verb composition lists them (issue 774): a provider's received file
|
|
// names its consumers, a file changed and one added are said as such, and nothing equal is listed.
|
|
changes := ChangedResources(mail('a', true, container, spool, received, config), *mail('b', true, container, spool, received2, config2, tools))
|
|
if want := `[{mesh-mail.conf file changed []} {mesh-mail.received-smtp file changed [cloud on novox leaves smtp wiki on ace joins smtp]} {mesh-mail.tools file added []}]`; fmt.Sprint(changes) != want {
|
|
t.Errorf("changed resources: %v, want %s", changes, want)
|
|
}
|
|
if got := ChangedResources(nil, *mail('b', true, spool)); len(got) != 1 || got[0].Change != "added" {
|
|
t.Errorf("never ran: %v, want its one resource added", got)
|
|
}
|
|
if got := JudgeMove(nil, Composed{Node: "ace"}); got.Judgement != JudgedNeither {
|
|
t.Errorf("the node's own composition: %+v", got)
|
|
}
|
|
}
|