Files
mesh-controller/internal/catalogue/collections_test.go
T

180 lines
9.9 KiB
Go

package catalogue
import (
"reflect"
"strings"
"testing"
)
// A collection is declared and filled by the client (novox/hq ADR 0349 §13, design 57 L1, issue 684): a collector
// names a collection it collects, a contributor an item from a template of its own, and a handed composition plans
// both for the node's provisioner client and renders neither. The three old namespaces read as collections of their
// own name. Each file is filled one way: a piece of the other form on the machine is said as not placed.
const (
collectorZsh = `{"module":"zsh","version":"1","moved":true,
"claims":[{"name":"node-login-shell","scope":"node"}],
"collections":[{"name":"widgets","comment":"#"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]},
"resources":[{"id":"rc","type":"file","path":"${machine:account-home}/.zshrc","owner":"${machine:account}",
"mode":"0644","template":"files/zshrc"}]}`
zshrcText = "# zsh\n${shell:zsh:normal}${collected:widgets}"
contributorText = "source ${machine:account-home}/.p10k.zsh\n"
contributorP10k = `{"module":"prompt","version":"1","moved":true,
"items":[{"collection":"shell:zsh:normal","template":"files/zsh"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}`
oldFormAliases = `{"module":"aliases","version":"1",
"shell":[{"for":"zsh","slot":"normal","code":"alias ll='ls -l'\n"}]}`
)
func builtWith(module string, texts map[string]string) []Built {
return []Built{{Name: "files", Kind: ArtifactArchive,
Reference: ArtifactStoreScheme + module + "/files/blobs/sha256:" + strings.Repeat("e", 64),
Digest: "sha256:" + strings.Repeat("e", 64), Texts: texts}}
}
func collectionsOn(t *testing.T) Resolution {
t.Helper()
zsh := held(t, collectorZsh, builtWith("zsh", map[string]string{"zshrc": zshrcText}))
prompt := held(t, contributorP10k, builtWith("prompt", map[string]string{"zsh": contributorText}))
aliases, err := ParseManifest([]byte(oldFormAliases))
if err != nil {
t.Fatal(err)
}
r, err := Resolve(shelf(zsh, prompt, aliases), []string{"zsh", "prompt", "aliases"}, workstation(), World{})
if err != nil {
t.Fatal(err)
}
r.Account = "op"
return r
}
func TestAContributorsBuildKeepsItsItemsTemplateAndText(t *testing.T) {
m := held(t, contributorP10k, builtWith("prompt", map[string]string{"zsh": contributorText}))
if m.Handed == nil || !reflect.DeepEqual(m.Handed.Items, map[string]string{"shell:zsh:normal": "zsh"}) {
t.Fatalf("the build kept %+v", m.Handed)
}
if !reflect.DeepEqual(m.Items, []Item{{Collection: "shell:zsh:normal", Content: contributorText}}) {
t.Fatalf("the held items are %+v: the template's text, read back", m.Items)
}
}
func TestAHandedCollectorAndContributorArePlannedAndNeitherIsRendered(t *testing.T) {
c, got := composeWith(t, collectionsOn(t), handingTo("store:5000"))
if strings.Contains(got, ".p10k.zsh") || strings.Contains(got, "alias ll") {
t.Fatalf("the controller rendered a contribution into a handed collector: %s", got)
}
zsh, prompt := c.Plans["zsh"], c.Plans["prompt"]
wantCollections := []PlanCollection{{Name: "shell:zsh:normal", Comment: "#"}, {Name: "widgets", Comment: "#"}}
if !reflect.DeepEqual(zsh.Collections, wantCollections) || len(zsh.Items) != 0 {
t.Fatalf("zsh's plan collects %+v and contributes %+v", zsh.Collections, zsh.Items)
}
if !reflect.DeepEqual(prompt.Items, []PlanItem{{Collection: "shell:zsh:normal", Template: "zsh"}}) ||
len(prompt.Files) != 0 || prompt.Placement["machine:account-home"] != "/home/op" {
t.Fatalf("prompt's plan is %+v: its item, by template, and the placement its template names", prompt)
}
// The old form on the same machine is not placed, and said so.
if len(c.Unplaced) != 1 || !strings.Contains(c.Unplaced[0], "aliases's shell:zsh:normal is not placed") {
t.Fatalf("unplaced: %v", c.Unplaced)
}
}
// A collector filled the old way holds the old forms and each moved contributor's item, rendered from the text the
// mesh holds as its old form was (design 57 L2, issue 681), so the file loses no line where nothing is handed; a
// collection of the new form stays empty.
func TestACollectorFilledTheOldWayHoldsTheOldFormsAndEachHeldItem(t *testing.T) {
c, got := composeWith(t, collectionsOn(t), Rendering{ArtifactStore: "store:5000"})
if c.Plans != nil {
t.Fatalf("handed on a machine that cannot take it: %v", c.Plans)
}
if !strings.Contains(got, `"content":"# zsh\n# aliases\nalias ll='ls -l'\n# prompt\nsource /home/op/.p10k.zsh\n"`) {
t.Fatalf("the old way does not hold the old forms and the held item in module order: %s", got)
}
if len(c.Unplaced) != 0 {
t.Fatalf("unplaced: %v", c.Unplaced)
}
}
// An item the controller cannot render the old way (it names a value but a machine fact) is said as not placed.
func TestAHeldItemNamingMoreThanAFactIsSaidNotPlacedTheOldWay(t *testing.T) {
zsh := held(t, collectorZsh, builtWith("zsh", map[string]string{"zshrc": zshrcText}))
if _, ok := heldItemText(Manifest{Module: "p", Items: []Item{{Collection: "shell:zsh:normal",
Content: "export THEME=${config:theme}\n"}}}, "shell:zsh:normal", map[string]string{}); ok {
t.Fatal("an item naming a config value was rendered by the controller")
}
if _, ok := heldItemText(Manifest{Module: "p", Items: []Item{{Collection: "shell:zsh:normal",
Content: "cd ${machine:account-home}\n"}}}, "shell:zsh:normal", map[string]string{}); ok {
t.Fatal("an item naming a fact this machine lacks was rendered")
}
if _, ok := heldItemText(Manifest{Module: "p", Items: []Item{{Collection: "widgets", Content: "x\n"}}},
"widgets", nil); ok {
t.Fatal("an item of a collection of the new form was rendered the old way")
}
left := itemsLeftOut([]Manifest{zsh, {Module: "p", Items: []Item{{Collection: "shell:zsh:normal",
Content: "export THEME=${config:theme}\n"}}}}, zsh, "shell:zsh:normal", map[string]string{})
if len(left) != 1 || !strings.Contains(left[0], "p's item of shell:zsh:normal is not placed") {
t.Fatalf("left out: %v", left)
}
}
// Each old namespace L2 moves renders a moved contributor's item exactly as its old form did, where the collector is
// not handed: the same contributor written both ways composes the same bytes (design 57 L2, issue 681).
func TestAMovedContributorsItemRendersAsItsOldFormDid(t *testing.T) {
code := "# two lines\nalias a=b"
asOld := Manifest{Module: "laptop", Shell: []ShellCode{{For: "zsh", Slot: "normal", Code: code}},
Contributions: []SeatContribution{{Seat: HotkeysSeat, Kind: "trigger", Content: "KEY_F21 1 touchpad\n"}}}
asItem := Manifest{Module: "laptop", Moved: true, Items: []Item{{Collection: "shell:zsh:normal", Content: code},
{Collection: "contribution:node-hotkeys:trigger", Content: "KEY_F21 1 touchpad\n"}}}
other := Manifest{Module: "zz-other", Shell: []ShellCode{{For: "zsh", Slot: "normal", Code: "x=1\n"}},
Contributions: []SeatContribution{{Seat: HotkeysSeat, Kind: "trigger", Content: "KEY_MUTE 1 mute\n"}}}
first := Manifest{Module: "aa-first", Shell: []ShellCode{{For: "zsh", Slot: "normal", Code: "y=2\n"}}}
for _, mods := range [][]Manifest{{other, first}, {}} {
was := append(append([]Manifest(nil), mods...), asOld)
is := append(append([]Manifest(nil), mods...), asItem)
if a, b := shellCodeOn(was, "zsh", "normal", nil), shellCodeOn(is, "zsh", "normal", nil); a != b || a == "" {
t.Errorf("shell: the old form made %q, the item %q", a, b)
}
a, _, errA := seatContributions(was, hotkeysHolder(), "node-hotkeys:trigger", Rendering{}, nil, nil)
b, left, errB := seatContributions(is, hotkeysHolder(), "node-hotkeys:trigger", Rendering{}, nil, nil)
if errA != nil || errB != nil || a != b || a == "" || len(left) != 0 {
t.Errorf("hotkeys: the old form made %q, the item %q (%v %v %v)", a, b, errA, errB, left)
}
}
}
func TestCollectionsAndItemsAreJudged(t *testing.T) {
for name, c := range map[string]struct{ raw, says string }{
"an item of a module not moved": {`{"module":"m","version":"1",
"items":[{"collection":"shell:zsh:normal","template":"files/x"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}`, "is marked moved"},
"two items to one collection": {`{"module":"m","version":"1","moved":true,
"items":[{"collection":"a","template":"files/x"},{"collection":"a","template":"files/y"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}`, "contributes to a twice"},
"an item to no slot": {`{"module":"m","version":"1","moved":true,
"items":[{"collection":"shell:zsh:middle","template":"files/x"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}`, "is no slot"},
"an item outside the templates": {`{"module":"m","version":"1","moved":true,
"items":[{"collection":"a","template":"x"}],
"build":{"artifacts":[{"name":"files","kind":"archive","from":"files"}]}}`, "is not a file under files/"},
"an item naming a secret": {`{"module":"m","version":"1",
"items":[{"collection":"a","content":"t=${secret:token}"}]}`, "where no secret is"},
"a collection not declared": {`{"module":"m","version":"1",
"resources":[{"id":"f","type":"file","path":"/f","content":"${collected:a}"}]}`, "does not collect"},
"an old namespace declared": {`{"module":"m","version":"1","collections":[{"name":"shell:zsh:normal"}],
"resources":[{"id":"f","type":"file","path":"/f","content":"x"}]}`, "read from its placeholder"},
"a collection placed nowhere": {`{"module":"m","version":"1","collections":[{"name":"a"}],
"resources":[{"id":"f","type":"file","path":"/f","content":"x"}]}`, "no file of its places it"},
"a collection in a path": {`{"module":"m","version":"1","collections":[{"name":"a"}],
"resources":[{"id":"f","type":"file","path":"/${collected:a}","content":"${collected:a}"}]}`,
"only in a file's content"},
} {
_, err := ParseManifest([]byte(c.raw))
if err == nil || !strings.Contains(err.Error(), c.says) {
t.Errorf("%s: %v, want it to say %q", name, err, c.says)
}
}
if _, err := ParseManifest([]byte(collectorZsh)); err != nil {
t.Errorf("a collector: %v", err)
}
}