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
				
			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>
		
			
				
	
	
		
			85 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			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}
 | |
| }
 |