diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-10-06 22:23:20 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-10-06 23:09:19 +0900 |
| commit | a9e2749f6654d0aa07b274a45c9177d10323f80a (patch) | |
| tree | 291f5b23a67af036cbe5d374b3d3fb0240fc438c /test/sandbox/main.go | |
| parent | 19f36491f2e2a5029ac396c10408d653cad6c81b (diff) | |
internal/testsuite: move from test
This structure is a lot less clumsy than the old nix-centric layout.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'test/sandbox/main.go')
| -rw-r--r-- | test/sandbox/main.go | 409 |
1 files changed, 0 insertions, 409 deletions
diff --git a/test/sandbox/main.go b/test/sandbox/main.go deleted file mode 100644 index 4961c04f..00000000 --- a/test/sandbox/main.go +++ /dev/null @@ -1,409 +0,0 @@ -//go:build testsuite - -// The sandbox test program runs cmd/hakurei with configurations simulating -// several common workloads and inspects the resulting container states. -package main - -import ( - "bytes" - "context" - "encoding/json" - "io" - "log" - "os" - "os/exec" - "path/filepath" - "slices" - "strconv" - "strings" - "sync" - "sync/atomic" - "syscall" - - "hakurei.app/check" - "hakurei.app/fhs" - "hakurei.app/hst" - "hakurei.app/internal/store" - - "hakurei.app/test/internal/testsuite" - "hakurei.app/test/sandbox/testdata" -) - -// mustScanFor continuously scans the proc filesystem and calls f for each entry -// visited. -func mustScanFor(f func(ps *testsuite.StatScanner) bool) int { - var ps testsuite.StatScanner - - for ps.Scan() { - if f(&ps) { - break - } - } - if err := ps.Err(); err != nil { - log.Fatal(err) - } - return ps.Stat().PID -} - -// mustStart starts a hakurei container and returns the pid of a process within -// the container. This process must be terminated by the caller. -func mustStart( - ctx context.Context, - serial uint64, - cred *syscall.Credential, - files ...*os.File, -) (pid int, done <-chan error) { - _serial := strconv.FormatUint(serial, 10) - _, done = testsuite.MustStartWith( - ctx, cred, nil, files, - "hakurei", "exec", - "sleep", "infinity", _serial, - ) - - var stat syscall.Stat_t - pid = mustScanFor(func(s *testsuite.StatScanner) bool { - select { - case err := <-done: - if err == nil { - log.Fatal("test process terminated unexpectedly") - } - log.Fatal(err) - default: - break - } - - if s.Stat().Comm != "sleep" { - return false - } - - if args, err := s.Stat().Args(); err != nil { - if testsuite.IsNotExist(err) { - return false - } - log.Fatal(err) - } else if !slices.Equal(args, []string{ - "sleep", - "infinity", - _serial, - }) { - return false - } - - if err := s.Stat().Stat(&stat); err != nil { - if testsuite.IsNotExist(err) { - return false - } - log.Fatal(err) - } - - id := hst.ToUser[uint32](0, 0) - if stat.Uid != id || stat.Gid != id { - return false - } - - return true - }) - return -} - -func main() { - go testsuite.ReceiveSignals() - - // the signal handler does not wait for termination - ctx := context.Background() - - cred := syscall.Credential{Uid: 1000, Gid: 100} - if err := os.MkdirAll("/opt/test-helper/bin", 0755); err != nil { - log.Fatal(err) - } - - var testToolDone <-chan error - { - cmd := exec.Command( - "go", "build", - "-o", "/opt/test-helper/bin", - "-tags=tester", - "-trimpath", - "./test/sandbox/tester", - ) - cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr - testToolDone = testsuite.MustStart(cmd) - } - - var wg sync.WaitGroup - defer wg.Wait() - - var serial atomic.Uint64 - newSerial := func() uint64 { serial.Add(1); return serial.Load() } - - testsuite.MustRun( - &cred, nil, - "hakurei", "exec", "capsh", "--print", - ) - wg.Go(func() { - defer log.Println("validated capabilities/securebits in user namespace") - - testsuite.MustRun( - &cred, nil, - "hakurei", "exec", "capsh", "--has-no-new-privs", - ) - - for _, p := range []byte{'a', 'b', 'i', 'p'} { - testsuite.MustFail( - &cred, nil, - "hakurei", "exec", "capsh", "--has-"+string(p)+"=CAP_SYS_ADMIN", - ) - } - testsuite.MustFail( - &cred, nil, - "hakurei", "exec", "umount", "-R", "/dev", - ) - }) - - wg.Go(func() { - defer log.Println("validated pd seccomp outcome") - - c, cancel := context.WithCancel(ctx) - defer cancel() - - pid, done := mustStart(c, newSerial(), &cred) - testsuite.MustCheckFilter(pid, testdata.SumPD) - if err := testsuite.FilterTerminated(<-done); err != nil { - log.Fatal(err) - } - }) - - wg.Go(func() { - defer log.Println("validated fd leak") - - c, cancel := context.WithCancel(ctx) - defer cancel() - - pid, done := mustStart(c, newSerial(), &cred, os.Stdin, os.Stdout, os.Stderr) - prefix := filepath.Join(fhs.Proc, strconv.Itoa(pid), "fd") - - var fail bool - if entries, err := os.ReadDir(prefix); err != nil { - log.Fatal(err.Error()) - } else { - for _, ent := range entries { - var fd int - if fd, err = strconv.Atoi(ent.Name()); err != nil { - log.Fatal(err.Error()) - } - - // skip standard streams - if fd <= 2 { - continue - } - fail = true - - var d string - if d, err = os.Readlink(filepath.Join( - prefix, - ent.Name(), - )); err != nil { - log.Fatal(err.Error()) - } - log.Printf("extra fd %d -> %s", fd, d) - } - } - if fail { - log.Fatal("file descriptors leaked") - } - - if err := syscall.Kill(pid, syscall.SIGTERM); err != nil { - log.Fatalf("cannot terminate anchor: %v", err) - } else if err = testsuite.FilterTerminated(<-done); err != nil { - log.Fatal(err) - } - }) - - if err := os.MkdirAll(testsuite.XDGRuntimeDir, 0700); err != nil { - log.Fatal(err) - } else if err = os.Chown(testsuite.XDGRuntimeDir, 1000, 1000); err != nil { - log.Fatal(err) - } - - var swg sync.WaitGroup - defer swg.Wait() - dbusEnv := testsuite.MustStartSessionBus(&cred) - testsuite.MustStartSway(&swg, &cred, dbusEnv) - defer testsuite.TerminateSway(&cred) - testsuite.MustStartPipeWire(&cred, dbusEnv) - - if err := <-testToolDone; err != nil { - log.Fatal(err) - } - log.Println("created test helper") - - s := store.New(check.MustAbs("/tmp/hakurei.0/state")) - for name, tc := range testdata.All() { - wg.Go(func() { - cmd := exec.Command( - "script", "/dev/null", - "-E", "always", - "-qec", - "hakurei run "+ - "--identifier-fd=5"+ - " 4 1>&3", - ) - cmd.SysProcAttr = &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, - Credential: &cred, - } - var output bytes.Buffer - cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, &output, &output - cmd.Env = []string{ - "PATH=" + os.Getenv("PATH"), - "TERM=xterm", - testsuite.XDGRuntimeEnv, - testsuite.WaylandEnv, - "DISPLAY=:0", - dbusEnv, - } - - var err error - var notify, _notify, _conf, conf, ident, _ident *os.File - if notify, _notify, err = os.Pipe(); err != nil { - log.Fatal(err) - } - cmd.ExtraFiles = append(cmd.ExtraFiles, _notify) - if _conf, conf, err = os.Pipe(); err != nil { - log.Fatal(err) - } - cmd.ExtraFiles = append(cmd.ExtraFiles, _conf) - if ident, _ident, err = os.Pipe(); err != nil { - log.Fatal(err) - } - cmd.ExtraFiles = append(cmd.ExtraFiles, _ident) - - done := testsuite.MustStart(cmd) - wg.Go(func() { - _err := <-done - log.Printf("completed test case %s\n%s", name, output.String()) - if _err != nil { - log.Fatalf("test case %s: %v", name, _err) - } - }) - - if err = json.NewEncoder(conf).Encode(&tc.Hakurei); err != nil { - log.Fatal(err) - } else if err = conf.Close(); err != nil { - log.Fatal(err) - } - - var id hst.ID - if _, err = io.ReadFull(ident, id[:]); err != nil { - log.Fatal(err) - } else if err = ident.Close(); err != nil { - log.Fatal(err) - } - - if _, err = io.ReadFull(notify, make([]byte, 8)); err != nil { - log.Fatal(err) - } else if err = notify.Close(); err != nil { - log.Fatal(err) - } - - var ( - ok bool - p hst.State - ) - entries, copyError := s.All() - for entry := range entries { - if entry.ID == id { - ok = true - if _, err = entry.Load(&p, nil); err != nil { - log.Fatal(err) - } - break - } - } - if err = copyError(); err != nil { - log.Fatal(err) - } - if !ok { - log.Fatalf("instance %s is not present in store", id) - } - - var stat syscall.Stat_t - pid := mustScanFor(func(ps *testsuite.StatScanner) bool { - select { - case err = <-done: - if err == nil { - log.Fatal("test process terminated unexpectedly") - } - log.Fatal(err) - default: - break - } - - if ps.Stat().Comm != "test-helper" { - return false - } - - var args []string - if args, err = ps.Stat().Args(); err != nil { - if testsuite.IsNotExist(err) { - return false - } - log.Fatal(err) - } else if !slices.Equal(args, tc.Hakurei.Container.Args) { - return false - } - - if err = ps.Stat().Stat(&stat); err != nil { - if testsuite.IsNotExist(err) { - return false - } - log.Fatal(err) - } - - uid := hst.ToUser[uint32](0, uint32(tc.Hakurei.Identity)) - if stat.Uid != uid || stat.Gid != uid { - return false - } - - var t []byte - if t, err = os.ReadFile(filepath.Join( - fhs.Proc, - strconv.Itoa(ps.Stat().PPID), - "stat", - )); err != nil { - if testsuite.IsNotExist(err) { - return false - } - log.Fatal(err) - } - - var _stat testsuite.Stat - if err = _stat.UnmarshalText(t); err != nil { - log.Fatal(err) - } - if _stat.PPID != p.ShimPID { - return false - } - - return true - }) - - testsuite.MustCheckFilter( - pid, - tc.Sum, - ) - }) - } - - wg.Wait() - - if dents, err := os.ReadDir("/tmp"); err != nil { - log.Fatal(err) - } else { - for _, dent := range dents { - if name := dent.Name(); strings.HasPrefix(name, ".hakurei-shim-") { - log.Fatalf("leftover shim work dir %q", name) - } - } - } -} |
