package runner
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
)
// A RUNNER THAT STARTS AFTER ONE WAS STOPPED MID-JOB HAS EVERY JOB USER
// HAND BACK EVERY WORKSPACE AND STALE TEMP DIR (#419).
//
// The stopped runner's job left directories only its job user could
// read; the new runner ended that user's processes and nothing more, so
// every checkout into that workspace failed until someone fixed it by
// hand. sudo is a recorder here: the test reads which commands the
// runner asked for, as which user, on which directory.
func TestStartupHandsBackWorkspacesAndStaleTempDirs(t *testing.T) {
bin, work, tmp := t.TempDir(), t.TempDir(), filepath.Join(t.TempDir(), "qr")
rec := filepath.Join(bin, "calls")
fake := "#!/bin/sh\necho \"$*\" >> " + rec + "\nexit 0\n"
if err := os.WriteFile(filepath.Join(bin, "sudo"), []byte(fake), 0o755); err != nil {
t.Fatal(err)
}
t.Setenv("PATH", bin+string(os.PathListSeparator)+os.Getenv("PATH"))
for _, d := range []string{"app.job-0", "app.job-1"} {
if err := os.MkdirAll(filepath.Join(work, "ws", d), 0o755); err != nil {
t.Fatal(err)
}
}
if err := os.WriteFile(filepath.Join(work, "ws", "not-a-dir"), nil, 0o644); err != nil {
t.Fatal(err)
}
// A task dir of a runner that no longer runs: pid 1 is never this
// test, and a pid this large is never alive.
stale := filepath.Join(tmp, fmt.Sprintf("%s%d-123", taskPrefix, 1<<30))
if err := os.MkdirAll(stale, 0o755); err != nil {
t.Fatal(err)
}
r, err := New(Config{
Bridge: "http://127.0.0.1:1", Token: "WT", Tasks: []string{"t"}, MaxTasks: 2,
WorkDir: work, TempRoot: tmp, Checkout: appCheckout{}, JobUsers: []string{"qa", "qb"}, Self: "/bin/true",
Logf: t.Logf,
})
if err != nil {
t.Fatalf("FAIL: New: %v", err)
}
if err := r.sweepTemp(); err != nil {
t.Fatalf("FAIL: sweepTemp: %v", err)
}
r.handBackWorkspaces()
b, _ := os.ReadFile(rec)
calls := string(b)
for _, u := range []string{"qa", "qb"} {
for _, d := range []string{filepath.Join(work, "ws", "app.job-0"), filepath.Join(work, "ws", "app.job-1"), stale} {
want := "-n -u " + u + " -- chmod -R g+rwX " + d
if !strings.Contains(calls, want+"\n") {
t.Errorf("FAIL: user %s was not asked to hand back %s", u, d)
}
}
}
if strings.Contains(calls, "not-a-dir") {
t.Errorf("FAIL: a plain file under ws was handed to chmod -R")
}
if _, err := os.Lstat(stale); !os.IsNotExist(err) {
t.Errorf("FAIL: the stale temp dir is still there: %v", err)
}
t.Log("ok")
}