container/stub: export stub helpers
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 1m53s
Test / Hakurei (push) Successful in 3m18s
Test / Sandbox (race detector) (push) Successful in 3m40s
Test / Hpkg (push) Successful in 3m35s
Test / Hakurei (race detector) (push) Successful in 5m19s
Test / Flake checks (push) Successful in 1m39s
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 1m53s
Test / Hakurei (push) Successful in 3m18s
Test / Sandbox (race detector) (push) Successful in 3m40s
Test / Hpkg (push) Successful in 3m35s
Test / Hakurei (race detector) (push) Successful in 5m19s
Test / Flake checks (push) Successful in 1m39s
These are very useful in many packages containing relatively large amount of code making calls to difficult or impossible to stub functions. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -2,7 +2,6 @@ package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
@@ -11,16 +10,14 @@ import (
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
|
||||
var errUnique = errors.New("unique error injected by the test suite")
|
||||
|
||||
type opValidTestCase struct {
|
||||
name string
|
||||
op Op
|
||||
@@ -28,9 +25,15 @@ type opValidTestCase struct {
|
||||
}
|
||||
|
||||
func checkOpsValid(t *testing.T, testCases []opValidTestCase) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("valid", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if got := tc.op.Valid(); got != tc.want {
|
||||
t.Errorf("Valid: %v, want %v", got, tc.want)
|
||||
}
|
||||
@@ -46,9 +49,15 @@ type opsBuilderTestCase struct {
|
||||
}
|
||||
|
||||
func checkOpsBuilder(t *testing.T, testCases []opsBuilderTestCase) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("build", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if !slices.EqualFunc(*tc.ops, tc.want, func(op Op, v Op) bool { return op.Is(v) }) {
|
||||
t.Errorf("Ops: %#v, want %#v", tc.ops, tc.want)
|
||||
}
|
||||
@@ -64,9 +73,15 @@ type opIsTestCase struct {
|
||||
}
|
||||
|
||||
func checkOpIs(t *testing.T, testCases []opIsTestCase) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("is", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if got := tc.op.Is(tc.v); got != tc.want {
|
||||
t.Errorf("Is: %v, want %v", got, tc.want)
|
||||
}
|
||||
@@ -84,16 +99,26 @@ type opMetaTestCase struct {
|
||||
}
|
||||
|
||||
func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("meta", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("prefix", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if got := tc.op.prefix(); got != tc.wantPrefix {
|
||||
t.Errorf("prefix: %q, want %q", got, tc.wantPrefix)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("string", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
if got := tc.op.String(); got != tc.wantString {
|
||||
t.Errorf("String: %s, want %s", got, tc.wantString)
|
||||
}
|
||||
@@ -106,20 +131,26 @@ func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
||||
type simpleTestCase struct {
|
||||
name string
|
||||
f func(k syscallDispatcher) error
|
||||
want [][]kexpect
|
||||
want stub.Expect
|
||||
wantErr error
|
||||
}
|
||||
|
||||
func checkSimple(t *testing.T, fname string, testCases []simpleTestCase) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer handleExitStub()
|
||||
k := &kstub{t: t, want: tc.want, wg: new(sync.WaitGroup)}
|
||||
t.Helper()
|
||||
|
||||
defer stub.HandleExit()
|
||||
k := &kstub{stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} }, tc.want)}
|
||||
if err := tc.f(k); !reflect.DeepEqual(err, tc.wantErr) {
|
||||
t.Errorf("%s: error = %v, want %v", fname, err, tc.wantErr)
|
||||
}
|
||||
k.handleIncomplete(func(k *kstub) {
|
||||
t.Errorf("%s: %d calls, want %d (track %d)", fname, k.pos, len(k.want[k.track]), k.track)
|
||||
k.VisitIncomplete(func(s *stub.Stub[syscallDispatcher]) {
|
||||
t.Helper()
|
||||
|
||||
t.Errorf("%s: %d calls, want %d", fname, s.Pos(), s.Len())
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -130,22 +161,31 @@ type opBehaviourTestCase struct {
|
||||
params *Params
|
||||
op Op
|
||||
|
||||
early []kexpect
|
||||
early []stub.Call
|
||||
wantErrEarly error
|
||||
|
||||
apply []kexpect
|
||||
apply []stub.Call
|
||||
wantErrApply error
|
||||
}
|
||||
|
||||
func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("behaviour", func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer handleExitStub()
|
||||
t.Helper()
|
||||
|
||||
defer stub.HandleExit()
|
||||
state := &setupState{Params: tc.params}
|
||||
k := &kstub{t: t, want: [][]kexpect{slices.Concat(tc.early, []kexpect{{name: "\x00"}}, tc.apply)}, wg: new(sync.WaitGroup)}
|
||||
k := &kstub{stub.New(t,
|
||||
func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{s} },
|
||||
stub.Expect{Calls: slices.Concat(tc.early, []stub.Call{{Name: stub.CallSeparator}}, tc.apply)},
|
||||
)}
|
||||
errEarly := tc.op.early(state, k)
|
||||
k.expect("\x00")
|
||||
k.Expects(stub.CallSeparator)
|
||||
if !reflect.DeepEqual(errEarly, tc.wantErrEarly) {
|
||||
t.Errorf("early: error = %v, want %v", errEarly, tc.wantErrEarly)
|
||||
}
|
||||
@@ -158,8 +198,8 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
}
|
||||
|
||||
out:
|
||||
k.handleIncomplete(func(k *kstub) {
|
||||
count := k.pos - 1 // separator
|
||||
k.VisitIncomplete(func(s *stub.Stub[syscallDispatcher]) {
|
||||
count := k.Pos() - 1 // separator
|
||||
if count < len(tc.early) {
|
||||
t.Errorf("early: %d calls, want %d", count, len(tc.early))
|
||||
} else {
|
||||
@@ -226,8 +266,6 @@ func (writeErrOsFile) Stat() (fs.FileInfo, error) { panic("unreachable") }
|
||||
func (writeErrOsFile) Read([]byte) (int, error) { panic("unreachable") }
|
||||
func (writeErrOsFile) Close() error { panic("unreachable") }
|
||||
|
||||
type expectArgs = [5]any
|
||||
|
||||
type isDirFi bool
|
||||
|
||||
func (isDirFi) Name() string { panic("unreachable") }
|
||||
@@ -252,184 +290,83 @@ func (nameDentry) IsDir() bool { panic("unreachable") }
|
||||
func (nameDentry) Type() fs.FileMode { panic("unreachable") }
|
||||
func (nameDentry) Info() (fs.FileInfo, error) { panic("unreachable") }
|
||||
|
||||
type kexpect struct {
|
||||
name string
|
||||
args expectArgs
|
||||
ret any
|
||||
err error
|
||||
}
|
||||
type kstub struct{ *stub.Stub[syscallDispatcher] }
|
||||
|
||||
func (k *kexpect) error(ok ...bool) error {
|
||||
if !slices.Contains(ok, false) {
|
||||
return k.err
|
||||
}
|
||||
return syscall.ENOTRECOVERABLE
|
||||
}
|
||||
func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) }
|
||||
|
||||
func handleExitStub() {
|
||||
r := recover()
|
||||
if r == 0xdeadbeef {
|
||||
return
|
||||
}
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
|
||||
type kstub struct {
|
||||
t *testing.T
|
||||
|
||||
want [][]kexpect
|
||||
// pos is the current position in want[track].
|
||||
pos int
|
||||
// track is the current active want.
|
||||
track int
|
||||
// sub stores addresses of kstub created by new.
|
||||
sub []*kstub
|
||||
// wg waits for all descendants to complete.
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// handleIncomplete calls f on an incomplete k and all its descendants.
|
||||
func (k *kstub) handleIncomplete(f func(k *kstub)) {
|
||||
k.wg.Wait()
|
||||
|
||||
if k.want != nil && len(k.want[k.track]) != k.pos {
|
||||
f(k)
|
||||
}
|
||||
for _, sk := range k.sub {
|
||||
sk.handleIncomplete(f)
|
||||
}
|
||||
}
|
||||
|
||||
// expect checks name and returns the current kexpect and advances pos.
|
||||
func (k *kstub) expect(name string) (expect *kexpect) {
|
||||
if len(k.want[k.track]) == k.pos {
|
||||
k.t.Fatal("expect: want too short")
|
||||
}
|
||||
expect = &k.want[k.track][k.pos]
|
||||
if name != expect.name {
|
||||
if expect.name == "\x00" {
|
||||
k.t.Fatalf("expect: func = %s, separator overrun", name)
|
||||
}
|
||||
if name == "\x00" {
|
||||
k.t.Fatalf("expect: separator, want %s", expect.name)
|
||||
}
|
||||
k.t.Fatalf("expect: func = %s, want %s", name, expect.name)
|
||||
}
|
||||
k.pos++
|
||||
return
|
||||
}
|
||||
|
||||
// checkArg checks an argument comparable with the == operator. Avoid using this with pointers.
|
||||
func checkArg[T comparable](k *kstub, arg string, got T, n int) bool {
|
||||
if k.pos == 0 {
|
||||
panic("invalid call to checkArg")
|
||||
}
|
||||
expect := k.want[k.track][k.pos-1]
|
||||
want, ok := expect.args[n].(T)
|
||||
if !ok || got != want {
|
||||
k.t.Errorf("%s: %s = %#v, want %#v (%d)", expect.name, arg, got, want, k.pos-1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// checkArgReflect checks an argument of any type.
|
||||
func checkArgReflect(k *kstub, arg string, got any, n int) bool {
|
||||
if k.pos == 0 {
|
||||
panic("invalid call to checkArgReflect")
|
||||
}
|
||||
expect := k.want[k.track][k.pos-1]
|
||||
want := expect.args[n]
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
k.t.Errorf("%s: %s = %#v, want %#v (%d)", expect.name, arg, got, want, k.pos-1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (k *kstub) new(f func(k syscallDispatcher)) {
|
||||
k.expect("new")
|
||||
if len(k.want) <= k.track+1 {
|
||||
k.t.Fatalf("new: track overrun")
|
||||
}
|
||||
sk := &kstub{t: k.t, want: k.want, track: len(k.sub) + 1, wg: k.wg}
|
||||
k.sub = append(k.sub, sk)
|
||||
k.wg.Add(1)
|
||||
go func() {
|
||||
defer k.wg.Done()
|
||||
defer handleExitStub()
|
||||
f(sk)
|
||||
}()
|
||||
}
|
||||
|
||||
func (k *kstub) lockOSThread() { k.expect("lockOSThread") }
|
||||
func (k *kstub) lockOSThread() { k.Helper(); k.Expects("lockOSThread") }
|
||||
|
||||
func (k *kstub) setPtracer(pid uintptr) error {
|
||||
return k.expect("setPtracer").error(
|
||||
checkArg(k, "pid", pid, 0))
|
||||
k.Helper()
|
||||
return k.Expects("setPtracer").Error(
|
||||
stub.CheckArg(k.Stub, "pid", pid, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) setDumpable(dumpable uintptr) error {
|
||||
return k.expect("setDumpable").error(
|
||||
checkArg(k, "dumpable", dumpable, 0))
|
||||
k.Helper()
|
||||
return k.Expects("setDumpable").Error(
|
||||
stub.CheckArg(k.Stub, "dumpable", dumpable, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) setNoNewPrivs() error { return k.expect("setNoNewPrivs").err }
|
||||
func (k *kstub) lastcap() uintptr { return k.expect("lastcap").ret.(uintptr) }
|
||||
func (k *kstub) setNoNewPrivs() error { k.Helper(); return k.Expects("setNoNewPrivs").Err }
|
||||
func (k *kstub) lastcap() uintptr { k.Helper(); return k.Expects("lastcap").Ret.(uintptr) }
|
||||
|
||||
func (k *kstub) capset(hdrp *capHeader, datap *[2]capData) error {
|
||||
return k.expect("capset").error(
|
||||
checkArgReflect(k, "hdrp", hdrp, 0),
|
||||
checkArgReflect(k, "datap", datap, 1))
|
||||
k.Helper()
|
||||
return k.Expects("capset").Error(
|
||||
stub.CheckArgReflect(k.Stub, "hdrp", hdrp, 0),
|
||||
stub.CheckArgReflect(k.Stub, "datap", datap, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) capBoundingSetDrop(cap uintptr) error {
|
||||
return k.expect("capBoundingSetDrop").error(
|
||||
checkArg(k, "cap", cap, 0))
|
||||
k.Helper()
|
||||
return k.Expects("capBoundingSetDrop").Error(
|
||||
stub.CheckArg(k.Stub, "cap", cap, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) capAmbientClearAll() error { return k.expect("capAmbientClearAll").err }
|
||||
func (k *kstub) capAmbientClearAll() error { k.Helper(); return k.Expects("capAmbientClearAll").Err }
|
||||
|
||||
func (k *kstub) capAmbientRaise(cap uintptr) error {
|
||||
return k.expect("capAmbientRaise").error(
|
||||
checkArg(k, "cap", cap, 0))
|
||||
k.Helper()
|
||||
return k.Expects("capAmbientRaise").Error(
|
||||
stub.CheckArg(k.Stub, "cap", cap, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) isatty(fd int) bool {
|
||||
expect := k.expect("isatty")
|
||||
if !checkArg(k, "fd", fd, 0) {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
expect := k.Expects("isatty")
|
||||
if !stub.CheckArg(k.Stub, "fd", fd, 0) {
|
||||
k.FailNow()
|
||||
}
|
||||
return expect.ret.(bool)
|
||||
return expect.Ret.(bool)
|
||||
}
|
||||
|
||||
func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error, err error) {
|
||||
expect := k.expect("receive")
|
||||
k.Helper()
|
||||
expect := k.Expects("receive")
|
||||
|
||||
var closed bool
|
||||
closeFunc = func() error {
|
||||
if closed {
|
||||
k.t.Error("closeFunc called more than once")
|
||||
k.Error("closeFunc called more than once")
|
||||
return os.ErrClosed
|
||||
}
|
||||
closed = true
|
||||
|
||||
if expect.ret != nil {
|
||||
if expect.Ret != nil {
|
||||
// use return stored in kexpect for closeFunc instead
|
||||
return expect.ret.(error)
|
||||
return expect.Ret.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
err = expect.error(
|
||||
checkArg(k, "key", key, 0),
|
||||
checkArgReflect(k, "e", e, 1),
|
||||
checkArgReflect(k, "fdp", fdp, 2))
|
||||
err = expect.Error(
|
||||
stub.CheckArg(k.Stub, "key", key, 0),
|
||||
stub.CheckArgReflect(k.Stub, "e", e, 1),
|
||||
stub.CheckArgReflect(k.Stub, "fdp", fdp, 2))
|
||||
|
||||
// 3 is unused so stores params
|
||||
if expect.args[3] != nil {
|
||||
if v, ok := expect.args[3].(*initParams); ok && v != nil {
|
||||
if expect.Args[3] != nil {
|
||||
if v, ok := expect.Args[3].(*initParams); ok && v != nil {
|
||||
if p, ok0 := e.(*initParams); ok0 && p != nil {
|
||||
*p = *v
|
||||
}
|
||||
@@ -437,8 +374,8 @@ func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error
|
||||
}
|
||||
|
||||
// 4 is unused so stores fd
|
||||
if expect.args[4] != nil {
|
||||
if v, ok := expect.args[4].(uintptr); ok && v >= 3 {
|
||||
if expect.Args[4] != nil {
|
||||
if v, ok := expect.Args[4].(uintptr); ok && v >= 3 {
|
||||
if fdp != nil {
|
||||
*fdp = v
|
||||
}
|
||||
@@ -449,246 +386,277 @@ func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error
|
||||
}
|
||||
|
||||
func (k *kstub) bindMount(source, target string, flags uintptr, eq bool) error {
|
||||
return k.expect("bindMount").error(
|
||||
checkArg(k, "source", source, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "flags", flags, 2),
|
||||
checkArg(k, "eq", eq, 3))
|
||||
k.Helper()
|
||||
return k.Expects("bindMount").Error(
|
||||
stub.CheckArg(k.Stub, "source", source, 0),
|
||||
stub.CheckArg(k.Stub, "target", target, 1),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 2),
|
||||
stub.CheckArg(k.Stub, "eq", eq, 3))
|
||||
}
|
||||
|
||||
func (k *kstub) remount(target string, flags uintptr) error {
|
||||
return k.expect("remount").error(
|
||||
checkArg(k, "target", target, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
k.Helper()
|
||||
return k.Expects("remount").Error(
|
||||
stub.CheckArg(k.Stub, "target", target, 0),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||
return k.expect("mountTmpfs").error(
|
||||
checkArg(k, "fsname", fsname, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "flags", flags, 2),
|
||||
checkArg(k, "size", size, 3),
|
||||
checkArg(k, "perm", perm, 4))
|
||||
k.Helper()
|
||||
return k.Expects("mountTmpfs").Error(
|
||||
stub.CheckArg(k.Stub, "fsname", fsname, 0),
|
||||
stub.CheckArg(k.Stub, "target", target, 1),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 2),
|
||||
stub.CheckArg(k.Stub, "size", size, 3),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||
|
||||
return k.expect("ensureFile").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArg(k, "perm", perm, 1),
|
||||
checkArg(k, "pperm", pperm, 2))
|
||||
k.Helper()
|
||||
return k.Expects("ensureFile").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 1),
|
||||
stub.CheckArg(k.Stub, "pperm", pperm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
||||
return k.expect("seccompLoad").error(
|
||||
checkArgReflect(k, "rules", rules, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
k.Helper()
|
||||
return k.Expects("seccompLoad").Error(
|
||||
stub.CheckArgReflect(k.Stub, "rules", rules, 0),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) notify(c chan<- os.Signal, sig ...os.Signal) {
|
||||
expect := k.expect("notify")
|
||||
if c == nil || expect.error(
|
||||
checkArgReflect(k, "sig", sig, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
expect := k.Expects("notify")
|
||||
if c == nil || expect.Error(
|
||||
stub.CheckArgReflect(k.Stub, "sig", sig, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
|
||||
// export channel for external instrumentation
|
||||
if chanf, ok := expect.args[0].(func(c chan<- os.Signal)); ok && chanf != nil {
|
||||
if chanf, ok := expect.Args[0].(func(c chan<- os.Signal)); ok && chanf != nil {
|
||||
chanf(c)
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) start(c *exec.Cmd) error {
|
||||
expect := k.expect("start")
|
||||
err := expect.error(
|
||||
checkArg(k, "c.Path", c.Path, 0),
|
||||
checkArgReflect(k, "c.Args", c.Args, 1),
|
||||
checkArgReflect(k, "c.Env", c.Env, 2),
|
||||
checkArg(k, "c.Dir", c.Dir, 3))
|
||||
k.Helper()
|
||||
expect := k.Expects("start")
|
||||
err := expect.Error(
|
||||
stub.CheckArg(k.Stub, "c.Path", c.Path, 0),
|
||||
stub.CheckArgReflect(k.Stub, "c.Args", c.Args, 1),
|
||||
stub.CheckArgReflect(k.Stub, "c.Env", c.Env, 2),
|
||||
stub.CheckArg(k.Stub, "c.Dir", c.Dir, 3))
|
||||
|
||||
if process, ok := expect.ret.(*os.Process); ok && process != nil {
|
||||
if process, ok := expect.Ret.(*os.Process); ok && process != nil {
|
||||
c.Process = process
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (k *kstub) signal(c *exec.Cmd, sig os.Signal) error {
|
||||
return k.expect("signal").error(
|
||||
checkArg(k, "c.Path", c.Path, 0),
|
||||
checkArgReflect(k, "c.Args", c.Args, 1),
|
||||
checkArgReflect(k, "c.Env", c.Env, 2),
|
||||
checkArg(k, "c.Dir", c.Dir, 3),
|
||||
checkArg(k, "sig", sig, 4))
|
||||
k.Helper()
|
||||
return k.Expects("signal").Error(
|
||||
stub.CheckArg(k.Stub, "c.Path", c.Path, 0),
|
||||
stub.CheckArgReflect(k.Stub, "c.Args", c.Args, 1),
|
||||
stub.CheckArgReflect(k.Stub, "c.Env", c.Env, 2),
|
||||
stub.CheckArg(k.Stub, "c.Dir", c.Dir, 3),
|
||||
stub.CheckArg(k.Stub, "sig", sig, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) evalSymlinks(path string) (string, error) {
|
||||
expect := k.expect("evalSymlinks")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "path", path, 0))
|
||||
k.Helper()
|
||||
expect := k.Expects("evalSymlinks")
|
||||
return expect.Ret.(string), expect.Error(
|
||||
stub.CheckArg(k.Stub, "path", path, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) exit(code int) {
|
||||
k.expect("exit")
|
||||
if !checkArg(k, "code", code, 0) {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
k.Expects("exit")
|
||||
if !stub.CheckArg(k.Stub, "code", code, 0) {
|
||||
k.FailNow()
|
||||
}
|
||||
panic(0xdeadbeef)
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
func (k *kstub) getpid() int { return k.expect("getpid").ret.(int) }
|
||||
func (k *kstub) getpid() int { k.Helper(); return k.Expects("getpid").Ret.(int) }
|
||||
|
||||
func (k *kstub) stat(name string) (os.FileInfo, error) {
|
||||
expect := k.expect("stat")
|
||||
return expect.ret.(os.FileInfo), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
k.Helper()
|
||||
expect := k.Expects("stat")
|
||||
return expect.Ret.(os.FileInfo), expect.Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdir(name string, perm os.FileMode) error {
|
||||
return k.expect("mkdir").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArg(k, "perm", perm, 1))
|
||||
k.Helper()
|
||||
return k.Expects("mkdir").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdirTemp(dir, pattern string) (string, error) {
|
||||
expect := k.expect("mkdirTemp")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "dir", dir, 0),
|
||||
checkArg(k, "pattern", pattern, 1))
|
||||
k.Helper()
|
||||
expect := k.Expects("mkdirTemp")
|
||||
return expect.Ret.(string), expect.Error(
|
||||
stub.CheckArg(k.Stub, "dir", dir, 0),
|
||||
stub.CheckArg(k.Stub, "pattern", pattern, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mkdirAll(path string, perm os.FileMode) error {
|
||||
return k.expect("mkdirAll").error(
|
||||
checkArg(k, "path", path, 0),
|
||||
checkArg(k, "perm", perm, 1))
|
||||
k.Helper()
|
||||
return k.Expects("mkdirAll").Error(
|
||||
stub.CheckArg(k.Stub, "path", path, 0),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) readdir(name string) ([]os.DirEntry, error) {
|
||||
expect := k.expect("readdir")
|
||||
return expect.ret.([]os.DirEntry), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
k.Helper()
|
||||
expect := k.Expects("readdir")
|
||||
return expect.Ret.([]os.DirEntry), expect.Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) openNew(name string) (osFile, error) {
|
||||
expect := k.expect("openNew")
|
||||
return expect.ret.(osFile), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
k.Helper()
|
||||
expect := k.Expects("openNew")
|
||||
return expect.Ret.(osFile), expect.Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) writeFile(name string, data []byte, perm os.FileMode) error {
|
||||
return k.expect("writeFile").error(
|
||||
checkArg(k, "name", name, 0),
|
||||
checkArgReflect(k, "data", data, 1),
|
||||
checkArg(k, "perm", perm, 2))
|
||||
k.Helper()
|
||||
return k.Expects("writeFile").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0),
|
||||
stub.CheckArgReflect(k.Stub, "data", data, 1),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) createTemp(dir, pattern string) (osFile, error) {
|
||||
expect := k.expect("createTemp")
|
||||
return expect.ret.(osFile), expect.error(
|
||||
checkArg(k, "dir", dir, 0),
|
||||
checkArg(k, "pattern", pattern, 1))
|
||||
k.Helper()
|
||||
expect := k.Expects("createTemp")
|
||||
return expect.Ret.(osFile), expect.Error(
|
||||
stub.CheckArg(k.Stub, "dir", dir, 0),
|
||||
stub.CheckArg(k.Stub, "pattern", pattern, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) remove(name string) error {
|
||||
return k.expect("remove").error(
|
||||
checkArg(k, "name", name, 0))
|
||||
k.Helper()
|
||||
return k.Expects("remove").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) newFile(fd uintptr, name string) *os.File {
|
||||
expect := k.expect("newFile")
|
||||
if expect.error(
|
||||
checkArg(k, "fd", fd, 0),
|
||||
checkArg(k, "name", name, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
expect := k.Expects("newFile")
|
||||
if expect.Error(
|
||||
stub.CheckArg(k.Stub, "fd", fd, 0),
|
||||
stub.CheckArg(k.Stub, "name", name, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
return expect.ret.(*os.File)
|
||||
return expect.Ret.(*os.File)
|
||||
}
|
||||
|
||||
func (k *kstub) symlink(oldname, newname string) error {
|
||||
return k.expect("symlink").error(
|
||||
checkArg(k, "oldname", oldname, 0),
|
||||
checkArg(k, "newname", newname, 1))
|
||||
k.Helper()
|
||||
return k.Expects("symlink").Error(
|
||||
stub.CheckArg(k.Stub, "oldname", oldname, 0),
|
||||
stub.CheckArg(k.Stub, "newname", newname, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) readlink(name string) (string, error) {
|
||||
expect := k.expect("readlink")
|
||||
return expect.ret.(string), expect.error(
|
||||
checkArg(k, "name", name, 0))
|
||||
k.Helper()
|
||||
expect := k.Expects("readlink")
|
||||
return expect.Ret.(string), expect.Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) umask(mask int) (oldmask int) {
|
||||
expect := k.expect("umask")
|
||||
if !checkArg(k, "mask", mask, 0) {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
expect := k.Expects("umask")
|
||||
if !stub.CheckArg(k.Stub, "mask", mask, 0) {
|
||||
k.FailNow()
|
||||
}
|
||||
return expect.ret.(int)
|
||||
return expect.Ret.(int)
|
||||
}
|
||||
|
||||
func (k *kstub) sethostname(p []byte) (err error) {
|
||||
return k.expect("sethostname").error(
|
||||
checkArgReflect(k, "p", p, 0))
|
||||
k.Helper()
|
||||
return k.Expects("sethostname").Error(
|
||||
stub.CheckArgReflect(k.Stub, "p", p, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) chdir(path string) (err error) {
|
||||
return k.expect("chdir").error(
|
||||
checkArg(k, "path", path, 0))
|
||||
k.Helper()
|
||||
return k.Expects("chdir").Error(
|
||||
stub.CheckArg(k.Stub, "path", path, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) fchdir(fd int) (err error) {
|
||||
return k.expect("fchdir").error(
|
||||
checkArg(k, "fd", fd, 0))
|
||||
k.Helper()
|
||||
return k.Expects("fchdir").Error(
|
||||
stub.CheckArg(k.Stub, "fd", fd, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
expect := k.expect("open")
|
||||
return expect.ret.(int), expect.error(
|
||||
checkArg(k, "path", path, 0),
|
||||
checkArg(k, "mode", mode, 1),
|
||||
checkArg(k, "perm", perm, 2))
|
||||
k.Helper()
|
||||
expect := k.Expects("open")
|
||||
return expect.Ret.(int), expect.Error(
|
||||
stub.CheckArg(k.Stub, "path", path, 0),
|
||||
stub.CheckArg(k.Stub, "mode", mode, 1),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) close(fd int) (err error) {
|
||||
return k.expect("close").error(
|
||||
checkArg(k, "fd", fd, 0))
|
||||
k.Helper()
|
||||
return k.Expects("close").Error(
|
||||
stub.CheckArg(k.Stub, "fd", fd, 0))
|
||||
}
|
||||
|
||||
func (k *kstub) pivotRoot(newroot, putold string) (err error) {
|
||||
return k.expect("pivotRoot").error(
|
||||
checkArg(k, "newroot", newroot, 0),
|
||||
checkArg(k, "putold", putold, 1))
|
||||
k.Helper()
|
||||
return k.Expects("pivotRoot").Error(
|
||||
stub.CheckArg(k.Stub, "newroot", newroot, 0),
|
||||
stub.CheckArg(k.Stub, "putold", putold, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) mount(source, target, fstype string, flags uintptr, data string) (err error) {
|
||||
return k.expect("mount").error(
|
||||
checkArg(k, "source", source, 0),
|
||||
checkArg(k, "target", target, 1),
|
||||
checkArg(k, "fstype", fstype, 2),
|
||||
checkArg(k, "flags", flags, 3),
|
||||
checkArg(k, "data", data, 4))
|
||||
k.Helper()
|
||||
return k.Expects("mount").Error(
|
||||
stub.CheckArg(k.Stub, "source", source, 0),
|
||||
stub.CheckArg(k.Stub, "target", target, 1),
|
||||
stub.CheckArg(k.Stub, "fstype", fstype, 2),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 3),
|
||||
stub.CheckArg(k.Stub, "data", data, 4))
|
||||
}
|
||||
|
||||
func (k *kstub) unmount(target string, flags int) (err error) {
|
||||
return k.expect("unmount").error(
|
||||
checkArg(k, "target", target, 0),
|
||||
checkArg(k, "flags", flags, 1))
|
||||
k.Helper()
|
||||
return k.Expects("unmount").Error(
|
||||
stub.CheckArg(k.Stub, "target", target, 0),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) {
|
||||
expect := k.expect("wait4")
|
||||
k.Helper()
|
||||
expect := k.Expects("wait4")
|
||||
// special case to prevent leaking the wait4 goroutine when testing initEntrypoint
|
||||
if v, ok := expect.args[4].(int); ok && v == 0xdeadbeef {
|
||||
k.t.Log("terminating current goroutine as requested by kexpect")
|
||||
panic(0xdeadbeef)
|
||||
if v, ok := expect.Args[4].(int); ok && v == stub.PanicExit {
|
||||
k.Log("terminating current goroutine as requested by kexpect")
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
wpid = expect.ret.(int)
|
||||
err = expect.error(
|
||||
checkArg(k, "pid", pid, 0),
|
||||
checkArg(k, "options", options, 2))
|
||||
wpid = expect.Ret.(int)
|
||||
err = expect.Error(
|
||||
stub.CheckArg(k.Stub, "pid", pid, 0),
|
||||
stub.CheckArg(k.Stub, "options", options, 2))
|
||||
|
||||
if wstatusV, ok := expect.args[1].(syscall.WaitStatus); wstatus != nil && ok {
|
||||
if wstatusV, ok := expect.Args[1].(syscall.WaitStatus); wstatus != nil && ok {
|
||||
*wstatus = wstatusV
|
||||
}
|
||||
if rusageV, ok := expect.args[3].(syscall.Rusage); rusage != nil && ok {
|
||||
if rusageV, ok := expect.Args[3].(syscall.Rusage); rusage != nil && ok {
|
||||
*rusage = rusageV
|
||||
}
|
||||
|
||||
@@ -696,53 +664,50 @@ func (k *kstub) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage
|
||||
}
|
||||
|
||||
func (k *kstub) printf(format string, v ...any) {
|
||||
if k.expect("printf").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
if k.Expects("printf").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) fatal(v ...any) {
|
||||
if k.expect("fatal").error(
|
||||
checkArgReflect(k, "v", v, 0)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
if k.Expects("fatal").Error(
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
panic(0xdeadbeef)
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
func (k *kstub) fatalf(format string, v ...any) {
|
||||
if k.expect("fatalf").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
if k.Expects("fatalf").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
panic(0xdeadbeef)
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
func (k *kstub) verbose(v ...any) {
|
||||
if k.expect("verbose").error(
|
||||
checkArgReflect(k, "v", v, 0)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
if k.Expects("verbose").Error(
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) verbosef(format string, v ...any) {
|
||||
if k.expect("verbosef").error(
|
||||
checkArg(k, "format", format, 0),
|
||||
checkArgReflect(k, "v", v, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
k.Helper()
|
||||
if k.Expects("verbosef").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 1)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) suspend() { k.expect("suspend") }
|
||||
func (k *kstub) resume() bool { return k.expect("resume").ret.(bool) }
|
||||
func (k *kstub) beforeExit() { k.expect("beforeExit") }
|
||||
|
||||
func (k *kstub) printBaseErr(err error, fallback string) {
|
||||
if k.expect("printBaseErr").error(
|
||||
checkArgReflect(k, "err", err, 0),
|
||||
checkArg(k, "fallback", fallback, 1)) != nil {
|
||||
k.t.FailNow()
|
||||
}
|
||||
}
|
||||
func (k *kstub) suspend() { k.Helper(); k.Expects("suspend") }
|
||||
func (k *kstub) resume() bool { k.Helper(); return k.Expects("resume").Ret.(bool) }
|
||||
func (k *kstub) beforeExit() { k.Helper(); k.Expects("beforeExit") }
|
||||
|
||||
Reference in New Issue
Block a user