hakurei/internal/app/hsu_test.go
Ophestra a103c4a7c7
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m10s
Test / Hakurei (push) Successful in 3m4s
Test / Hpkg (push) Successful in 4m0s
Test / Sandbox (race detector) (push) Successful in 4m3s
Test / Hakurei (race detector) (push) Successful in 4m44s
Test / Flake checks (push) Successful in 1m22s
internal/app/hsu: check behaviour
The stub exec.ExitError is hairy as usual, but internal/app is not cross-platform, so this is okay.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-10-18 20:45:42 +09:00

85 lines
2.8 KiB
Go

package app
import (
"os"
"os/exec"
"reflect"
"strconv"
"syscall"
"testing"
"unsafe"
"hakurei.app/container/stub"
"hakurei.app/hst"
)
func TestHsu(t *testing.T) {
t.Parallel()
t.Run("ensure dispatcher", func(t *testing.T) {
hsu := new(Hsu)
hsu.ensureDispatcher()
k := direct{}
if !reflect.DeepEqual(hsu.k, k) {
t.Errorf("ensureDispatcher: k = %#v, want %#v", hsu.k, k)
}
})
fCheckID := func(k *kstub) error {
hsu := &Hsu{k: k}
id, err := hsu.ID()
k.Verbose(id)
if id0, err0 := hsu.ID(); id0 != id || !reflect.DeepEqual(err0, err) {
t.Fatalf("ID: id0 = %d, err0 = %#v, id = %d, err = %#v", id0, err0, id, err)
}
return err
}
checkSimple(t, "Hsu.ID", []simpleTestCase{
{"hsu nonexistent", fCheckID, stub.Expect{Calls: []stub.Call{
call("mustHsuPath", stub.ExpectArgs{}, m("/run/wrappers/bin/hsu"), nil),
call("cmdOutput", stub.ExpectArgs{"/run/wrappers/bin/hsu", os.Stderr, []string{}, "/"}, ([]byte)(nil), os.ErrNotExist),
call("verbose", stub.ExpectArgs{[]any{-1}}, nil, nil),
}}, &hst.AppError{
Step: "obtain uid from hsu",
Err: os.ErrNotExist,
Msg: "the setuid helper is missing: /run/wrappers/bin/hsu",
}},
{"access", fCheckID, stub.Expect{Calls: []stub.Call{
call("mustHsuPath", stub.ExpectArgs{}, m("/run/wrappers/bin/hsu"), nil),
call("cmdOutput", stub.ExpectArgs{"/run/wrappers/bin/hsu", os.Stderr, []string{}, "/"}, ([]byte)(nil), makeExitError(1<<8)),
call("verbose", stub.ExpectArgs{[]any{-1}}, nil, nil),
}}, &hst.AppError{
Step: "obtain uid from hsu",
Err: ErrHsuAccess,
}},
{"invalid output", fCheckID, stub.Expect{Calls: []stub.Call{
call("mustHsuPath", stub.ExpectArgs{}, m("/run/wrappers/bin/hsu"), nil),
call("cmdOutput", stub.ExpectArgs{"/run/wrappers/bin/hsu", os.Stderr, []string{}, "/"}, []byte{0}, nil),
call("verbose", stub.ExpectArgs{[]any{0}}, nil, nil),
}}, &hst.AppError{
Step: "obtain uid from hsu",
Err: &strconv.NumError{Func: "Atoi", Num: "\x00", Err: strconv.ErrSyntax},
Msg: "invalid uid string from hsu",
}},
{"success", fCheckID, stub.Expect{Calls: []stub.Call{
call("mustHsuPath", stub.ExpectArgs{}, m("/run/wrappers/bin/hsu"), nil),
call("cmdOutput", stub.ExpectArgs{"/run/wrappers/bin/hsu", os.Stderr, []string{}, "/"}, []byte{'0'}, nil),
call("verbose", stub.ExpectArgs{[]any{0}}, nil, nil),
}}, nil},
})
}
// makeExitError populates syscall.WaitStatus in an [exec.ExitError].
// Do not reuse this function in a cross-platform package.
func makeExitError(status syscall.WaitStatus) error {
ps := new(os.ProcessState)
statusV := reflect.ValueOf(ps).Elem().FieldByName("status")
*reflect.NewAt(statusV.Type(), unsafe.Pointer(statusV.UnsafeAddr())).Interface().(*syscall.WaitStatus) = status
return &exec.ExitError{ProcessState: ps}
}