diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-10-29 04:32:43 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-10-29 04:33:13 +0900 |
| commit | a0b4e47acc228e48165966d8e139277b8f6f450e (patch) | |
| tree | d363a6781536ce946aa445271ca1d3df587e6031 /internal/outcome/hsu_test.go | |
| parent | a52f7038e5a607dd0901244abb791c96deaf9c2d (diff) | |
internal/outcome: rename from app
This is less ambiguous, and more accurately describes the purpose of the package.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/outcome/hsu_test.go')
| -rw-r--r-- | internal/outcome/hsu_test.go | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/internal/outcome/hsu_test.go b/internal/outcome/hsu_test.go new file mode 100644 index 00000000..4ee7fa9c --- /dev/null +++ b/internal/outcome/hsu_test.go @@ -0,0 +1,84 @@ +package outcome + +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} +} |
