aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cmd/hakurei/testsuite/sandbox/main.go11
-rw-r--r--internal/testsuite/testsuite.go134
2 files changed, 113 insertions, 32 deletions
diff --git a/cmd/hakurei/testsuite/sandbox/main.go b/cmd/hakurei/testsuite/sandbox/main.go
index 31e85331..a85ec485 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",
)
})
@@ -287,14 +287,13 @@ func main() {
for name, tc := range testdata.All() {
wg.Go(func() {
_, pid := testsuite.MustStartHakurei(
- &wg, &cred, dbusEnv,
+ ctx, &wg, &cred, dbusEnv,
func(err error, output string) {
log.Printf("completed test case %s\n%s", name, output)
if err != nil {
log.Fatalf("test case %s: %v", name, err)
}
- },
- &tc.Hakurei,
+ }, true, false, &tc.Hakurei,
)
testsuite.MustCheckFilter(
diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go
index aa03327f..fee4952c 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,21 +470,29 @@ 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(
+ ctx context.Context,
wg *sync.WaitGroup,
cred *syscall.Credential,
dbusEnv string,
+ processCommand func(cmd *exec.Cmd),
onDone func(err error, output string),
+ scan, wait, verbose 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(
+ hakureiFlags := ""
+ if verbose {
+ hakureiFlags += " -v"
+ }
+
+ cmd := exec.CommandContext(ctx,
"script", "/dev/null",
"-E", "always",
"-qec",
- "hakurei run "+
+ "hakurei"+hakureiFlags+" run "+
"--identifier-fd=5"+
" 4 1>&3",
)
@@ -479,44 +501,76 @@ func MustStartHakurei(
Credential: cred,
}
var output strings.Builder
- cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, &output, &output
+ cmd.Stdout, cmd.Stderr = &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 _, err = io.ReadFull(notify, make([]byte, 8)); err != nil {
- log.Fatal(err)
- } else if err = notify.Close(); err != nil {
- log.Fatal(err)
+ if !scan {
+ err = notify.Close()
+ return
+ }
+
+ if wait {
+ if _, err = io.ReadFull(notify, make([]byte, 8)); err != nil {
+ _ = notify.Close()
+ return
+ }
+ }
+ if err = notify.Close(); err != nil {
+ return
}
var ok bool
@@ -595,3 +649,31 @@ func MustStartHakurei(
})
return
}
+
+// MustStartHakurei is like [StartHakurei], but terminates the test suite if
+// an error is encountered.
+func MustStartHakurei(
+ ctx context.Context,
+ wg *sync.WaitGroup,
+ cred *syscall.Credential,
+ dbusEnv string,
+ onDone func(err error, output string),
+ wait, verbose bool,
+ c *hst.Config,
+) (p hst.State, pid int) {
+ _ctx, cancel := context.WithCancel(ctx)
+
+ var err error
+ p, pid, err = StartHakurei(
+ _ctx, wg, cred, dbusEnv,
+ nil, func(err error, output string) {
+ defer cancel()
+ onDone(err, output)
+ }, true, wait, verbose, c,
+ )
+ if err != nil {
+ log.Printf("cannot start hakurei container: %v", err)
+ cancel()
+ }
+ return
+}