Mirrors were generated once and never again and caches never cleaned. The module holds node-package-manager (hq ADR 0207), declares pacman itself, owns /etc/pacman.conf whole — [options] cannot take an appended block — with the union of the enabled repositories and improved options, proven by pacman-conf in its test, and enables reflector.timer (its config owned) and paccache.timer. Fifteen tools from a Go bundle; transactions run as transient units so a call's timeout never kills pacman mid-transaction (to-be 42).
108 lines
3.3 KiB
Go
108 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// call is one command a fake runner was asked to run.
|
|
type call struct {
|
|
name string
|
|
args []string
|
|
}
|
|
|
|
func (c call) String() string {
|
|
if len(c.args) == 0 {
|
|
return c.name
|
|
}
|
|
return c.name + " " + strings.Join(c.args, " ")
|
|
}
|
|
|
|
// fake is a runner answering by the command line it is given, recording every call.
|
|
func fake(answer func(c call) Ran, calls *[]call) Runner {
|
|
return func(_ context.Context, name string, args ...string) Ran {
|
|
c := call{name, append([]string(nil), args...)}
|
|
if calls != nil {
|
|
*calls = append(*calls, c)
|
|
}
|
|
return answer(c)
|
|
}
|
|
}
|
|
|
|
// byLine answers from a table keyed by the whole command line, and refuses anything else as a
|
|
// command the test did not expect.
|
|
func byLine(table map[string]Ran, calls *[]call) Runner {
|
|
return fake(func(c call) Ran {
|
|
if r, ok := table[c.String()]; ok {
|
|
return r
|
|
}
|
|
return Ran{Status: 99, Stderr: "unexpected command: " + c.String()}
|
|
}, calls)
|
|
}
|
|
|
|
func machine(run Runner, uid int) *Machine {
|
|
return &Machine{Run: run, UID: uid, User: "operator", Account: "operator",
|
|
ReadFile: func(string) ([]byte, error) { return nil, errNoFile },
|
|
Now: func() time.Time { return time.Date(2026, 10, 4, 12, 0, 0, 0, time.UTC) },
|
|
Sleep: func(time.Duration) {}}
|
|
}
|
|
|
|
type noFile struct{}
|
|
|
|
func (noFile) Error() string { return "no such file" }
|
|
|
|
var errNoFile = noFile{}
|
|
|
|
func TestAnActNeedingRootGoesThroughSudoWithoutAPromptUnlessThisIsRoot(t *testing.T) {
|
|
if p, a := Escalated(1000, "visudo", "-c"); p != "sudo" || strings.Join(a, " ") != "-n visudo -c" {
|
|
t.Fatalf("not root: %s %v", p, a)
|
|
}
|
|
if p, a := Escalated(0, "visudo", "-c"); p != "visudo" || strings.Join(a, " ") != "-c" {
|
|
t.Fatalf("root: %s %v", p, a)
|
|
}
|
|
}
|
|
|
|
func TestFailuresAreNamedNeverReadAsEmpty(t *testing.T) {
|
|
cases := []struct {
|
|
r Ran
|
|
want string
|
|
}{
|
|
{Ran{Status: 127, Err: "ENOENT"}, "sudo is not installed here"},
|
|
{Ran{Status: 1, Stderr: "sudo: a password is required\n"}, "may not run it without a prompt: sudo: a password is required"},
|
|
{Ran{Status: 124, Err: "no answer within 20 s"}, "did not answer: no answer within 20 s"},
|
|
{Ran{Status: 2, Stderr: "boom\nmore"}, "failed (2): boom"},
|
|
}
|
|
for _, c := range cases {
|
|
m := machine(fake(func(call) Ran { return c.r }, nil), 1000)
|
|
if _, err := m.Root("thing"); err == nil || !strings.Contains(err.Error(), c.want) {
|
|
t.Errorf("%+v: %v, want %q", c.r, err, c.want)
|
|
}
|
|
}
|
|
m := machine(fake(func(call) Ran { return Ran{Status: 127, Err: "ENOENT"} }, nil), 1000)
|
|
if _, err := m.Out("thing"); err == nil || !strings.Contains(err.Error(), "thing is not installed") {
|
|
t.Errorf("a missing program: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestAnArgumentIsNeverAnOption(t *testing.T) {
|
|
for _, bad := range []any{"-rf", "a\nb", 3.0} {
|
|
if _, err := text(map[string]any{"x": bad}, "x", true); err == nil {
|
|
t.Errorf("%v was accepted", bad)
|
|
}
|
|
}
|
|
if s, err := text(map[string]any{"x": " ok "}, "x", true); err != nil || s != "ok" {
|
|
t.Errorf("a plain value: %q %v", s, err)
|
|
}
|
|
if _, err := text(map[string]any{}, "x", true); err == nil {
|
|
t.Error("a missing required value was accepted")
|
|
}
|
|
if n, _ := whole(map[string]any{"n": 10000.0}, "n", 5, 1, 100); n != 100 {
|
|
t.Errorf("not bounded: %d", n)
|
|
}
|
|
if _, err := whole(map[string]any{"n": 0.0}, "n", 5, 1, 100); err == nil {
|
|
t.Error("below the least was accepted")
|
|
}
|
|
}
|