All checks were successful
Test / Create distribution (push) Successful in 1m4s
Test / Sandbox (push) Successful in 2m55s
Test / Hakurei (push) Successful in 3m52s
Test / ShareFS (push) Successful in 3m44s
Test / Sandbox (race detector) (push) Successful in 5m25s
Test / Hakurei (race detector) (push) Successful in 6m35s
Test / Flake checks (push) Successful in 1m22s
This is now usable by internal/report. Signed-off-by: Ophestra <cat@gensokyo.uk>
215 lines
5.9 KiB
Go
215 lines
5.9 KiB
Go
package report_test
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"log"
|
|
"os"
|
|
"reflect"
|
|
"slices"
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"hakurei.app/check"
|
|
"hakurei.app/internal/kobject"
|
|
"hakurei.app/internal/report"
|
|
"hakurei.app/internal/stub"
|
|
"hakurei.app/internal/uevent"
|
|
)
|
|
|
|
type representableUE struct{ stub.UniqueError }
|
|
|
|
func (representableUE) Representable() {}
|
|
|
|
func TestDispatch(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
flag uint64
|
|
errs []report.Error
|
|
|
|
persist bool
|
|
wantFiles []string
|
|
wantLog string
|
|
wantPanic error
|
|
}{
|
|
{"default", 0, []report.Error{
|
|
{
|
|
Severity: report.Fatal,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
{
|
|
Severity: report.Inconsistent,
|
|
Message: "processed inconsistent uevent",
|
|
Err: (&kobject.Event{
|
|
Action: uevent.KOBJ_ADD,
|
|
DevPath: "\x00",
|
|
Env: map[string]string{"V": "\xfd"},
|
|
Sequence: 2,
|
|
}).NewError(kobject.EDuplicateAdd, &kobject.Object{
|
|
State: kobject.StateNew,
|
|
DevPath: "\x00",
|
|
Env: map[string]string{"V": "\xff"},
|
|
}),
|
|
},
|
|
}, true, []string{`{"kind":"fatal","message":"rejecting coldboot loop","error":"unique error 51966 injected by the test suite"}
|
|
`, `{"kind":"inconsistent","message":"processed inconsistent uevent","error":{"fault":1,"event":{"action":"add","devpath":"\u0000","env":{"V":"\ufffd"},"seqnum":2,"subsystem":""},"object":{"state":1,"devpath":"\u0000","subsystem":"","env":{"V":"\ufffd"}}}}
|
|
`}, `dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite
|
|
dispatch: processed inconsistent uevent: duplicate add event on devpath "\x00"
|
|
`, nil},
|
|
|
|
{"strict", report.DStrict, []report.Error{
|
|
{
|
|
Severity: report.Degraded,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
}, true, []string{
|
|
`{"kind":"degradation","message":"rejecting coldboot loop","error":"unique error 51966 injected by the test suite"}
|
|
`,
|
|
}, "dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite\n", report.Error{
|
|
Severity: report.Degraded,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
}},
|
|
|
|
{"strict no recover", report.DStrict | report.DNoRecover, []report.Error{
|
|
{
|
|
Severity: report.Inconsistent,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
}, true, []string{
|
|
`{"kind":"inconsistent","message":"rejecting coldboot loop","error":"unique error 51966 injected by the test suite"}
|
|
`,
|
|
}, "dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite\n", report.Error{
|
|
Severity: report.Inconsistent,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
}},
|
|
|
|
{"no recover", report.DNoRecover, []report.Error{
|
|
{
|
|
Severity: 0xbeef,
|
|
Message: "rejecting coldboot loop",
|
|
Err: representableUE{stub.UniqueError(0xcafe)},
|
|
},
|
|
}, true, []string{
|
|
`{"kind":48879,"message":"rejecting coldboot loop","error":{"UniqueError":51966}}
|
|
`,
|
|
}, "dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite\n", nil},
|
|
|
|
{"early", 0, []report.Error{
|
|
{
|
|
Severity: report.Fatal,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
}, false, nil, "dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite\n", report.Error{
|
|
Severity: report.Fatal,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
}},
|
|
|
|
{"bypass early", report.DBypassEarly, []report.Error{
|
|
{
|
|
Severity: report.Fatal,
|
|
Message: "rejecting coldboot loop",
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
}, false, nil, "dispatch: rejecting coldboot loop: unique error 51966 injected by the test suite\n", nil},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var r report.Reporter
|
|
r.SetFlags(tc.flag)
|
|
var buf bytes.Buffer
|
|
l := log.New(&buf, "dispatch: ", 0)
|
|
r.SetOutput(l)
|
|
|
|
a := check.MustAbs(t.TempDir())
|
|
if tc.persist {
|
|
r.SetPathname(a)
|
|
}
|
|
|
|
var got []report.Error
|
|
r.Notify(func(p report.Error) { got = append(got, p) })
|
|
|
|
var gotPanic any
|
|
func() {
|
|
defer func() { gotPanic = recover() }()
|
|
for _, p := range tc.errs {
|
|
r.Dispatch(p.Severity, p.Message, p.Err)
|
|
}
|
|
}()
|
|
|
|
if gotPanic == nil && !reflect.DeepEqual(got, tc.errs) {
|
|
t.Errorf("Dispatch: %#v, want %#v", got, tc.errs)
|
|
}
|
|
if !reflect.DeepEqual(gotPanic, tc.wantPanic) {
|
|
t.Errorf("Dispatch: panic = %v, want %v", gotPanic, tc.wantPanic)
|
|
}
|
|
if gotLog := buf.String(); gotLog != tc.wantLog {
|
|
t.Errorf("Dispatch: log =\n%s\nwant\n%s", gotLog, tc.wantLog)
|
|
}
|
|
|
|
if tc.persist {
|
|
var names []string
|
|
if dents, err := os.ReadDir(a.String()); err != nil {
|
|
t.Fatal(err)
|
|
} else {
|
|
names = make([]string, len(dents))
|
|
for i, dent := range dents {
|
|
names[i] = dent.Name()
|
|
}
|
|
slices.Sort(names)
|
|
}
|
|
|
|
gotFiles := make([]string, len(names))
|
|
for i, name := range names {
|
|
if p, err := os.ReadFile(a.Append(name).String()); err != nil {
|
|
t.Fatal(err)
|
|
} else {
|
|
gotFiles[i] = unsafe.String(unsafe.SliceData(p), len(p))
|
|
}
|
|
}
|
|
|
|
if !slices.Equal(gotFiles, tc.wantFiles) {
|
|
t.Errorf("Dispatch: persist = %s, want %s", gotFiles, tc.wantFiles)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBadPersist(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var r report.Reporter
|
|
r.SetFlags(report.DNoRecover)
|
|
r.SetPathname(check.MustAbs("/proc/nonexistent"))
|
|
|
|
var pathError *os.PathError
|
|
func() {
|
|
defer func() {
|
|
if !errors.As(recover().(error), &pathError) {
|
|
t.Fatal("invalid panic kind")
|
|
}
|
|
}()
|
|
r.Dispatch(report.Fatal, "\x00", stub.UniqueError(0xbad))
|
|
}()
|
|
if !errors.Is(pathError.Err, os.ErrNotExist) {
|
|
t.Fatalf("Dispatch: panic = %v", pathError)
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
l := log.New(&buf, "persist: ", 0)
|
|
r.SetOutput(l)
|
|
r.SetFlags(0)
|
|
r.Dispatch(report.Fatal, "\x00", stub.UniqueError(0xbad))
|
|
}
|