All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m6s
Test / Flake checks (push) Successful in 1m26s
This allows tests to stub all kernel behaviour, enabling measurement of all function call arguments and error injection. Signed-off-by: Ophestra <cat@gensokyo.uk>
163 lines
3.6 KiB
Go
163 lines
3.6 KiB
Go
package container_test
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"strings"
|
|
"sync/atomic"
|
|
"syscall"
|
|
"testing"
|
|
|
|
"hakurei.app/container"
|
|
"hakurei.app/internal/hlog"
|
|
)
|
|
|
|
func TestDefaultMsg(t *testing.T) {
|
|
// bypass WrapErr testing behaviour
|
|
t.Setenv("GOPATH", container.Nonexistent)
|
|
|
|
{
|
|
w := log.Writer()
|
|
f := log.Flags()
|
|
t.Cleanup(func() { log.SetOutput(w); log.SetFlags(f) })
|
|
}
|
|
msg := new(container.DefaultMsg)
|
|
|
|
t.Run("is verbose", func(t *testing.T) {
|
|
if !msg.IsVerbose() {
|
|
t.Error("IsVerbose unexpected outcome")
|
|
}
|
|
})
|
|
|
|
t.Run("verbose", func(t *testing.T) {
|
|
log.SetOutput(panicWriter{})
|
|
msg.Suspend()
|
|
msg.Verbose()
|
|
msg.Verbosef("\x00")
|
|
msg.Resume()
|
|
|
|
buf := new(strings.Builder)
|
|
log.SetOutput(buf)
|
|
log.SetFlags(0)
|
|
msg.Verbose()
|
|
msg.Verbosef("\x00")
|
|
|
|
want := "\n\x00\n"
|
|
if buf.String() != want {
|
|
t.Errorf("Verbose: %q, want %q", buf.String(), want)
|
|
}
|
|
})
|
|
|
|
t.Run("wrapErr", func(t *testing.T) {
|
|
buf := new(strings.Builder)
|
|
log.SetOutput(buf)
|
|
log.SetFlags(0)
|
|
if err := msg.WrapErr(syscall.EBADE, "\x00", "\x00"); err != syscall.EBADE {
|
|
t.Errorf("WrapErr: %v", err)
|
|
}
|
|
msg.PrintBaseErr(syscall.ENOTRECOVERABLE, "cannot cuddle cat:")
|
|
|
|
want := "\x00 \x00\ncannot cuddle cat: state not recoverable\n"
|
|
if buf.String() != want {
|
|
t.Errorf("WrapErr: %q, want %q", buf.String(), want)
|
|
}
|
|
})
|
|
|
|
t.Run("inactive", func(t *testing.T) {
|
|
{
|
|
inactive := msg.Resume()
|
|
if inactive {
|
|
t.Cleanup(func() { msg.Suspend() })
|
|
}
|
|
}
|
|
|
|
if msg.Resume() {
|
|
t.Error("Resume unexpected outcome")
|
|
}
|
|
|
|
msg.Suspend()
|
|
if !msg.Resume() {
|
|
t.Error("Resume unexpected outcome")
|
|
}
|
|
})
|
|
|
|
// the function is a noop
|
|
t.Run("beforeExit", func(t *testing.T) { msg.BeforeExit() })
|
|
|
|
t.Run("checkedWrappedErr", func(t *testing.T) {
|
|
// temporarily re-enable testing behaviour
|
|
t.Setenv("GOPATH", "")
|
|
wrappedErr := msg.WrapErr(syscall.ENOTRECOVERABLE, "cannot cuddle cat:", syscall.ENOTRECOVERABLE)
|
|
|
|
t.Run("string", func(t *testing.T) {
|
|
want := "state not recoverable, a = [cannot cuddle cat: state not recoverable]"
|
|
if got := wrappedErr.Error(); got != want {
|
|
t.Errorf("Error: %q, want %q", got, want)
|
|
}
|
|
})
|
|
|
|
t.Run("bad concrete type", func(t *testing.T) {
|
|
if errors.Is(wrappedErr, syscall.ENOTRECOVERABLE) {
|
|
t.Error("incorrect type assertion")
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
type panicWriter struct{}
|
|
|
|
func (panicWriter) Write([]byte) (int, error) { panic("unreachable") }
|
|
|
|
func saveRestoreOutput(t *testing.T) {
|
|
out := container.GetOutput()
|
|
t.Cleanup(func() { container.SetOutput(out) })
|
|
}
|
|
|
|
func replaceOutput(t *testing.T) {
|
|
saveRestoreOutput(t)
|
|
container.SetOutput(&testOutput{t: t})
|
|
}
|
|
|
|
type testOutput struct {
|
|
t *testing.T
|
|
suspended atomic.Bool
|
|
}
|
|
|
|
func (out *testOutput) IsVerbose() bool { return testing.Verbose() }
|
|
|
|
func (out *testOutput) Verbose(v ...any) {
|
|
if !out.IsVerbose() {
|
|
return
|
|
}
|
|
out.t.Log(v...)
|
|
}
|
|
|
|
func (out *testOutput) Verbosef(format string, v ...any) {
|
|
if !out.IsVerbose() {
|
|
return
|
|
}
|
|
out.t.Logf(format, v...)
|
|
}
|
|
|
|
func (out *testOutput) WrapErr(err error, a ...any) error { return hlog.WrapErr(err, a...) }
|
|
func (out *testOutput) PrintBaseErr(err error, fallback string) { hlog.PrintBaseError(err, fallback) }
|
|
|
|
func (out *testOutput) Suspend() {
|
|
if out.suspended.CompareAndSwap(false, true) {
|
|
out.Verbose("suspend called")
|
|
return
|
|
}
|
|
out.Verbose("suspend called on suspended output")
|
|
}
|
|
|
|
func (out *testOutput) Resume() bool {
|
|
if out.suspended.CompareAndSwap(true, false) {
|
|
out.Verbose("resume called")
|
|
return true
|
|
}
|
|
out.Verbose("resume called on unsuspended output")
|
|
return false
|
|
}
|
|
|
|
func (out *testOutput) BeforeExit() { out.Verbose("beforeExit called") }
|