From d5d2c23d5a489bba6be8a75ad4c5d1ac3cda4bb6 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 6 Oct 2026 21:54:48 +0900 Subject: test/internal/testsuite: directly set credentials There is no reason to keep using sudo here, now that processes are spawned natively. This change removes all use of sudo. Signed-off-by: Ophestra --- test/internal/testsuite/testsuite.go | 134 +++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 60 deletions(-) (limited to 'test/internal/testsuite/testsuite.go') diff --git a/test/internal/testsuite/testsuite.go b/test/internal/testsuite/testsuite.go index 00eb2f92..456c36b4 100644 --- a/test/internal/testsuite/testsuite.go +++ b/test/internal/testsuite/testsuite.go @@ -13,8 +13,6 @@ import ( "os" "os/exec" "os/signal" - "os/user" - "strconv" "sync" "syscall" "time" @@ -27,20 +25,17 @@ func ReceiveSignals() { log.Fatalf("terminating on signal %s", <-s) } -// GetUser returns the [user.User] structure describing the user with uid 1000. -func GetUser() *user.User { - if u, err := user.LookupId("1000"); err != nil { - log.Fatal(err) - return nil - } else { - return u - } -} - // MustRun runs command and terminates the testsuite on error. -func MustRun(command ...string) { +func MustRun(cred *syscall.Credential, extraEnv []string, command ...string) { cmd := exec.Command(command[0], command[1:]...) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + Credential: cred, + } + if len(extraEnv) != 0 { + cmd.Env = append(cmd.Environ(), extraEnv...) + } if err := cmd.Run(); err != nil { log.Fatal(err) } @@ -52,9 +47,16 @@ var ErrUnexpectedSuccess = errors.New("process unexpectedly exited with code 0") // MustFail runs command and terminates the testsuite if the program fails to // start or exits with code 0. -func MustFail(command ...string) { +func MustFail(cred *syscall.Credential, extraEnv []string, command ...string) { cmd := exec.Command(command[0], command[1:]...) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + Credential: cred, + } + if len(extraEnv) != 0 { + cmd.Env = append(cmd.Environ(), extraEnv...) + } if err := cmd.Run(); err == nil { log.Fatal(ErrUnexpectedSuccess) } else if e, ok := errors.AsType[*exec.ExitError](err); !ok { @@ -64,16 +66,6 @@ func MustFail(command ...string) { } } -// MustRunAs wraps [MustRun] for sudo. -func MustRunAs(username string, command ...string) { - MustRun(append([]string{"sudo", "-u", username}, command...)...) -} - -// MustFailAs wraps [MustFail] for sudo. -func MustFailAs(username string, command ...string) { - MustFail(append([]string{"sudo", "-u", username}, command...)...) -} - // MustStart starts cmd and returns a channel delivering its wait error. func MustStart(cmd *exec.Cmd) (done <-chan error) { if err := cmd.Start(); err != nil { @@ -84,24 +76,24 @@ func MustStart(cmd *exec.Cmd) (done <-chan error) { return d } -// MustStartAs wraps [MustStart] for sudo. -func MustStartAs( +// MustStartWith wraps [MustStart] and creates the [exec.Cmd] object internally. +func MustStartWith( ctx context.Context, - username string, + cred *syscall.Credential, + extraEnv []string, files []*os.File, command ...string, ) (proc *os.Process, done <-chan error) { - sudoArgs := []string{ - "-u", username, - } - if len(files) != 0 { - sudoArgs = append(sudoArgs, "-C", strconv.Itoa(len(files)+4)) - } - sudoArgs = append(sudoArgs, "--") - cmd := exec.CommandContext(ctx, "sudo", append(sudoArgs, command...)...) + cmd := exec.CommandContext(ctx, command[0], command[1:]...) cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr cmd.ExtraFiles = files - cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGTERM} + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGTERM, + Credential: cred, + } + if len(extraEnv) != 0 { + cmd.Env = append(cmd.Environ(), extraEnv...) + } return cmd.Process, MustStart(cmd) } @@ -136,9 +128,21 @@ func FilterTerminated(err error) error { } // Poll repeatedly runs command until it succeeds. -func Poll(d time.Duration, command ...string) { +func Poll( + d time.Duration, + cred *syscall.Credential, + extraEnv []string, + command ...string, +) { for range time.NewTicker(d).C { cmd := exec.Command(command[0], command[1:]...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + Credential: cred, + } + if len(extraEnv) != 0 { + cmd.Env = append(cmd.Environ(), extraEnv...) + } if err := cmd.Run(); err != nil { if e, ok := errors.AsType[*exec.ExitError](err); ok && e.Exited() { continue @@ -160,15 +164,15 @@ const ( // MustStartSessionBus starts a session bus that is never explicitly terminated. // The test suite is terminated if the session bus daemon terminates. -func MustStartSessionBus(username string) (dbusEnv string) { +func MustStartSessionBus(cred *syscall.Credential) (dbusEnv string) { r, w, err := os.Pipe() if err != nil { log.Fatal(err) } // this is never explicitly terminated - _, done := MustStartAs( - context.Background(), username, []*os.File{w}, + _, done := MustStartWith( + context.Background(), cred, nil, []*os.File{w}, "dbus-daemon", "--print-address=3", "--address=unix:path="+XDGRuntimeDir+"/dbus", @@ -209,16 +213,18 @@ const ( // by calling [TerminateSway]. func MustStartSway( wg *sync.WaitGroup, - username, dbusEnv string, + cred *syscall.Credential, + dbusEnv string, ) { wg.Go(func() { // this is terminated via swaymsg - _, done := MustStartAs( - context.Background(), username, nil, "env", - "WLR_BACKENDS=headless", - XDGRuntimeEnv, - SwayEnv, - dbusEnv, + _, done := MustStartWith( + context.Background(), cred, []string{ + "WLR_BACKENDS=headless", + XDGRuntimeEnv, + SwayEnv, + dbusEnv, + }, nil, "sway", ) if err := <-done; err != nil { @@ -226,23 +232,29 @@ func MustStartSway( } }) - Poll(50*time.Millisecond, "sudo", "-u", username, SwayEnv, "swaymsg") + Poll( + 50*time.Millisecond, + cred, + []string{SwayEnv}, + "swaymsg", + ) log.Printf("sway available via %s", SwayEnv) } // TerminateSway requests for the sway server to terminate via sway IPC. -func TerminateSway(username string) { - MustFailAs(username, SwayEnv, "swaymsg", "exit") +func TerminateSway(cred *syscall.Credential) { + MustFail(cred, []string{SwayEnv}, "swaymsg", "exit") } // MustStartPipeWire starts a PipeWire server that is never explicitly // terminated. The test suite is terminated if the PipeWire server terminates. -func MustStartPipeWire(username, dbusEnv string) { +func MustStartPipeWire(cred *syscall.Credential, dbusEnv string) { // this is never explicitly terminated - _, done := MustStartAs( - context.Background(), username, nil, "env", - XDGRuntimeEnv, - dbusEnv, + _, done := MustStartWith( + context.Background(), cred, []string{ + XDGRuntimeEnv, + dbusEnv, + }, nil, "pipewire", ) @@ -253,17 +265,19 @@ func MustStartPipeWire(username, dbusEnv string) { log.Fatal("pipewire terminated unexpectedly") }() - Poll(50*time.Millisecond, "sudo", "-u", username, + Poll(50*time.Millisecond, cred, []string{ XDGRuntimeEnv, dbusEnv, + }, "wpctl", "status", ) - _, _done := MustStartAs( - context.Background(), username, nil, "env", - XDGRuntimeEnv, - dbusEnv, + _, _done := MustStartWith( + context.Background(), cred, []string{ + XDGRuntimeEnv, + dbusEnv, + }, nil, "wireplumber", ) -- cgit v1.3.1