// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package tentacle import ( "context" "encoding/json" "errors" "os" "os/exec" "path/filepath" "strconv" "syscall" "testing" "time" ) func supervisor_program(t testing.TB) []string { t.Helper() executable, err := os.Executable() if err != nil { t.Fatal(err) } return []string{executable, "-test.run=^TestSupervisorHelper$", "--", "supervisor"} } func supervised_manager(t testing.TB) *Manager { t.Helper() manager, err := NewSupervisedManager(supervisor_program(t), "auto") if err != nil { t.Fatal(err) } t.Cleanup(func() { ctx, cancel := context.WithTimeout(context.Background(), 7*time.Second) defer cancel() if err := manager.Shutdown(ctx); err != nil { t.Error(err) } if manager.Stats() != (Stats{}) { t.Error(manager.Stats()) } }) return manager } func supervised_descendant(t testing.TB, session *Session) int { t.Helper() result, err := session.Invoke(context.Background(), "echo", nil) if err != nil { t.Fatal(err) } value := wait_result(t, result) var pid int if value.Err != nil || json.Unmarshal(value.Value, &pid) != nil || pid <= 1 { t.Fatalf("descendant: %+v", value) } return pid } func wait_supervised_reap(t *testing.T, pid int) { t.Helper() deadline := time.NewTimer(6 * time.Second) defer deadline.Stop() ticker := time.NewTicker(time.Millisecond) defer ticker.Stop() for { if _, err := os.Stat("/proc/" + strconv.Itoa(pid)); os.IsNotExist(err) || errors.Is(err, syscall.ESRCH) { return } select { case <-deadline.C: t.Fatalf("supervisor did not reap descendant %d", pid) case <-ticker.C: } } } func TestSupervisorHelper(t *testing.T) { if os.Args[len(os.Args)-1] == "supervisor" { if err := RunSupervisor(context.Background()); err != nil { os.Exit(1) } os.Exit(0) } if len(os.Args) < 3 || os.Args[len(os.Args)-2] != "supervisor-owner" { return } marker := os.Args[len(os.Args)-1] manager, err := NewSupervisedManager(supervisor_program(t), "auto") if err != nil { t.Fatal(err) } session := start_active(t, manager, "sample", "spawn-chain") pid := supervised_descendant(t, session) if err := os.WriteFile(marker, []byte(strconv.Itoa(pid)), 0600); err != nil { t.Fatal(err) } // Abrupt reader death: no Disable, Shutdown, deferred cleanup or signals. os.Exit(0) } func TestSupervisionWithoutInitToolsCleansDetachedDescendants(t *testing.T) { t.Setenv("PATH", "") t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") for _, mode := range []string{"spawn", "spawn-detached", "spawn-chain"} { t.Run(mode, func(t *testing.T) { manager := supervised_manager(t) first := start_active(t, manager, "first", mode) second := start_active(t, manager, "second", "spawn-detached") pid := supervised_descendant(t, first) other := supervised_descendant(t, second) first.Disable() wait_signal(t, first.Done()) if state, err := first.Status(); state != Stopped || err != nil { t.Fatalf("disable: %s %v", state, err) } wait_supervised_reap(t, pid) if _, err := os.Stat("/proc/" + strconv.Itoa(other)); err != nil { t.Fatal("another session was terminated", err) } second.Disable() wait_signal(t, second.Done()) wait_supervised_reap(t, other) }) } } func TestSupervisionCleansDescendantsAfterReaderDeath(t *testing.T) { t.Setenv("PATH", "") t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") executable, _ := os.Executable() marker := filepath.Join(t.TempDir(), "descendant") ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() command := exec.CommandContext(ctx, executable, "-test.run=^TestSupervisorHelper$", "--", "supervisor-owner", marker) if output, err := command.CombinedOutput(); err != nil { t.Fatalf("owner: %v %s", err, output) } data, err := os.ReadFile(marker) if err != nil { t.Fatal(err) } pid, err := strconv.Atoi(string(data)) if err != nil || pid <= 1 { t.Fatal("invalid descendant marker") } wait_supervised_reap(t, pid) } func TestSupervisionReapsExitedDescendantWhileSessionActive(t *testing.T) { t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") manager := supervised_manager(t) session := start_active(t, manager, "sample", "spawn-chain") pid := supervised_descendant(t, session) if err := syscall.Kill(pid, syscall.SIGKILL); err != nil { t.Fatal(err) } wait_supervised_reap(t, pid) if state, err := session.Status(); state != Active || err != nil { t.Fatalf("descendant exit retired the live session: %s %v", state, err) } // A status flag alone does not prove the main child's protocol still works. _ = supervised_descendant(t, session) } func TestSupervisionMissingProgramReleasesCapacity(t *testing.T) { t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") manager := supervised_manager(t) spec := Spec{ID: "sample", Program: []string{filepath.Join(t.TempDir(), "missing")}} session, err := manager.Start(context.Background(), spec) if err != nil { t.Fatal(err) } wait_signal(t, session.Done()) if state, failure := session.Status(); state != Failed || failure == nil { t.Fatal(state, failure) } healthy := start_active(t, manager, "sample", "echo") healthy.Disable() wait_signal(t, healthy.Done()) } func TestSupervisionRejectsInvalidExplicitCgroupParent(t *testing.T) { for _, parent := range []string{"relative", t.TempDir()} { if _, err := NewSupervisedManager(supervisor_program(t), parent); !errors.Is(err, ErrContainment) { t.Fatalf("silently ignored explicit parent %q: %v", parent, err) } } t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", t.TempDir()) if _, err := NewSupervisedManager(supervisor_program(t), "auto"); !errors.Is(err, ErrContainment) { t.Fatalf("silently ignored configured parent: %v", err) } } func TestSupervisionCancelledStartupReleasesCapacity(t *testing.T) { t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") manager := supervised_manager(t) session, err := manager.Start(context.Background(), child_spec(t, "sample", "hang-start")) if err != nil { t.Fatal(err) } wait_control(t, func() bool { session.mutex.Lock() defer session.mutex.Unlock() return len(session.pending) > 0 }) session.Disable() wait_signal(t, session.Done()) if state, err := session.Status(); state != Stopped || err != nil { t.Fatal(state, err) } healthy := start_active(t, manager, "sample", "echo") healthy.Disable() wait_signal(t, healthy.Done()) } func TestSupervisionDetectsChildExitAfterActivation(t *testing.T) { t.Setenv("CTHULHU_TENTACLE_CGROUP_PARENT", "") manager := supervised_manager(t) session := start_active(t, manager, "sample", "exit-active") wait_signal(t, session.Done()) if state, err := session.Status(); state != Failed || !errors.Is(err, ErrExited) { t.Fatal(state, err) } }