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.
|
// just synchronising access is not enough, as this is for test instrumentation.
|
||||||
new(f func(k syscallDispatcher))
|
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 provides os.Link.
|
||||||
link(oldname, newname string) error
|
link(oldname, newname string) error
|
||||||
// remove provides os.Remove.
|
// remove provides os.Remove.
|
||||||
@ -44,6 +48,8 @@ type direct struct{}
|
|||||||
|
|
||||||
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
func (k direct) new(f func(k syscallDispatcher)) { go f(k) }
|
||||||
|
|
||||||
|
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) link(oldname, newname string) error { return os.Link(oldname, newname) }
|
||||||
func (k direct) remove(name string) error { return os.Remove(name) }
|
func (k direct) remove(name string) error { return os.Remove(name) }
|
||||||
|
|
||||||
|
@ -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) 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 {
|
func (k *kstub) link(oldname, newname string) error {
|
||||||
k.Helper()
|
k.Helper()
|
||||||
return k.Expects("link").Error(
|
return k.Expects("link").Error(
|
||||||
|
@ -28,32 +28,31 @@ type mkdirOp struct {
|
|||||||
|
|
||||||
func (m *mkdirOp) Type() Enablement { return m.et }
|
func (m *mkdirOp) Type() Enablement { return m.et }
|
||||||
|
|
||||||
func (m *mkdirOp) apply(*I) error {
|
func (m *mkdirOp) apply(sys *I) error {
|
||||||
msg.Verbose("ensuring directory", m)
|
sys.verbose("ensuring directory", m)
|
||||||
|
|
||||||
// create directory
|
if err := sys.mkdir(m.path, m.perm); err != nil {
|
||||||
if err := os.Mkdir(m.path, m.perm); err != nil {
|
|
||||||
if !errors.Is(err, os.ErrExist) {
|
if !errors.Is(err, os.ErrExist) {
|
||||||
return newOpError("mkdir", err, false)
|
return newOpError("mkdir", err, false)
|
||||||
}
|
}
|
||||||
// directory exists, ensure mode
|
// 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 {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mkdirOp) revert(_ *I, ec *Criteria) error {
|
func (m *mkdirOp) revert(sys *I, ec *Criteria) error {
|
||||||
if !m.ephemeral {
|
if !m.ephemeral {
|
||||||
// skip non-ephemeral dir and do not log anything
|
// skip non-ephemeral dir and do not log anything
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ec.hasType(m.Type()) {
|
if ec.hasType(m.Type()) {
|
||||||
msg.Verbose("destroying ephemeral directory", m)
|
sys.verbose("destroying ephemeral directory", m)
|
||||||
return newOpError("mkdir", os.Remove(m.path), true)
|
return newOpError("mkdir", sys.remove(m.path), true)
|
||||||
} else {
|
} else {
|
||||||
msg.Verbose("skipping ephemeral directory", m)
|
sys.verbose("skipping ephemeral directory", m)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,72 +4,108 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container/stub"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEnsure(t *testing.T) {
|
func TestMkdirOp(t *testing.T) {
|
||||||
testCases := []struct {
|
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||||
name string
|
{"mkdir", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||||
perm os.FileMode
|
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)),
|
||||||
{"/tmp/hakurei.1971", 0701},
|
}, &OpError{Op: "mkdir", Err: stub.UniqueError(2)}, nil, nil},
|
||||||
{"/tmp/hakurei.1971/tmpdir", 0700},
|
|
||||||
{"/tmp/hakurei.1971/tmpdir/150", 0700},
|
{"chmod", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{
|
||||||
{"/run/user/1971/hakurei", 0700},
|
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),
|
||||||
for _, tc := range testCases {
|
call("chmod", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, stub.UniqueError(1)),
|
||||||
t.Run(tc.name+"_"+tc.perm.String(), func(t *testing.T) {
|
}, &OpError{Op: "mkdir", Err: stub.UniqueError(1)}, nil, nil},
|
||||||
sys := New(t.Context(), 150)
|
|
||||||
sys.Ensure(tc.name, tc.perm)
|
{"remove", 0xdeadbeef, 0xff, &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{
|
||||||
(&tcOp{User, tc.name}).test(t, sys.ops, []Op{&mkdirOp{User, tc.name, tc.perm, false}}, "Ensure")
|
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}},
|
||||||
|
|
||||||
|
{"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"`},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMkdirString(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
want string
|
|
||||||
ephemeral bool
|
|
||||||
et Enablement
|
|
||||||
}{
|
|
||||||
{"ensure", false, User},
|
|
||||||
{"ensure", false, Process},
|
|
||||||
{"ensure", false, EWayland},
|
|
||||||
|
|
||||||
{"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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user