193 lines
8.5 KiB
Go
193 lines
8.5 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// The session environment's collection (design 57 L3, issue 795), filled by this client from typed items, is what the
|
|
// controller composed from the old forms before the move. testdata/environment holds that composition for a machine
|
|
// with the five contributors and for one with zsh alone; mesh-controller's internal/catalogue
|
|
// TestTheEnvironmentOfTheCatalogueIsTheSameHandedOrNot holds the not handed half against the same files.
|
|
|
|
type envItem struct{ module, name, kind, attr, value string }
|
|
|
|
// theCataloguesEnvironment is the five contributors' environment as the catalogue declared it before the move.
|
|
var theCataloguesEnvironment = []envItem{
|
|
{"adwaita", "gtk-theme", "variable", "GTK_THEME", "Adwaita:dark"},
|
|
{"adwaita", "gtk2-rc-files", "variable", "GTK2_RC_FILES", "/usr/share/themes/Adwaita-dark/gtk-2.0/gtkrc"},
|
|
{"adwaita", "qt-qpa-platformtheme", "variable", "QT_QPA_PLATFORMTHEME", "qt6ct"},
|
|
{"adwaita", "qt-style-override", "variable", "QT_STYLE_OVERRIDE", "Fusion"},
|
|
{"adwaita", "qt-select", "variable", "QT_SELECT", "6"},
|
|
{"adwaita", "xcursor-theme", "variable", "XCURSOR_THEME", "Adwaita"},
|
|
{"adwaita", "xcursor-size", "variable", "XCURSOR_SIZE", "24"},
|
|
{"clipmenu", "cm-selections", "variable", "CM_SELECTIONS", "clipboard"},
|
|
{"clipmenu", "cm-max-clips", "variable", "CM_MAX_CLIPS", "500"},
|
|
{"clipmenu", "cm-histlength", "variable", "CM_HISTLENGTH", "15"},
|
|
{"i3", "xdg-current-desktop", "variable", "XDG_CURRENT_DESKTOP", "i3"},
|
|
{"i3", "xdg-session-desktop", "variable", "XDG_SESSION_DESKTOP", "i3"},
|
|
{"xterm", "terminal", "variable", "TERMINAL", "xterm"},
|
|
{"zsh", "editor", "variable", "EDITOR", "vim"},
|
|
{"zsh", "visual", "variable", "VISUAL", "vim"},
|
|
{"zsh", "xdg-config-home", "variable", "XDG_CONFIG_HOME", "${machine:account-home}/.config"},
|
|
{"zsh", "path-1", "path:10", "", "${machine:account-home}/.local/bin"},
|
|
{"zsh", "path-2", "path:20", "", "${machine:account-home}/scripts"},
|
|
{"zsh", "path-3", "path:30", "", "${machine:account-home}/scripts/bin"},
|
|
}
|
|
|
|
func envPlans(t *testing.T, items []envItem) (collector Plan, contributors map[string]Plan) {
|
|
t.Helper()
|
|
posix := "# header\n${collected:environment:posix}"
|
|
systemd := "${environment:systemd}"
|
|
tpl, _ := templates(t, map[string]string{"posix": posix, "systemd": systemd})
|
|
facts := map[string]string{"machine:account-home": "/home/op"}
|
|
collector = Plan{Templates: tpl, Placement: facts,
|
|
Files: []PlannedFile{{ID: "posix", Path: "/env/environment.sh", Template: "posix", OwnerAtRuntime: "owned"},
|
|
{ID: "systemd", Path: "/env/50-mesh.conf", Template: "systemd", OwnerAtRuntime: "owned"}},
|
|
Collections: []PlannedCollection{{Name: "environment", Comment: "#"}}}
|
|
texts := map[string]map[string]string{}
|
|
planned := map[string][]PlannedItem{}
|
|
for _, it := range items {
|
|
if texts[it.module] == nil {
|
|
texts[it.module] = map[string]string{}
|
|
}
|
|
texts[it.module]["env-"+it.name] = it.value + "\n"
|
|
attrs := map[string]string{"kind": "variable", "name": it.attr}
|
|
if strings.HasPrefix(it.kind, "path") {
|
|
attrs = map[string]string{"kind": "path", "at": "start", "order": strings.TrimPrefix(it.kind, "path:")}
|
|
}
|
|
planned[it.module] = append(planned[it.module], PlannedItem{Collection: "environment", Name: it.name,
|
|
Attributes: attrs, Template: "env-" + it.name})
|
|
}
|
|
contributors = map[string]Plan{}
|
|
for m := range texts {
|
|
tp, _ := templates(t, texts[m])
|
|
contributors[m] = Plan{Templates: tp, Items: planned[m], Placement: facts}
|
|
}
|
|
return collector, contributors
|
|
}
|
|
|
|
func TestNatsTheEnvironmentFilledFromTypedItemsIsWhatTheOldContributionMade(t *testing.T) {
|
|
for name, only := range map[string]string{"all": "", "zsh": "zsh"} {
|
|
t.Run(name, func(t *testing.T) {
|
|
var items []envItem
|
|
for _, it := range theCataloguesEnvironment {
|
|
if only == "" || it.module == only {
|
|
items = append(items, it)
|
|
}
|
|
}
|
|
collector, contributors := envPlans(t, items)
|
|
b := startBus(t)
|
|
e := startEngine(t, map[string]string{"/env/environment.sh": "owned", "/env/50-mesh.conf": "owned"})
|
|
b.assign(t, "node-env", collector)
|
|
for m, p := range contributors {
|
|
b.assign(t, m, p)
|
|
}
|
|
aClient(t, b, e, t.TempDir(), time.Hour)
|
|
for file, golden := range map[string]string{"/env/environment.sh": "posix", "/env/50-mesh.conf": "systemd"} {
|
|
want, err := os.ReadFile(filepath.Join("testdata", "environment", name+"."+golden))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
prefix := ""
|
|
if golden == "posix" {
|
|
prefix = "# header\n"
|
|
}
|
|
eventually(t, file+" is what it was", func() bool { return e.read(t, file) == prefix+string(want) })
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTheEnvironmentRefusesAVariableTwoModulesSetAndAColonOnPATH(t *testing.T) {
|
|
items := map[string]itemValue{
|
|
"a": {text: "1\n", attributes: map[string]string{"kind": "variable", "name": "X"}},
|
|
"b": {text: "2\n", attributes: map[string]string{"kind": "variable", "name": "X"}},
|
|
}
|
|
if _, err := environmentText(items, EnvironmentPOSIX); err == nil || !strings.Contains(err.Error(), "both set X") {
|
|
t.Fatalf("two modules setting X: %v", err)
|
|
}
|
|
items = map[string]itemValue{"a": {text: "/x:/y\n", attributes: map[string]string{"kind": "path", "at": "end"}}}
|
|
if _, err := environmentText(items, EnvironmentSystemd); err == nil || !strings.Contains(err.Error(), "colon") {
|
|
t.Fatalf("a colon on PATH: %v", err)
|
|
}
|
|
if !attributeFits("environment", "name", "GTK_THEME") || attributeFits("shell:zsh:normal", "name", "GTK_THEME") {
|
|
t.Fatal("an upper-case name is the environment's alone")
|
|
}
|
|
}
|
|
|
|
// The catalogue's own modules, as they are declared now: node-env's two files and the five contributors' items, read
|
|
// from their module.json and templates, fill to the files the old form composed (issue 795).
|
|
func TestNatsTheEnvironmentOfTheCataloguesModulesIsWhatTheOldFormComposed(t *testing.T) {
|
|
modules := filepath.Join("..", "..", "..")
|
|
type item struct {
|
|
Collection string `json:"collection"`
|
|
Name string `json:"name"`
|
|
Attributes map[string]string `json:"attributes"`
|
|
Template string `json:"template"`
|
|
}
|
|
read := func(path string) []byte {
|
|
b, err := os.ReadFile(filepath.Join(modules, path))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return b
|
|
}
|
|
for name, only := range map[string][]string{"all": {"adwaita", "clipmenu", "i3", "xterm", "zsh"}, "zsh": {"zsh"}} {
|
|
t.Run(name, func(t *testing.T) {
|
|
facts := map[string]string{"machine:account-home": "/home/op"}
|
|
tpl, _ := templates(t, map[string]string{"posix": string(read("node-env/files/environment.sh")),
|
|
"systemd": string(read("node-env/files/50-mesh.conf"))})
|
|
b := startBus(t)
|
|
e := startEngine(t, map[string]string{"/env/environment.sh": "owned", "/env/50-mesh.conf": "owned"})
|
|
b.assign(t, "node-env", Plan{Templates: tpl, Placement: facts,
|
|
Files: []PlannedFile{{ID: "posix", Path: "/env/environment.sh", Template: "posix", OwnerAtRuntime: "owned"},
|
|
{ID: "systemd", Path: "/env/50-mesh.conf", Template: "systemd", OwnerAtRuntime: "owned"}},
|
|
Collections: []PlannedCollection{{Name: "environment", Comment: "#"}}})
|
|
for _, m := range only {
|
|
var manifest struct {
|
|
Moved bool `json:"moved"`
|
|
Items []item `json:"items"`
|
|
}
|
|
if err := json.Unmarshal(read(m+"/module.json"), &manifest); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !manifest.Moved || len(manifest.Items) == 0 {
|
|
t.Fatalf("%s is not a moved contributor of items", m)
|
|
}
|
|
texts := map[string]string{}
|
|
var planned []PlannedItem
|
|
for _, it := range manifest.Items {
|
|
id := filepath.Base(it.Template)
|
|
texts[id] = string(read(m + "/" + it.Template))
|
|
planned = append(planned, PlannedItem{Collection: it.Collection, Name: it.Name,
|
|
Attributes: it.Attributes, Template: id})
|
|
}
|
|
tp, _ := templates(t, texts)
|
|
b.assign(t, m, Plan{Templates: tp, Items: planned, Placement: facts})
|
|
}
|
|
aClient(t, b, e, t.TempDir(), time.Hour)
|
|
for file, golden := range map[string]string{"/env/environment.sh": "posix", "/env/50-mesh.conf": "systemd"} {
|
|
want, err := os.ReadFile(filepath.Join("testdata", "environment", name+"."+golden))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// node-env's own files hold their header, which is the module's, then the collected text.
|
|
header := strings.SplitAfter(string(read("node-env/files/"+map[string]string{"posix": "environment.sh",
|
|
"systemd": "50-mesh.conf"}[golden])), "\n")
|
|
head := ""
|
|
for _, l := range header {
|
|
if strings.HasPrefix(l, "#") {
|
|
head += l
|
|
}
|
|
}
|
|
eventually(t, file+" is what it was", func() bool { return e.read(t, file) == head+string(want) })
|
|
}
|
|
})
|
|
}
|
|
}
|