diff options
| -rw-r--r-- | cmd/hakurei/testsuite/sandbox/main.go | 6 | ||||
| -rw-r--r-- | internal/testsuite/testsuite.go | 104 |
2 files changed, 86 insertions, 24 deletions
diff --git a/cmd/hakurei/testsuite/sandbox/main.go b/cmd/hakurei/testsuite/sandbox/main.go index 31e85331..7927882d 100644 --- a/cmd/hakurei/testsuite/sandbox/main.go +++ b/cmd/hakurei/testsuite/sandbox/main.go @@ -35,7 +35,7 @@ func mustStart( ) (pid int, done <-chan error) { _serial := strconv.FormatUint(serial, 10) _, done = testsuite.MustStartWith( - ctx, cred, nil, files, + ctx, cred, false, nil, files, "hakurei", "exec", "-a", strconv.Itoa(identity), "sleep", "infinity", _serial, @@ -202,12 +202,12 @@ func main() { for _, p := range []byte{'a', 'b', 'i', 'p'} { testsuite.MustFail( - &cred, nil, + &cred, nil, false, "hakurei", "exec", "capsh", "--has-"+string(p)+"=CAP_SYS_ADMIN", ) } testsuite.MustFail( - &cred, nil, + &cred, nil, false, "hakurei", "exec", "umount", "-R", "/dev", ) }) diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go index aa03327f..3fa6e13c 100644 --- a/internal/testsuite/testsuite.go +++ b/internal/testsuite/testsuite.go @@ -110,9 +110,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(cred *syscall.Credential, extraEnv []string, command ...string) { +func MustFail( + cred *syscall.Credential, + extraEnv []string, + quiet bool, + command ...string, +) { cmd := exec.Command(command[0], command[1:]...) - cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + if !quiet { + cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + } cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGKILL, Credential: cred, @@ -141,12 +148,15 @@ func MustStart(cmd *exec.Cmd) (done <-chan error) { func MustStartWith( ctx context.Context, cred *syscall.Credential, + quiet bool, extraEnv []string, files []*os.File, command ...string, ) (proc *os.Process, done <-chan error) { cmd := exec.CommandContext(ctx, command[0], command[1:]...) - cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + if !quiet { + cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr + } cmd.ExtraFiles = files cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGTERM, @@ -313,6 +323,10 @@ func SessionEnv(dbusEnv string) []string { } } +// quietServices is initialised from the environment and controls whether +// session services should have their outputs connected. +var quietServices = os.Getenv("HAKUREI_VERBOSE_SERVICES") == "" + // MustStartSessionBus starts a session bus that is never explicitly terminated. // The test suite is terminated if the session bus daemon terminates. func MustStartSessionBus(cred *syscall.Credential) (dbusEnv string) { @@ -323,7 +337,7 @@ func MustStartSessionBus(cred *syscall.Credential) (dbusEnv string) { // this is never explicitly terminated _, done := MustStartWith( - context.Background(), cred, nil, []*os.File{w}, + context.Background(), cred, quietServices, nil, []*os.File{w}, "dbus-daemon", "--print-address=3", "--address=unix:path="+XDGRuntimeDir+"/dbus", @@ -370,7 +384,7 @@ func MustStartSway( wg.Go(func() { // this is terminated via swaymsg _, done := MustStartWith( - context.Background(), cred, []string{ + context.Background(), cred, quietServices, []string{ "WLR_BACKENDS=headless", XDGRuntimeEnv, SwayEnv, @@ -394,7 +408,7 @@ func MustStartSway( // TerminateSway requests for the sway server to terminate via sway IPC. func TerminateSway(cred *syscall.Credential) { - MustFail(cred, []string{SwayEnv}, "swaymsg", "exit") + MustFail(cred, []string{SwayEnv}, quietServices, "swaymsg", "exit") } // MustStartPipeWire starts a PipeWire server that is never explicitly @@ -402,7 +416,7 @@ func TerminateSway(cred *syscall.Credential) { func MustStartPipeWire(cred *syscall.Credential, dbusEnv string) { // this is never explicitly terminated _, done := MustStartWith( - context.Background(), cred, []string{ + context.Background(), cred, quietServices, []string{ XDGRuntimeEnv, dbusEnv, }, nil, @@ -425,7 +439,7 @@ func MustStartPipeWire(cred *syscall.Credential, dbusEnv string) { ) _, _done := MustStartWith( - context.Background(), cred, []string{ + context.Background(), cred, quietServices, []string{ XDGRuntimeEnv, dbusEnv, }, nil, @@ -456,14 +470,16 @@ func MustScanFor(f func(ps *StatScanner) bool) int { return ps.Stat().PID } -// MustStartHakurei starts a hakurei container configured by c. -func MustStartHakurei( +// StartHakurei starts a hakurei container configured by c. +func StartHakurei( wg *sync.WaitGroup, cred *syscall.Credential, dbusEnv string, + processCommand func(cmd *exec.Cmd), onDone func(err error, output string), + scan bool, c *hst.Config, -) (p hst.State, pid int) { +) (p hst.State, pid int, err error) { s := store.New(check.MustAbs("/tmp/hakurei.0/state")) cmd := exec.Command( @@ -482,41 +498,70 @@ func MustStartHakurei( cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, &output, &output cmd.Env = SessionEnv(dbusEnv) - var err error var notify, _notify, _conf, conf, ident, _ident *os.File if notify, _notify, err = os.Pipe(); err != nil { - log.Fatal(err) + return } cmd.ExtraFiles = append(cmd.ExtraFiles, _notify) if _conf, conf, err = os.Pipe(); err != nil { - log.Fatal(err) + _, _ = notify.Close(), _notify.Close() + return } cmd.ExtraFiles = append(cmd.ExtraFiles, _conf) if ident, _ident, err = os.Pipe(); err != nil { - log.Fatal(err) + _, _ = notify.Close(), _notify.Close() + _, _ = conf.Close(), _conf.Close() + return } cmd.ExtraFiles = append(cmd.ExtraFiles, _ident) + if processCommand != nil { + processCommand(cmd) + } done := MustStart(cmd) wg.Go(func() { _err := <-done; onDone(_err, output.String()) }) + if err = errors.Join( + _notify.Close(), + _conf.Close(), + _ident.Close(), + ); err != nil { + _, _, _ = notify.Close(), conf.Close(), ident.Close() + return + } + if err = json.NewEncoder(conf).Encode(c); err != nil { - log.Fatal(err) + _, _, _ = notify.Close(), conf.Close(), ident.Close() + return } else if err = conf.Close(); err != nil { - log.Fatal(err) + _, _ = notify.Close(), ident.Close() + return + } + + if !scan && len(cmd.ExtraFiles) != 3 { + err = errors.Join(notify.Close(), ident.Close()) + return } var id hst.ID if _, err = io.ReadFull(ident, id[:]); err != nil { - log.Fatal(err) + _, _ = notify.Close(), ident.Close() + return } else if err = ident.Close(); err != nil { - log.Fatal(err) + _ = notify.Close() + return + } + + if !scan { + err = notify.Close() + return } if _, err = io.ReadFull(notify, make([]byte, 8)); err != nil { - log.Fatal(err) + _ = notify.Close() + return } else if err = notify.Close(); err != nil { - log.Fatal(err) + return } var ok bool @@ -595,3 +640,20 @@ func MustStartHakurei( }) return } + +// MustStartHakurei is like [StartHakurei], but terminates the test suite if +// an error is encountered. +func MustStartHakurei( + wg *sync.WaitGroup, + cred *syscall.Credential, + dbusEnv string, + onDone func(err error, output string), + c *hst.Config, +) (p hst.State, pid int) { + var err error + p, pid, err = StartHakurei(wg, cred, dbusEnv, nil, onDone, true, c) + if err != nil { + log.Fatal(err) + } + return +} |
