system/mkdir: use syscall dispatcher
All checks were successful
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m55s
Test / Sandbox (race detector) (push) Successful in 4m29s
Test / Hakurei (race detector) (push) Successful in 5m4s
Test / Flake checks (push) Successful in 1m25s
All checks were successful
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m55s
Test / Sandbox (race detector) (push) Successful in 4m29s
Test / Hakurei (race detector) (push) Successful in 5m4s
Test / Flake checks (push) Successful in 1m25s
This enables mkdir op methods to be instrumented. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
6cc2b406a4
commit
323d132c40
@ -15,6 +15,10 @@ type syscallDispatcher interface {
|
||||
// just synchronising access is not enough, as this is for test instrumentation.
|
||||
new(f func(k syscallDispatcher))
|
||||
|
||||
// mkdir provides os.Mkdir.
|
||||
mkdir(name string, perm os.FileMode) error
|
||||
// chmod provides os.Chmod.
|
||||
chmod(name string, mode os.FileMode) error
|
||||
// link provides os.Link.
|
||||
link(oldname, newname string) error
|
||||
// remove provides os.Remove.
|
||||
@ -44,8 +48,10 @@ type direct struct{}
|
||||
|
||||
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
||||
|
||||
func (k direct) link(oldname, newname string) error { return os.Link(oldname, newname) }
|
||||
func (k direct) remove(name string) error { return os.Remove(name) }
|
||||
func (k direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) }
|
||||
func (k direct) chmod(name string, mode os.FileMode) error { return os.Chmod(name, mode) }
|
||||
func (k direct) link(oldname, newname string) error { return os.Link(oldname, newname) }
|
||||
func (k direct) remove(name string) error { return os.Remove(name) }
|
||||
|
||||
func (k direct) aclUpdate(name string, uid int, perms ...acl.Perm) error {
|
||||
return acl.Update(name, uid, perms...)
|
||||
|
@ -192,6 +192,20 @@ type kstub struct{ *stub.Stub[syscallDispatcher] }
|
||||
|
||||
func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) }
|
||||
|
||||
func (k *kstub) mkdir(name string, perm os.FileMode) error {
|
||||
k.Helper()
|
||||
return k.Expects("mkdir").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0),
|
||||
stub.CheckArg(k.Stub, "perm", perm, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) chmod(name string, mode os.FileMode) error {
|
||||
k.Helper()
|
||||
return k.Expects("chmod").Error(
|
||||
stub.CheckArg(k.Stub, "name", name, 0),
|
||||
stub.CheckArg(k.Stub, "mode", mode, 1))
|
||||
}
|
||||
|
||||
func (k *kstub) link(oldname, newname string) error {
|
||||
k.Helper()
|
||||
return k.Expects("link").Error(
|
||||
|
@ -28,32 +28,31 @@ type mkdirOp struct {
|
||||
|
||||
func (m *mkdirOp) Type() Enablement { return m.et }
|
||||
|
||||
func (m *mkdirOp) apply(*I) error {
|
||||
msg.Verbose("ensuring directory", m)
|
||||
func (m *mkdirOp) apply(sys *I) error {
|
||||
sys.verbose("ensuring directory", m)
|
||||
|
||||
// create directory
|
||||
if err := os.Mkdir(m.path, m.perm); err != nil {
|
||||
if err := sys.mkdir(m.path, m.perm); err != nil {
|
||||
if !errors.Is(err, os.ErrExist) {
|
||||
return newOpError("mkdir", err, false)
|
||||
}
|
||||
// directory exists, ensure mode
|
||||
return newOpError("mkdir", os.Chmod(m.path, m.perm), false)
|
||||
return newOpError("mkdir", sys.chmod(m.path, m.perm), false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mkdirOp) revert(_ *I, ec *Criteria) error {
|
||||
func (m *mkdirOp) revert(sys *I, ec *Criteria) error {
|
||||
if !m.ephemeral {
|
||||
// skip non-ephemeral dir and do not log anything
|
||||
return nil
|
||||
}
|
||||
|
||||
if ec.hasType(m.Type()) {
|
||||
msg.Verbose("destroying ephemeral directory", m)
|
||||
return newOpError("mkdir", os.Remove(m.path), true)
|
||||
sys.verbose("destroying ephemeral directory", m)
|
||||
return newOpError("mkdir", sys.remove(m.path), true)
|
||||
} else {
|
||||
msg.Verbose("skipping ephemeral directory", m)
|
||||
sys.verbose("skipping ephemeral directory", m)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -4,72 +4,108 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
|
||||
func TestEnsure(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
perm os.FileMode
|
||||
}{
|
||||
{"/tmp/hakurei.1971", 0701},
|
||||
{"/tmp/hakurei.1971/tmpdir", 0700},
|
||||
{"/tmp/hakurei.1971/tmpdir/150", 0700},
|
||||
{"/run/user/1971/hakurei", 0700},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name+"_"+tc.perm.String(), func(t *testing.T) {
|
||||
sys := New(t.Context(), 150)
|
||||
sys.Ensure(tc.name, tc.perm)
|
||||
(&tcOp{User, tc.name}).test(t, sys.ops, []Op{&mkdirOp{User, tc.name, tc.perm, false}}, "Ensure")
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestMkdirOp(t *testing.T) {
|
||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||
{"mkdir", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, stub.UniqueError(2)),
|
||||
}, &OpError{Op: "mkdir", Err: stub.UniqueError(2)}, nil, nil},
|
||||
|
||||
func TestEphemeral(t *testing.T) {
|
||||
testCases := []struct {
|
||||
perm os.FileMode
|
||||
tcOp
|
||||
}{
|
||||
{0700, tcOp{Process, "/run/user/1971/hakurei/ec07546a772a07cde87389afc84ffd13"}},
|
||||
{0701, tcOp{Process, "/tmp/hakurei.1971/ec07546a772a07cde87389afc84ffd13"}},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.path+"_"+tc.perm.String()+"_"+TypeString(tc.et), func(t *testing.T) {
|
||||
sys := New(t.Context(), 150)
|
||||
sys.Ephemeral(tc.et, tc.path, tc.perm)
|
||||
tc.test(t, sys.ops, []Op{&mkdirOp{tc.et, tc.path, tc.perm, true}}, "Ephemeral")
|
||||
})
|
||||
}
|
||||
}
|
||||
{"chmod", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, os.ErrExist),
|
||||
call("chmod", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, stub.UniqueError(1)),
|
||||
}, &OpError{Op: "mkdir", Err: stub.UniqueError(1)}, nil, nil},
|
||||
|
||||
func TestMkdirString(t *testing.T) {
|
||||
testCases := []struct {
|
||||
want string
|
||||
ephemeral bool
|
||||
et Enablement
|
||||
}{
|
||||
{"ensure", false, User},
|
||||
{"ensure", false, Process},
|
||||
{"ensure", false, EWayland},
|
||||
{"remove", 0xdeadbeef, 0xff, &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil),
|
||||
}, nil, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"destroying ephemeral directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"}, nil, stub.UniqueError(0)),
|
||||
}, &OpError{Op: "mkdir", Err: stub.UniqueError(0), Revert: true}},
|
||||
|
||||
{"wayland", true, EWayland},
|
||||
{"x11", true, EX11},
|
||||
{"dbus", true, EDBus},
|
||||
{"pulseaudio", true, EPulse},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.want, func(t *testing.T) {
|
||||
m := &mkdirOp{
|
||||
et: tc.et,
|
||||
path: container.Nonexistent,
|
||||
perm: 0701,
|
||||
ephemeral: tc.ephemeral,
|
||||
}
|
||||
want := "mode: " + os.FileMode(0701).String() + " type: " + tc.want + ` path: "/proc/nonexistent"`
|
||||
if got := m.String(); got != want {
|
||||
t.Errorf("String() = %v, want %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
{"success exist chmod", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, os.ErrExist),
|
||||
call("chmod", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil),
|
||||
}, nil, nil, nil},
|
||||
|
||||
{"success ensure", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil),
|
||||
}, nil, nil, nil},
|
||||
|
||||
{"success skip", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil),
|
||||
}, nil, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"skipping ephemeral directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
}, nil},
|
||||
|
||||
{"success", 0xdeadbeef, 0xff, &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil),
|
||||
}, nil, []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"destroying ephemeral directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil),
|
||||
call("remove", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"}, nil, nil),
|
||||
}, nil},
|
||||
})
|
||||
|
||||
checkOpsBuilder(t, "EnsureEphemeral", []opsBuilderTestCase{
|
||||
{"ensure", 0xcafebabe, func(_ *testing.T, sys *I) {
|
||||
sys.Ensure("/tmp/hakurei.0", 0700)
|
||||
}, []Op{
|
||||
&mkdirOp{User, "/tmp/hakurei.0", 0700, false},
|
||||
}, stub.Expect{}},
|
||||
|
||||
{"ephemeral", 0xcafebabe, func(_ *testing.T, sys *I) {
|
||||
sys.Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711)
|
||||
}, []Op{
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true},
|
||||
}, stub.Expect{}},
|
||||
})
|
||||
|
||||
checkOpIs(t, []opIsTestCase{
|
||||
{"nil", (*mkdirOp)(nil), (*mkdirOp)(nil), false},
|
||||
{"zero", new(mkdirOp), new(mkdirOp), true},
|
||||
|
||||
{"ephemeral differs",
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, false},
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
false},
|
||||
|
||||
{"perm differs",
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0701, true},
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
false},
|
||||
|
||||
{"path differs",
|
||||
&mkdirOp{Process, "/tmp/hakurei.1/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
false},
|
||||
|
||||
{"et differs",
|
||||
&mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
false},
|
||||
|
||||
{"equals",
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
true},
|
||||
})
|
||||
|
||||
checkOpMeta(t, []opMetaTestCase{
|
||||
{"ensure", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, false},
|
||||
User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9",
|
||||
`mode: -rwx------ type: ensure path: "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"`},
|
||||
|
||||
{"ephemeral", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
|
||||
User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9",
|
||||
`mode: -rwx------ type: user path: "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"`},
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user