Merge branch 'feat/one-group-one-plan' into g/977
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
//go:build integration
|
||||
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestThePOSIXEnvironmentSourcedTwiceLeavesPATHAsOnce(t *testing.T) {
|
||||
sh, err := exec.LookPath("sh")
|
||||
if err != nil {
|
||||
t.Skip("no sh on this machine")
|
||||
}
|
||||
script := "PATH=/usr/bin:/bin\n" + composedPOSIX + "once=$PATH\n" + composedPOSIX +
|
||||
`[ "$PATH" = "$once" ] || { echo "changed: $once -> $PATH"; exit 1; }` + "\n" +
|
||||
`echo "$PATH"; echo "$GOPATH"`
|
||||
out, err := exec.Command(sh, "-c", script).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("sourcing twice: %v\n%s", err, out)
|
||||
}
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
want := "/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/usr/bin:/bin:/opt/agent/bin:/opt/scripts"
|
||||
if lines[0] != want {
|
||||
t.Fatalf("PATH is %s, not %s", lines[0], want)
|
||||
}
|
||||
if lines[1] != "/home/op/go" {
|
||||
t.Fatalf("GOPATH was not exported: %q", lines[1])
|
||||
}
|
||||
// And an entry the account already has stays where it is, and once.
|
||||
out, err = exec.Command(sh, "-c", "PATH=/opt/scripts:/usr/bin\n"+composedPOSIX+`echo "$PATH"`).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%v\n%s", err, out)
|
||||
}
|
||||
if got := strings.TrimSpace(string(out)); got !=
|
||||
"/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/opt/scripts:/usr/bin:/opt/agent/bin" {
|
||||
t.Fatalf("an entry already on PATH was added again or moved: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTheServiceManagerReadsTheSystemdRenderingAsMeant(t *testing.T) {
|
||||
generator := "/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator"
|
||||
if _, err := os.Stat(generator); err != nil {
|
||||
t.Skip("NOT JUDGED: no environment.d generator on this machine, so the service manager's reading " +
|
||||
"of the rendering is judged only where systemd runs; the rendering itself is held byte for byte " +
|
||||
"by TestTheEnvironmentRendersForTheServiceManagerByteForByte")
|
||||
}
|
||||
const base = "/usr/bin:/bin"
|
||||
read := func(conf string) map[string]string {
|
||||
t.Helper()
|
||||
config := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(config, "environment.d"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if conf != "" {
|
||||
if err := os.WriteFile(filepath.Join(config, "environment.d", "50-mesh.conf"), []byte(conf), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
cmd := exec.Command(generator)
|
||||
cmd.Env = []string{"PATH=" + base, "HOME=" + config, "XDG_CONFIG_HOME=" + config}
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%v\n%s", err, out)
|
||||
}
|
||||
vars := map[string]string{}
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
if k, v, ok := strings.Cut(line, "="); ok {
|
||||
vars[k] = v
|
||||
}
|
||||
}
|
||||
return vars
|
||||
}
|
||||
machine, read50 := read(""), read(composedSystemd)
|
||||
|
||||
// What the machine's own files do to PATH: nothing, or append to it. One that replaces or prepends
|
||||
// leaves nothing this test can say about the mesh's file, and says so rather than guess.
|
||||
added, ok := strings.CutPrefix(machine["PATH"], base)
|
||||
if machine["PATH"] != "" && !ok {
|
||||
t.Skipf("NOT JUDGED: this machine's own environment.d sets PATH to %s, not %s with something after it, so "+
|
||||
"what the mesh's file adds cannot be told apart from it", machine["PATH"], base)
|
||||
}
|
||||
want := "/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/usr/bin:/bin:/opt/agent/bin:/opt/scripts" + added
|
||||
if read50["PATH"] != want || read50["GOPATH"] != "/home/op/go" {
|
||||
t.Fatalf("the service manager read PATH=%s GOPATH=%s, not PATH=%s GOPATH=/home/op/go (the machine's own "+
|
||||
"files add %q to PATH)", read50["PATH"], read50["GOPATH"], want, added)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package catalogue
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -101,36 +98,6 @@ func TestTheEnvironmentRendersForTheServiceManagerByteForByte(t *testing.T) {
|
||||
// Sourcing twice changes nothing (ADR 0203 §3): a login shell that starts another reads the file
|
||||
// again, and a PATH that grew each time would be the symptom. Run by a real `sh`, because the claim
|
||||
// is about what a shell does with the file, not about what the file looks like.
|
||||
func TestThePOSIXEnvironmentSourcedTwiceLeavesPATHAsOnce(t *testing.T) {
|
||||
sh, err := exec.LookPath("sh")
|
||||
if err != nil {
|
||||
t.Skip("no sh on this machine")
|
||||
}
|
||||
script := "PATH=/usr/bin:/bin\n" + composedPOSIX + "once=$PATH\n" + composedPOSIX +
|
||||
`[ "$PATH" = "$once" ] || { echo "changed: $once -> $PATH"; exit 1; }` + "\n" +
|
||||
`echo "$PATH"; echo "$GOPATH"`
|
||||
out, err := exec.Command(sh, "-c", script).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("sourcing twice: %v\n%s", err, out)
|
||||
}
|
||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||
want := "/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/usr/bin:/bin:/opt/agent/bin:/opt/scripts"
|
||||
if lines[0] != want {
|
||||
t.Fatalf("PATH is %s, not %s", lines[0], want)
|
||||
}
|
||||
if lines[1] != "/home/op/go" {
|
||||
t.Fatalf("GOPATH was not exported: %q", lines[1])
|
||||
}
|
||||
// And an entry the account already has stays where it is, and once.
|
||||
out, err = exec.Command(sh, "-c", "PATH=/opt/scripts:/usr/bin\n"+composedPOSIX+`echo "$PATH"`).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%v\n%s", err, out)
|
||||
}
|
||||
if got := strings.TrimSpace(string(out)); got !=
|
||||
"/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/opt/scripts:/usr/bin:/opt/agent/bin" {
|
||||
t.Fatalf("an entry already on PATH was added again or moved: %s", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The environment.d rendering, read by the service manager's own generator where this machine has
|
||||
// one — the same reader an account's user manager runs, so the PATH it composes is the one asserted.
|
||||
@@ -143,54 +110,6 @@ func TestThePOSIXEnvironmentSourcedTwiceLeavesPATHAsOnce(t *testing.T) {
|
||||
// A machine without the generator — the build seat's toolchain image holds no systemd — cannot judge
|
||||
// this and says so: there the rendering is held byte for byte by
|
||||
// TestTheEnvironmentRendersForTheServiceManagerByteForByte, and this reading only where systemd runs.
|
||||
func TestTheServiceManagerReadsTheSystemdRenderingAsMeant(t *testing.T) {
|
||||
generator := "/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator"
|
||||
if _, err := os.Stat(generator); err != nil {
|
||||
t.Skip("NOT JUDGED: no environment.d generator on this machine, so the service manager's reading " +
|
||||
"of the rendering is judged only where systemd runs; the rendering itself is held byte for byte " +
|
||||
"by TestTheEnvironmentRendersForTheServiceManagerByteForByte")
|
||||
}
|
||||
const base = "/usr/bin:/bin"
|
||||
read := func(conf string) map[string]string {
|
||||
t.Helper()
|
||||
config := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(config, "environment.d"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if conf != "" {
|
||||
if err := os.WriteFile(filepath.Join(config, "environment.d", "50-mesh.conf"), []byte(conf), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
cmd := exec.Command(generator)
|
||||
cmd.Env = []string{"PATH=" + base, "HOME=" + config, "XDG_CONFIG_HOME=" + config}
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("%v\n%s", err, out)
|
||||
}
|
||||
vars := map[string]string{}
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
if k, v, ok := strings.Cut(line, "="); ok {
|
||||
vars[k] = v
|
||||
}
|
||||
}
|
||||
return vars
|
||||
}
|
||||
machine, read50 := read(""), read(composedSystemd)
|
||||
|
||||
// What the machine's own files do to PATH: nothing, or append to it. One that replaces or prepends
|
||||
// leaves nothing this test can say about the mesh's file, and says so rather than guess.
|
||||
added, ok := strings.CutPrefix(machine["PATH"], base)
|
||||
if machine["PATH"] != "" && !ok {
|
||||
t.Skipf("NOT JUDGED: this machine's own environment.d sets PATH to %s, not %s with something after it, so "+
|
||||
"what the mesh's file adds cannot be told apart from it", machine["PATH"], base)
|
||||
}
|
||||
want := "/home/op/go/bin:/usr/local/go/bin:/home/op/.local/bin:/home/op/bin:/usr/bin:/bin:/opt/agent/bin:/opt/scripts" + added
|
||||
if read50["PATH"] != want || read50["GOPATH"] != "/home/op/go" {
|
||||
t.Fatalf("the service manager read PATH=%s GOPATH=%s, not PATH=%s GOPATH=/home/op/go (the machine's own "+
|
||||
"files add %q to PATH)", read50["PATH"], read50["GOPATH"], want, added)
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing contributed renders nothing, in both formats — not an empty `export PATH`.
|
||||
func TestNoContributionsRenderNothing(t *testing.T) {
|
||||
|
||||
@@ -75,8 +75,9 @@ func TestEveryCatalogueManifestDeclaresWhatItMounts(t *testing.T) {
|
||||
if len(files) == 0 {
|
||||
t.Fatal("no manifests in the catalogue, so this proved nothing")
|
||||
}
|
||||
root := beside.Dir(t, "mesh-catalog") // once: it copies the captured tree
|
||||
for _, file := range files {
|
||||
if _, err := ReadTreeManifest(beside.Dir(t, "mesh-catalog"), filepath.Dir(file)); err != nil {
|
||||
if _, err := ReadTreeManifest(root, filepath.Dir(file)); err != nil {
|
||||
t.Errorf("%s: %v", filepath.Base(filepath.Dir(file)), err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user