aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-10-06 23:11:29 +0900
committerOphestra <cat@gensokyo.uk>2026-10-06 23:11:29 +0900
commita6334d4ff69ce0c02128256f2032617096882ee5 (patch)
treefa3b1d49a6315166bfa5f4e7e2ed616db0e9622b
parenta9e2749f6654d0aa07b274a45c9177d10323f80a (diff)
internal/testsuite: add additional environment
This improves compatibility. This change also improves error messages. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/hakurei/testsuite/sandbox/main.go12
-rw-r--r--internal/testsuite/testsuite.go81
2 files changed, 67 insertions, 26 deletions
diff --git a/cmd/hakurei/testsuite/sandbox/main.go b/cmd/hakurei/testsuite/sandbox/main.go
index 1d3d4516..820b7e2f 100644
--- a/cmd/hakurei/testsuite/sandbox/main.go
+++ b/cmd/hakurei/testsuite/sandbox/main.go
@@ -65,9 +65,9 @@ func mustStart(
select {
case err := <-done:
if err == nil {
- log.Fatal("test process terminated unexpectedly")
+ log.Fatalf("test process %d terminated unexpectedly", serial)
}
- log.Fatal(err)
+ log.Fatalf("test process %d terminated unexpectedly: %v", serial, err)
default:
break
}
@@ -117,7 +117,7 @@ func main() {
log.Fatal(err)
}
- var testToolDone <-chan error
+ var testHelperDone <-chan error
{
cmd := exec.Command(
"go", "build",
@@ -127,7 +127,7 @@ func main() {
"./cmd/hakurei/testsuite/sandbox/tester",
)
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
- testToolDone = testsuite.MustStart(cmd)
+ testHelperDone = testsuite.MustStart(cmd)
}
var wg sync.WaitGroup
@@ -232,8 +232,8 @@ func main() {
defer testsuite.TerminateSway(&cred)
testsuite.MustStartPipeWire(&cred, dbusEnv)
- if err := <-testToolDone; err != nil {
- log.Fatal(err)
+ if err := <-testHelperDone; err != nil {
+ log.Fatalf("cannot compile test helper: %v", err)
}
log.Println("created test helper")
diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go
index 456c36b4..6e48eca1 100644
--- a/internal/testsuite/testsuite.go
+++ b/internal/testsuite/testsuite.go
@@ -13,6 +13,9 @@ import (
"os"
"os/exec"
"os/signal"
+ "os/user"
+ "strconv"
+ "strings"
"sync"
"syscall"
"time"
@@ -25,6 +28,52 @@ func ReceiveSignals() {
log.Fatalf("terminating on signal %s", <-s)
}
+var (
+ // users caches [user.LookupId] calls.
+ users = make(map[string]*user.User)
+ // usersMu synchronises access to users.
+ usersMu sync.RWMutex
+)
+
+// mustLookupId is like [user.LookupId], but the first result is cached.
+func mustLookupId(uid string) *user.User {
+ usersMu.RLock()
+ v, ok := users[uid]
+ usersMu.RUnlock()
+ if ok {
+ return v
+ }
+
+ u, err := user.LookupId(uid)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ usersMu.Lock()
+ users[uid] = u
+ usersMu.Unlock()
+ return u
+}
+
+// MustAppendEnv adds extra environment variables to cmd.
+func MustAppendEnv(cmd *exec.Cmd, env ...string) {
+ if len(cmd.Env) == 0 {
+ var cred syscall.Credential
+ if cmd.SysProcAttr != nil && cmd.SysProcAttr.Credential != nil {
+ cred = *cmd.SysProcAttr.Credential
+ }
+ u := mustLookupId(strconv.Itoa(int(cred.Uid)))
+
+ cmd.Env = append(cmd.Env,
+ "PATH="+os.Getenv("PATH"),
+ "HOME="+u.HomeDir,
+ "USER="+u.Username,
+ "USERNAME="+u.Username,
+ )
+ }
+ cmd.Env = append(cmd.Env, env...)
+}
+
// MustRun runs command and terminates the testsuite on error.
func MustRun(cred *syscall.Credential, extraEnv []string, command ...string) {
cmd := exec.Command(command[0], command[1:]...)
@@ -33,11 +82,9 @@ func MustRun(cred *syscall.Credential, extraEnv []string, command ...string) {
Pdeathsig: syscall.SIGKILL,
Credential: cred,
}
- if len(extraEnv) != 0 {
- cmd.Env = append(cmd.Environ(), extraEnv...)
- }
+ MustAppendEnv(cmd, extraEnv...)
if err := cmd.Run(); err != nil {
- log.Fatal(err)
+ log.Fatalf("must run %s: %v", strings.Join(command, " "), err)
}
}
@@ -54,15 +101,13 @@ func MustFail(cred *syscall.Credential, extraEnv []string, command ...string) {
Pdeathsig: syscall.SIGKILL,
Credential: cred,
}
- if len(extraEnv) != 0 {
- cmd.Env = append(cmd.Environ(), extraEnv...)
- }
+ MustAppendEnv(cmd, extraEnv...)
if err := cmd.Run(); err == nil {
log.Fatal(ErrUnexpectedSuccess)
} else if e, ok := errors.AsType[*exec.ExitError](err); !ok {
- log.Fatal(err)
+ log.Fatalf("must fail %s: %v", strings.Join(command, " "), err)
} else if !e.Exited() {
- log.Fatal(e)
+ log.Fatalf("must fail %s: %v", strings.Join(command, " "), e)
}
}
@@ -91,9 +136,7 @@ func MustStartWith(
Pdeathsig: syscall.SIGTERM,
Credential: cred,
}
- if len(extraEnv) != 0 {
- cmd.Env = append(cmd.Environ(), extraEnv...)
- }
+ MustAppendEnv(cmd, extraEnv...)
return cmd.Process, MustStart(cmd)
}
@@ -140,14 +183,12 @@ func Poll(
Pdeathsig: syscall.SIGKILL,
Credential: cred,
}
- if len(extraEnv) != 0 {
- cmd.Env = append(cmd.Environ(), extraEnv...)
- }
+ MustAppendEnv(cmd, extraEnv...)
if err := cmd.Run(); err != nil {
if e, ok := errors.AsType[*exec.ExitError](err); ok && e.Exited() {
continue
}
- log.Fatal(err)
+ log.Fatalf("poll %s: %v", strings.Join(command, " "), err)
}
break
}
@@ -183,7 +224,7 @@ func MustStartSessionBus(cred *syscall.Credential) (dbusEnv string) {
go func() {
if _err := <-done; _err != nil {
- log.Fatal(_err)
+ log.Fatalf("session bus terminated unexpectedly: %v", _err)
}
log.Fatal("session bus terminated unexpectedly")
}()
@@ -228,7 +269,7 @@ func MustStartSway(
"sway",
)
if err := <-done; err != nil {
- log.Fatal(err)
+ log.Fatalf("sway terminated unexpectedly: %v", err)
}
})
@@ -260,7 +301,7 @@ func MustStartPipeWire(cred *syscall.Credential, dbusEnv string) {
go func() {
if _err := <-done; _err != nil {
- log.Fatal(_err)
+ log.Fatalf("pipewire terminated unexpectedly: %v", _err)
}
log.Fatal("pipewire terminated unexpectedly")
}()
@@ -283,7 +324,7 @@ func MustStartPipeWire(cred *syscall.Credential, dbusEnv string) {
go func() {
if _err := <-_done; _err != nil {
- log.Fatal(_err)
+ log.Fatalf("wireplumber terminated unexpectedly: %v", _err)
}
log.Fatal("wireplumber terminated unexpectedly")
}()