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") } }