Rename mesh-control -> mesh-controller, substrate -> foundation
One name per thing, per the HQ glossary: the module/container/image/binary/repo becomes mesh-controller, the seat the-controller, and the store+broker pair the foundation (embedded base bundles, default template and example lock renamed with their go:embed directives). No behaviour change — a pure vocabulary rename. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/novox/mesh-controller/internal/inventory"
|
||||
)
|
||||
|
||||
// The shape something other than a person reads.
|
||||
//
|
||||
// Hard to change once anything is built against it, so it stays close to what the domain already
|
||||
// calls things and carries no summary field that would have to be kept true.
|
||||
|
||||
func statusOf(t *testing.T, wrong []inventory.Doing, nodes, quiet []inventory.Node,
|
||||
behind map[string][]string, sources map[string]inventory.Source) map[string]any {
|
||||
t.Helper()
|
||||
body, err := statusAsJSON(answers{
|
||||
wrong: wrong, nodes: nodes, quiet: quiet, behind: behind, sources: sources})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var parsed map[string]any
|
||||
if err := json.Unmarshal(body, &parsed); err != nil {
|
||||
t.Fatalf("what a board would read is not JSON: %v", err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func TestRefusedAndFailedStayDistinctAllTheWayOut(t *testing.T) {
|
||||
// They are fixed in different places, so one word for both would send half the readers of a
|
||||
// page to the wrong one.
|
||||
got := statusOf(t,
|
||||
[]inventory.Doing{
|
||||
{Node: "one", Outcome: inventory.OutcomeRefused, Refused: "a file needs a path"},
|
||||
{Node: "two", Outcome: inventory.OutcomeFailed, Applied: 3,
|
||||
Failed: []inventory.FailedResource{{ID: "shell.pkg", Error: "target not found"}}},
|
||||
},
|
||||
[]inventory.Node{{Name: "one"}, {Name: "two"}}, nil, nil, nil)
|
||||
|
||||
wrong, _ := got["wrong"].([]any)
|
||||
if len(wrong) != 2 {
|
||||
t.Fatalf("got %v", got["wrong"])
|
||||
}
|
||||
first, _ := wrong[0].(map[string]any)
|
||||
if first["outcome"] != inventory.OutcomeRefused || first["refused"] == nil {
|
||||
t.Fatalf("a refusal did not survive: %v", first)
|
||||
}
|
||||
second, _ := wrong[1].(map[string]any)
|
||||
if second["outcome"] != inventory.OutcomeFailed {
|
||||
t.Fatalf("a failure did not survive: %v", second)
|
||||
}
|
||||
if second["applied"] != float64(3) {
|
||||
// "Three of eight" and "none of eight" are different machines.
|
||||
t.Fatalf("what did apply was not carried: %v", second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAMachineThatNeverSpokeSaysSoByOmission(t *testing.T) {
|
||||
// Never heard from and quiet for a while are different situations, and a zero time would read
|
||||
// as a date in 1970 on any page that formatted it.
|
||||
got := statusOf(t, nil,
|
||||
[]inventory.Node{{Name: "silent"}, {Name: "away", LastSeen: time.Now().Add(-3 * time.Hour)}},
|
||||
[]inventory.Node{{Name: "silent"}, {Name: "away", LastSeen: time.Now().Add(-3 * time.Hour)}},
|
||||
nil, nil)
|
||||
|
||||
quiet, _ := got["quiet"].([]any)
|
||||
if len(quiet) != 2 {
|
||||
t.Fatalf("got %v", got["quiet"])
|
||||
}
|
||||
never, _ := quiet[0].(map[string]any)
|
||||
if _, said := never["lastSeen"]; said {
|
||||
t.Fatalf("a machine that never spoke carries a time: %v", never)
|
||||
}
|
||||
away, _ := quiet[1].(map[string]any)
|
||||
if _, said := away["lastSeen"]; !said {
|
||||
t.Fatalf("a machine that has been quiet carries no time: %v", away)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNothingWrongIsAnEmptyListRatherThanNothing(t *testing.T) {
|
||||
// A page distinguishing "no machines are wrong" from "this field is missing" would have to
|
||||
// handle both, and null is the one that gets forgotten.
|
||||
got := statusOf(t, nil, []inventory.Node{{Name: "a", LastSeen: time.Now()}}, nil, nil, nil)
|
||||
for _, key := range []string{"wrong", "quiet", "behind"} {
|
||||
list, ok := got[key].([]any)
|
||||
if !ok {
|
||||
t.Fatalf("%q is %T, not a list", key, got[key])
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Fatalf("%q is not empty: %v", key, list)
|
||||
}
|
||||
}
|
||||
// And how many machines there are, so a reader can tell "none wrong" from "none at all".
|
||||
if got["machines"] != float64(1) {
|
||||
t.Fatalf("got %v", got["machines"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestWhatIsBehindNamesTheMachinesRunningTheOldOne(t *testing.T) {
|
||||
// A module being out of date is a fact about the catalogue; machines running the old one is
|
||||
// the thing with consequences.
|
||||
got := statusOf(t, nil, nil, nil,
|
||||
map[string][]string{"shell": {"workstation", "laptop"}},
|
||||
map[string]inventory.Source{"shell": {BuiltFrom: "aaaaaaa1", Head: "bbbbbbb2"}})
|
||||
|
||||
behind, _ := got["behind"].([]any)
|
||||
if len(behind) != 1 {
|
||||
t.Fatalf("got %v", got["behind"])
|
||||
}
|
||||
row, _ := behind[0].(map[string]any)
|
||||
if row["module"] != "shell" || row["builtFrom"] != "aaaaaaa1" || row["head"] != "bbbbbbb2" {
|
||||
t.Fatalf("got %v", row)
|
||||
}
|
||||
on, _ := row["on"].([]any)
|
||||
if len(on) != 2 {
|
||||
t.Fatalf("the machines running the old one are not named: %v", row)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSecretIsInWhatABoardReads(t *testing.T) {
|
||||
// Everything here comes from the mesh's own records, which hold no readable secret — but a
|
||||
// shape a page is built against is exactly where one would eventually be added for
|
||||
// convenience, so this says it out loud.
|
||||
body, err := statusAsJSON(answers{
|
||||
wrong: []inventory.Doing{{Node: "a", Outcome: inventory.OutcomeRefused,
|
||||
Refused: "resource \"x\": a file needs a path"}},
|
||||
nodes: []inventory.Node{{Name: "a"}},
|
||||
refused: map[string]string{"a": "nothing provides \"database\", wanted by web"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, word := range []string{"password", "secret", "sealed", "credential", "token"} {
|
||||
if strings.Contains(strings.ToLower(string(body)), word) {
|
||||
t.Fatalf("what a board reads carries a %q field:\n%s", word, body)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user