100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
package tentacle
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDelegationHelper(t *testing.T) {
|
|
if len(os.Args) < 3 {
|
|
return
|
|
}
|
|
mode, path := os.Args[len(os.Args)-2], os.Args[len(os.Args)-1]
|
|
if mode == "delegation-guardian" {
|
|
if err := RunGuardian(os.Stdin, os.Stdout, path); err != nil {
|
|
os.Exit(1)
|
|
}
|
|
os.Exit(0)
|
|
}
|
|
if mode != "delegation-owner" {
|
|
return
|
|
}
|
|
executable, _ := os.Executable()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
delegation, err := StartDelegation(ctx, []string{executable, "-test.run=^TestDelegationHelper$", "--", "delegation-guardian"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
manager, err := NewDelegatedManager(delegation)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
session, err := manager.Start(ctx, child_spec(t, "spawn", "spawn"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
select {
|
|
case <-session.Ready():
|
|
case <-ctx.Done():
|
|
t.Fatal(ctx.Err())
|
|
}
|
|
if err := session.Activate(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
result, err := session.Invoke(ctx, "echo", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
value := <-result
|
|
if value.Err != nil {
|
|
t.Fatal(value.Err)
|
|
}
|
|
var pid int
|
|
if err := json.Unmarshal(value.Value, &pid); err != nil || pid <= 0 {
|
|
t.Fatalf("descendant: %s %v", value.Value, err)
|
|
}
|
|
if err := os.WriteFile(path, []byte(delegation.Parent), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Simulate abrupt reader death: no Stop, Shutdown, Close, or deferred cleanup.
|
|
os.Exit(0)
|
|
}
|
|
|
|
func TestNativeDelegationReaderDeath(t *testing.T) {
|
|
if os.Getenv("CTHULHU_TENTACLE_MANAGED") != "1" {
|
|
t.Skip("requires a systemd user manager and cgroup v2")
|
|
}
|
|
executable, _ := os.Executable()
|
|
marker := filepath.Join(t.TempDir(), "group")
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
|
defer cancel()
|
|
command := exec.CommandContext(ctx, executable, "-test.run=^TestDelegationHelper$", "--", "delegation-owner", marker)
|
|
if output, err := command.CombinedOutput(); err != nil {
|
|
t.Fatalf("owner: %v %s", err, output)
|
|
}
|
|
parent, err := os.ReadFile(marker)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
timer := time.NewTimer(6 * time.Second)
|
|
defer timer.Stop()
|
|
ticker := time.NewTicker(10 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
for {
|
|
if _, err := os.Stat(string(parent)); os.IsNotExist(err) {
|
|
return
|
|
}
|
|
select {
|
|
case <-ticker.C:
|
|
case <-timer.C:
|
|
t.Fatal("reader death left its service/descendants alive")
|
|
}
|
|
}
|
|
}
|