aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-17 20:28:55 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-17 20:28:55 +0900
commit679e719f9e4d9230482491bf253a0d538f030f08 (patch)
tree4b26de24ea9384dbd5cbf569c924efd2bfdc134c /internal/system
parent064db9f02088448b42758dc089787ca7d05b1510 (diff)
system: tests for all Op implementations except DBus
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/system')
-rw-r--r--internal/system/acl_test.go89
-rw-r--r--internal/system/mkdir_test.go73
-rw-r--r--internal/system/op_internal_test.go79
-rw-r--r--internal/system/op_test.go53
-rw-r--r--internal/system/tmpfiles_test.go167
-rw-r--r--internal/system/xhost_test.go34
6 files changed, 495 insertions, 0 deletions
diff --git a/internal/system/acl_test.go b/internal/system/acl_test.go
new file mode 100644
index 00000000..37384e1a
--- /dev/null
+++ b/internal/system/acl_test.go
@@ -0,0 +1,89 @@
+package system
+
+import (
+ "testing"
+
+ "git.ophivana.moe/cat/fortify/acl"
+)
+
+func TestUpdatePerm(t *testing.T) {
+ testCases := []struct {
+ path string
+ perms []acl.Perm
+ }{
+ {"/run/user/1971/fortify", []acl.Perm{acl.Execute}},
+ {"/tmp/fortify.1971/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.path+permSubTestSuffix(tc.perms), func(t *testing.T) {
+ sys := New(150)
+ sys.UpdatePerm(tc.path, tc.perms...)
+ (&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms}}, "UpdatePerm")
+ })
+ }
+}
+
+func TestUpdatePermType(t *testing.T) {
+ testCases := []struct {
+ perms []acl.Perm
+ tcOp
+ }{
+ {[]acl.Perm{acl.Execute}, tcOp{User, "/tmp/fortify.1971/tmpdir"}},
+ {[]acl.Perm{acl.Read, acl.Write, acl.Execute}, tcOp{User, "/tmp/fortify.1971/tmpdir/150"}},
+ {[]acl.Perm{acl.Execute}, tcOp{Process, "/run/user/1971/fortify/fcb8a12f7c482d183ade8288c3de78b5"}},
+ {[]acl.Perm{acl.Read}, tcOp{Process, "/tmp/fortify.1971/fcb8a12f7c482d183ade8288c3de78b5/passwd"}},
+ {[]acl.Perm{acl.Read}, tcOp{Process, "/tmp/fortify.1971/fcb8a12f7c482d183ade8288c3de78b5/group"}},
+ {[]acl.Perm{acl.Read, acl.Write, acl.Execute}, tcOp{EWayland, "/run/user/1971/wayland-0"}},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.path+"_"+TypeString(tc.et)+permSubTestSuffix(tc.perms), func(t *testing.T) {
+ sys := New(150)
+ sys.UpdatePermType(tc.et, tc.path, tc.perms...)
+ tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms}}, "UpdatePermType")
+ })
+ }
+}
+
+func TestACL_String(t *testing.T) {
+ testCases := []struct {
+ want string
+ perms []acl.Perm
+ }{
+ {"---", []acl.Perm{}},
+ {"r--", []acl.Perm{acl.Read}},
+ {"-w-", []acl.Perm{acl.Write}},
+ {"--x", []acl.Perm{acl.Execute}},
+ {"rw-", []acl.Perm{acl.Read, acl.Write}},
+ {"r-x", []acl.Perm{acl.Read, acl.Execute}},
+ {"rwx", []acl.Perm{acl.Read, acl.Write, acl.Execute}},
+ {"rwx", []acl.Perm{acl.Read, acl.Write, acl.Write, acl.Execute}},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.want, func(t *testing.T) {
+ a := &ACL{perms: tc.perms}
+ if got := a.String(); got != tc.want {
+ t.Errorf("String() = %v, want %v",
+ got, tc.want)
+ }
+ })
+ }
+}
+
+func permSubTestSuffix(perms []acl.Perm) (suffix string) {
+ for _, perm := range perms {
+ switch perm {
+ case acl.Read:
+ suffix += "_read"
+ case acl.Write:
+ suffix += "_write"
+ case acl.Execute:
+ suffix += "_execute"
+ default:
+ panic("unreachable")
+ }
+ }
+ return
+}
diff --git a/internal/system/mkdir_test.go b/internal/system/mkdir_test.go
new file mode 100644
index 00000000..20826940
--- /dev/null
+++ b/internal/system/mkdir_test.go
@@ -0,0 +1,73 @@
+package system
+
+import (
+ "os"
+ "testing"
+)
+
+func TestEnsure(t *testing.T) {
+ testCases := []struct {
+ name string
+ perm os.FileMode
+ }{
+ {"/tmp/fortify.1971", 0701},
+ {"/tmp/fortify.1971/tmpdir", 0700},
+ {"/tmp/fortify.1971/tmpdir/150", 0700},
+ {"/run/user/1971/fortify", 0700},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name+"_"+tc.perm.String(), func(t *testing.T) {
+ sys := New(150)
+ sys.Ensure(tc.name, tc.perm)
+ (&tcOp{User, tc.name}).test(t, sys.ops, []Op{&Mkdir{User, tc.name, tc.perm, false}}, "Ensure")
+ })
+ }
+}
+
+func TestEphemeral(t *testing.T) {
+ testCases := []struct {
+ perm os.FileMode
+ tcOp
+ }{
+ {0700, tcOp{Process, "/run/user/1971/fortify/ec07546a772a07cde87389afc84ffd13"}},
+ {0701, tcOp{Process, "/tmp/fortify.1971/ec07546a772a07cde87389afc84ffd13"}},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.path+"_"+tc.perm.String()+"_"+TypeString(tc.et), func(t *testing.T) {
+ sys := New(150)
+ sys.Ephemeral(tc.et, tc.path, tc.perm)
+ tc.test(t, sys.ops, []Op{&Mkdir{tc.et, tc.path, tc.perm, true}}, "Ephemeral")
+ })
+ }
+}
+
+func TestMkdir_String(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},
+ {"D-Bus", true, EDBus},
+ {"PulseAudio", true, EPulse},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.want, func(t *testing.T) {
+ m := &Mkdir{
+ et: tc.et,
+ path: "/nonexistent",
+ perm: 0701,
+ ephemeral: tc.ephemeral,
+ }
+ want := "mode: " + os.FileMode(0701).String() + " type: " + tc.want + " path: \"/nonexistent\""
+ if got := m.String(); got != want {
+ t.Errorf("String() = %v, want %v", got, want)
+ }
+ })
+ }
+}
diff --git a/internal/system/op_internal_test.go b/internal/system/op_internal_test.go
new file mode 100644
index 00000000..7ec4f174
--- /dev/null
+++ b/internal/system/op_internal_test.go
@@ -0,0 +1,79 @@
+package system
+
+import "testing"
+
+type tcOp struct {
+ et Enablement
+ path string
+}
+
+// test an instance of the Op interface
+func (ptc tcOp) test(t *testing.T, gotOps []Op, wantOps []Op, fn string) {
+ if len(gotOps) != len(wantOps) {
+ t.Errorf("%s: inserted %v Ops, want %v", fn,
+ len(gotOps), len(wantOps))
+ return
+ }
+
+ t.Run("path", func(t *testing.T) {
+ if len(gotOps) > 0 {
+ if got := gotOps[0].Path(); got != ptc.path {
+ t.Errorf("Path() = %q, want %q",
+ got, ptc.path)
+ return
+ }
+ }
+ })
+
+ for i := range gotOps {
+ o := gotOps[i]
+
+ t.Run("is", func(t *testing.T) {
+ if !o.Is(o) {
+ t.Errorf("Is returned false on self")
+ return
+ }
+ if !o.Is(wantOps[i]) {
+ t.Errorf("%s: inserted %#v, want %#v",
+ fn,
+ o, wantOps[i])
+ return
+ }
+ })
+
+ t.Run("criteria", func(t *testing.T) {
+ testCases := []struct {
+ name string
+ ec *Criteria
+ want bool
+ }{
+ {"nil", newCriteria(), ptc.et != User},
+ {"self", newCriteria(ptc.et), true},
+ {"all", newCriteria(EWayland, EX11, EDBus, EPulse, User, Process), true},
+ {"enablements", newCriteria(EWayland, EX11, EDBus, EPulse), ptc.et != User && ptc.et != Process},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ if got := tc.ec.hasType(o); got != tc.want {
+ t.Errorf("hasType: got %v, want %v",
+ got, tc.want)
+ }
+ })
+ }
+ })
+ }
+}
+
+func newCriteria(labels ...Enablement) *Criteria {
+ ec := new(Criteria)
+ if len(labels) == 0 {
+ return ec
+ }
+
+ ec.Enablements = new(Enablements)
+ for _, e := range labels {
+ ec.Set(e)
+ }
+ return ec
+}
diff --git a/internal/system/op_test.go b/internal/system/op_test.go
new file mode 100644
index 00000000..428c7ea9
--- /dev/null
+++ b/internal/system/op_test.go
@@ -0,0 +1,53 @@
+package system_test
+
+import (
+ "strconv"
+ "testing"
+
+ "git.ophivana.moe/cat/fortify/internal/system"
+)
+
+func TestNew(t *testing.T) {
+ testCases := []struct {
+ uid int
+ }{
+ {150},
+ {149},
+ {148},
+ {147},
+ }
+
+ for _, tc := range testCases {
+ t.Run("sys initialised with uid "+strconv.Itoa(tc.uid), func(t *testing.T) {
+ if got := system.New(tc.uid); got.UID() != tc.uid {
+ t.Errorf("New(%d) uid = %d, want %d",
+ tc.uid,
+ got.UID(), tc.uid)
+ }
+ })
+ }
+}
+
+func TestTypeString(t *testing.T) {
+ testCases := []struct {
+ e system.Enablement
+ want string
+ }{
+ {system.EWayland, system.EWayland.String()},
+ {system.EX11, system.EX11.String()},
+ {system.EDBus, system.EDBus.String()},
+ {system.EPulse, system.EPulse.String()},
+ {system.User, "User"},
+ {system.Process, "Process"},
+ }
+
+ for _, tc := range testCases {
+ t.Run("label type string "+tc.want, func(t *testing.T) {
+ if got := system.TypeString(tc.e); got != tc.want {
+ t.Errorf("TypeString(%d) = %v, want %v",
+ tc.e,
+ got, tc.want)
+ }
+ })
+ }
+}
diff --git a/internal/system/tmpfiles_test.go b/internal/system/tmpfiles_test.go
new file mode 100644
index 00000000..afd92c7d
--- /dev/null
+++ b/internal/system/tmpfiles_test.go
@@ -0,0 +1,167 @@
+package system
+
+import (
+ "strconv"
+ "testing"
+
+ "git.ophivana.moe/cat/fortify/acl"
+)
+
+func TestCopyFile(t *testing.T) {
+ testCases := []struct {
+ dst, src string
+ }{
+ {"/tmp/fortify.1971/f587afe9fce3c8e1ad5b64deb6c41ad5/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie"},
+ {"/tmp/fortify.1971/62154f708b5184ab01f9dcc2bbe7a33b/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie"},
+ }
+ for _, tc := range testCases {
+ t.Run("copy file "+tc.dst+" from "+tc.src, func(t *testing.T) {
+ sys := New(150)
+ sys.CopyFile(tc.dst, tc.src)
+ (&tcOp{Process, tc.src}).test(t, sys.ops, []Op{
+ &Tmpfile{Process, tmpfileCopy, tc.dst, tc.src},
+ &ACL{Process, tc.dst, []acl.Perm{acl.Read}},
+ }, "CopyFile")
+ })
+ }
+}
+
+func TestCopyFileType(t *testing.T) {
+ testCases := []struct {
+ tcOp
+ dst string
+ }{
+ {tcOp{User, "/tmp/fortify.1971/f587afe9fce3c8e1ad5b64deb6c41ad5/pulse-cookie"}, "/home/ophestra/xdg/config/pulse/cookie"},
+ {tcOp{Process, "/tmp/fortify.1971/62154f708b5184ab01f9dcc2bbe7a33b/pulse-cookie"}, "/home/ophestra/xdg/config/pulse/cookie"},
+ }
+ for _, tc := range testCases {
+ t.Run("copy file "+tc.dst+" from "+tc.path+" with type "+TypeString(tc.et), func(t *testing.T) {
+ sys := New(150)
+ sys.CopyFileType(tc.et, tc.dst, tc.path)
+ tc.test(t, sys.ops, []Op{
+ &Tmpfile{tc.et, tmpfileCopy, tc.dst, tc.path},
+ &ACL{tc.et, tc.dst, []acl.Perm{acl.Read}},
+ }, "CopyFileType")
+ })
+ }
+}
+
+func TestLink(t *testing.T) {
+ testCases := []struct {
+ dst, src string
+ }{
+ {"/tmp/fortify.1971/f587afe9fce3c8e1ad5b64deb6c41ad5/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie"},
+ {"/tmp/fortify.1971/62154f708b5184ab01f9dcc2bbe7a33b/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie"},
+ }
+ for _, tc := range testCases {
+ t.Run("link file "+tc.dst+" from "+tc.src, func(t *testing.T) {
+ sys := New(150)
+ sys.Link(tc.src, tc.dst)
+ (&tcOp{Process, tc.src}).test(t, sys.ops, []Op{
+ &Tmpfile{Process, tmpfileLink, tc.dst, tc.src},
+ }, "Link")
+ })
+ }
+}
+
+func TestLinkFileType(t *testing.T) {
+ testCases := []struct {
+ tcOp
+ dst string
+ }{
+ {tcOp{User, "/tmp/fortify.1971/f587afe9fce3c8e1ad5b64deb6c41ad5/pulse-cookie"}, "/home/ophestra/xdg/config/pulse/cookie"},
+ {tcOp{Process, "/tmp/fortify.1971/62154f708b5184ab01f9dcc2bbe7a33b/pulse-cookie"}, "/home/ophestra/xdg/config/pulse/cookie"},
+ }
+ for _, tc := range testCases {
+ t.Run("link file "+tc.dst+" from "+tc.path+" with type "+TypeString(tc.et), func(t *testing.T) {
+ sys := New(150)
+ sys.LinkFileType(tc.et, tc.path, tc.dst)
+ tc.test(t, sys.ops, []Op{
+ &Tmpfile{tc.et, tmpfileLink, tc.dst, tc.path},
+ }, "LinkFileType")
+ })
+ }
+}
+
+func TestWrite(t *testing.T) {
+ testCases := []struct {
+ dst, src string
+ }{
+ {"/etc/passwd", "chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n"},
+ {"/etc/group", "fortify:x:65534:\n"},
+ }
+ for _, tc := range testCases {
+ t.Run("write "+strconv.Itoa(len(tc.src))+" bytes to "+tc.dst, func(t *testing.T) {
+ sys := New(150)
+ sys.Write(tc.dst, tc.src)
+ (&tcOp{Process, "(" + strconv.Itoa(len(tc.src)) + " bytes of data)"}).test(t, sys.ops, []Op{
+ &Tmpfile{Process, tmpfileWrite, tc.dst, tc.src},
+ &ACL{Process, tc.dst, []acl.Perm{acl.Read}},
+ }, "Write")
+ })
+ }
+}
+
+func TestWriteType(t *testing.T) {
+ testCases := []struct {
+ et Enablement
+ dst, src string
+ }{
+ {Process, "/etc/passwd", "chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n"},
+ {Process, "/etc/group", "fortify:x:65534:\n"},
+ {User, "/etc/passwd", "chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n"},
+ {User, "/etc/group", "fortify:x:65534:\n"},
+ }
+ for _, tc := range testCases {
+ t.Run("write "+strconv.Itoa(len(tc.src))+" bytes to "+tc.dst+" with type "+TypeString(tc.et), func(t *testing.T) {
+ sys := New(150)
+ sys.WriteType(tc.et, tc.dst, tc.src)
+ (&tcOp{tc.et, "(" + strconv.Itoa(len(tc.src)) + " bytes of data)"}).test(t, sys.ops, []Op{
+ &Tmpfile{tc.et, tmpfileWrite, tc.dst, tc.src},
+ &ACL{tc.et, tc.dst, []acl.Perm{acl.Read}},
+ }, "WriteType")
+ })
+ }
+}
+
+func TestTmpfile_String(t *testing.T) {
+ t.Run("invalid method panic", func(t *testing.T) {
+ defer func() {
+ wantPanic := "invalid tmpfile method 255"
+ if r := recover(); r != wantPanic {
+ t.Errorf("String() panic = %v, want %v",
+ r, wantPanic)
+ }
+ }()
+ _ = (&Tmpfile{method: 255}).String()
+ })
+
+ testCases := []struct {
+ method uint8
+ dst, src string
+ want string
+ }{
+ {tmpfileCopy, "/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/pulse-cookie", "/home/ophestra/xdg/config/pulse/cookie",
+ `"/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/pulse-cookie" from "/home/ophestra/xdg/config/pulse/cookie"`},
+ {tmpfileLink, "/run/user/1971/fortify/4b6bdc9182fb2f1d3a965c5fa8b9b66e/wayland", "/run/user/1971/wayland-0",
+ `"/run/user/1971/fortify/4b6bdc9182fb2f1d3a965c5fa8b9b66e/wayland" from "/run/user/1971/wayland-0"`},
+ {tmpfileLink, "/run/user/1971/fortify/4b6bdc9182fb2f1d3a965c5fa8b9b66e/pulse", "/run/user/1971/pulse/native",
+ `"/run/user/1971/fortify/4b6bdc9182fb2f1d3a965c5fa8b9b66e/pulse" from "/run/user/1971/pulse/native"`},
+ {tmpfileWrite, "/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/passwd", "chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n",
+ `75 bytes of data to "/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/passwd"`},
+ {tmpfileWrite, "/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/group", "fortify:x:65534:\n",
+ `17 bytes of data to "/tmp/fortify.1971/4b6bdc9182fb2f1d3a965c5fa8b9b66e/group"`},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.want, func(t *testing.T) {
+ if got := (&Tmpfile{
+ method: tc.method,
+ dst: tc.dst,
+ src: tc.src,
+ }).String(); got != tc.want {
+ t.Errorf("String() = %v, want %v", got, tc.want)
+ }
+ })
+ }
+}
diff --git a/internal/system/xhost_test.go b/internal/system/xhost_test.go
new file mode 100644
index 00000000..4b364432
--- /dev/null
+++ b/internal/system/xhost_test.go
@@ -0,0 +1,34 @@
+package system
+
+import (
+ "testing"
+)
+
+func TestChangeHosts(t *testing.T) {
+ testCases := []string{"chronos", "keyring", "cat", "kbd", "yonah"}
+ for _, tc := range testCases {
+ t.Run("append ChangeHosts operation for "+tc, func(t *testing.T) {
+ sys := New(150)
+ sys.ChangeHosts(tc)
+ (&tcOp{EX11, tc}).test(t, sys.ops, []Op{
+ XHost(tc),
+ }, "ChangeHosts")
+ })
+ }
+}
+
+func TestXHost_String(t *testing.T) {
+ testCases := []struct {
+ username string
+ want string
+ }{
+ {"chronos", "SI:localuser:chronos"},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.want, func(t *testing.T) {
+ if got := XHost(tc.username).String(); got != tc.want {
+ t.Errorf("String() = %v, want %v", got, tc.want)
+ }
+ })
+ }
+}