aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/sandbox/main.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-06 22:23:20 +0900
committerOphestra <cat@gensokyo.uk>2026-10-06 23:09:19 +0900
commita9e2749f6654d0aa07b274a45c9177d10323f80a (patch)
tree291f5b23a67af036cbe5d374b3d3fb0240fc438c /test/sandbox/main.go
parent19f36491f2e2a5029ac396c10408d653cad6c81b (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.go409
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)
- }
- }
- }
-}