hakurei/system/output_test.go
Ophestra 712cfc06d7
All checks were successful
Test / Create distribution (push) Successful in 35s
Test / Sandbox (push) Successful in 1m59s
Test / Hakurei (push) Successful in 3m20s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hpkg (push) Successful in 3m47s
Test / Hakurei (race detector) (push) Successful in 5m21s
Test / Flake checks (push) Successful in 1m35s
container: wrap container init start errors
This helps indicate the exact origin and nature of the error. This eliminates generic WrapErr from container.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-08-30 23:44:48 +09:00

190 lines
4.6 KiB
Go

package system
import (
"errors"
"net"
"os"
"reflect"
"syscall"
"testing"
"hakurei.app/container"
"hakurei.app/internal/hlog"
)
func TestOpError(t *testing.T) {
testCases := []struct {
name string
err error
s string
is error
isF error
}{
{"message", newOpErrorMessage("dbus", ErrDBusConfig,
"attempted to create message bus proxy args without session bus config", false),
"attempted to create message bus proxy args without session bus config",
ErrDBusConfig, syscall.ENOTRECOVERABLE},
{"apply", newOpError("tmpfile", syscall.EBADE, false),
"apply tmpfile: invalid exchange",
syscall.EBADE, syscall.EBADF},
{"revert", newOpError("wayland", syscall.EBADF, true),
"revert wayland: bad file descriptor",
syscall.EBADF, syscall.EBADE},
{"path", newOpError("tmpfile", &os.PathError{Op: "stat", Path: "/run/dbus", Err: syscall.EISDIR}, false),
"stat /run/dbus: is a directory",
syscall.EISDIR, syscall.ENOTDIR},
{"net", newOpError("wayland", &net.OpError{Op: "dial", Net: "unix", Addr: &net.UnixAddr{Name: "/run/user/1000/wayland-1", Net: "unix"}, Err: syscall.ENOENT}, false),
"dial unix /run/user/1000/wayland-1: no such file or directory",
syscall.ENOENT, syscall.EPERM},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Run("error", func(t *testing.T) {
if got := tc.err.Error(); got != tc.s {
t.Errorf("Error: %q, want %q", got, tc.s)
}
})
t.Run("is", func(t *testing.T) {
if !errors.Is(tc.err, tc.is) {
t.Error("Is: unexpected false")
}
if errors.Is(tc.err, tc.isF) {
t.Error("Is: unexpected true")
}
})
})
}
t.Run("new", func(t *testing.T) {
if err := newOpError("check", nil, false); err != nil {
t.Errorf("newOpError: %v", err)
}
if err := newOpErrorMessage("check", nil, "", false); err != nil {
t.Errorf("newOpErrorMessage: %v", err)
}
})
}
func TestSetOutput(t *testing.T) {
oldmsg := msg
t.Cleanup(func() { msg = oldmsg })
msg = nil
t.Run("nil", func(t *testing.T) {
SetOutput(nil)
if _, ok := msg.(*container.DefaultMsg); !ok {
t.Errorf("SetOutput: %#v", msg)
}
})
t.Run("hlog", func(t *testing.T) {
SetOutput(hlog.Output{})
if _, ok := msg.(hlog.Output); !ok {
t.Errorf("SetOutput: %#v", msg)
}
})
t.Run("reset", func(t *testing.T) {
SetOutput(nil)
if _, ok := msg.(*container.DefaultMsg); !ok {
t.Errorf("SetOutput: %#v", msg)
}
})
}
func TestPrintJoinedError(t *testing.T) {
testCases := []struct {
name string
err error
want [][]any
}{
{"nil", nil, [][]any{{"not a joined error:", nil}}},
{"unwrapped", syscall.EINVAL, [][]any{{"not a joined error:", syscall.EINVAL}}},
{"single", errors.Join(syscall.EINVAL), [][]any{{"invalid argument"}}},
{"many", errors.Join(syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT, syscall.EBADFD), [][]any{
{"state not recoverable"},
{"connection timed out"},
{"file descriptor in bad state"},
}},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var got [][]any
printJoinedError(func(v ...any) { got = append(got, v) }, "not a joined error:", tc.err)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("printJoinedError: %#v, want %#v", got, tc.want)
}
})
}
}
type tcOp struct {
et Enablement
path string
}
// test an instance of the Op interface
func (ptc tcOp) test(t *testing.T, gotOps []Op, wantOps []Op, fn string) {
if len(gotOps) != len(wantOps) {
t.Errorf("%s: inserted %v Ops, want %v", fn,
len(gotOps), len(wantOps))
return
}
t.Run("path", func(t *testing.T) {
if len(gotOps) > 0 {
if got := gotOps[0].Path(); got != ptc.path {
t.Errorf("Path() = %q, want %q",
got, ptc.path)
return
}
}
})
for i := range gotOps {
o := gotOps[i]
t.Run("is", func(t *testing.T) {
if !o.Is(o) {
t.Errorf("Is returned false on self")
return
}
if !o.Is(wantOps[i]) {
t.Errorf("%s: inserted %#v, want %#v",
fn,
o, wantOps[i])
return
}
})
t.Run("criteria", func(t *testing.T) {
testCases := []struct {
name string
ec *Criteria
want bool
}{
{"nil", nil, ptc.et != User},
{"self", newCriteria(ptc.et), true},
{"all", newCriteria(EWayland | EX11 | EDBus | EPulse | User | Process), true},
{"enablements", newCriteria(EWayland | EX11 | EDBus | EPulse), ptc.et != User && ptc.et != Process},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got := tc.ec.hasType(o); got != tc.want {
t.Errorf("hasType: got %v, want %v",
got, tc.want)
}
})
}
})
}
}
func newCriteria(e Enablement) *Criteria { return (*Criteria)(&e) }