aboutsummaryrefslogtreecommitdiffhomepage
path: root/system
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-09-06 22:30:08 +0900
committerOphestra <cat@gensokyo.uk>2025-09-06 22:30:08 +0900
commit323d132c40a74c5ac7a91731a0c43def2a8be7f1 (patch)
treead68a8f2ec743e6a92efd0ff759e413cc857dc36 /system
parent6cc2b406a45dee7c3fcb686036efdccc1776368d (diff)
system/mkdir: use syscall dispatcher
This enables mkdir op methods to be instrumented. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'system')
-rw-r--r--system/dispatcher.go10
-rw-r--r--system/dispatcher_test.go14
-rw-r--r--system/mkdir.go17
-rw-r--r--system/mkdir_test.go162
4 files changed, 129 insertions, 74 deletions
diff --git a/system/dispatcher.go b/system/dispatcher.go
index 5d5c82bf..038231bb 100644
--- a/system/dispatcher.go
+++ b/system/dispatcher.go
@@ -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...)
diff --git a/system/dispatcher_test.go b/system/dispatcher_test.go
index c459de4b..34973879 100644
--- a/system/dispatcher_test.go
+++ b/system/dispatcher_test.go
@@ -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(
diff --git a/system/mkdir.go b/system/mkdir.go
index 64b02496..97673f08 100644
--- a/system/mkdir.go
+++ b/system/mkdir.go
@@ -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
}
}
diff --git a/system/mkdir_test.go b/system/mkdir_test.go
index 2ead2e10..dd7104b4 100644
--- a/system/mkdir_test.go
+++ b/system/mkdir_test.go
@@ -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},
+
+ {"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}},
+
+ {"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},
+ })
-func TestMkdirString(t *testing.T) {
- testCases := []struct {
- want string
- ephemeral bool
- et Enablement
- }{
- {"ensure", false, User},
- {"ensure", false, Process},
- {"ensure", false, EWayland},
+ 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"`},
- {"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)
- }
- })
- }
+ {"ephemeral", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true},
+ User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9",
+ `mode: -rwx------ type: user path: "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"`},
+ })
}