aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/acl/acl_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/acl/acl_test.go')
-rw-r--r--internal/acl/acl_test.go200
1 files changed, 118 insertions, 82 deletions
diff --git a/internal/acl/acl_test.go b/internal/acl/acl_test.go
index 60c4b702..14f0ca18 100644
--- a/internal/acl/acl_test.go
+++ b/internal/acl/acl_test.go
@@ -18,93 +18,131 @@ import (
"hakurei.app/internal/info"
)
-const testFileName = "acl.test"
-
var (
uid = os.Geteuid()
- cred = int32(os.Geteuid())
+ cred = int32(uid)
)
+// testFile returns the pathname of a newly created test file.
+func testFile(t *testing.T) string {
+ name := filepath.Join(t.TempDir(), "f")
+ f, err := os.Create(name)
+ if err != nil {
+ t.Fatal(err)
+ } else if err = f.Close(); err != nil {
+ t.Fatal(err)
+ }
+ return name
+}
+
func TestUpdate(t *testing.T) {
if info.CanDegrade {
name := filepath.Join(t.TempDir(), "check-degrade")
if err := os.WriteFile(name, nil, 0); err != nil {
t.Fatal(err)
}
- if err := acl.Update(name, os.Geteuid()); errors.Is(err, syscall.ENOTSUP) {
+ if err := acl.Update(name, uid, 0); errors.Is(err, syscall.ENOTSUP) {
t.Skip(err)
}
}
- testFilePath := filepath.Join(t.TempDir(), testFileName)
+ t.Parallel()
- if f, err := os.Create(testFilePath); err != nil {
- t.Fatalf("Create: error = %v", err)
- } else {
- if err = f.Close(); err != nil {
- t.Fatalf("Close: error = %v", err)
- }
+ pathname := testFile(t)
+ cur := getfacl(t, pathname)
+ if len(cur) != 3 {
+ t.Fatalf("unexpected test file acl length %d", len(cur))
}
- defer func() {
- if err := os.Remove(testFilePath); err != nil {
- t.Fatalf("Remove: error = %v", err)
- }
- }()
- cur := getfacl(t, testFilePath)
+ if err := acl.Update(pathname, uid, 0); err != nil {
+ t.Fatalf("(clear) Update: error = %v", err)
+ }
+ if cur = getfacl(t, pathname); len(cur) != 4 {
+ t.Fatalf("(clear) Update: %v", cur)
+ }
- t.Run("default entry count", func(t *testing.T) {
- if len(cur) != 3 {
- t.Fatalf("unexpected test file acl length %d", len(cur))
- }
- })
+ if err := acl.Update(pathname, uid, 0); err != nil {
+ t.Fatalf("(clear*) Update: error = %v", err)
+ }
+ if val := getfacl(t, pathname); !reflect.DeepEqual(val, cur) {
+ t.Fatalf("(clear*) Update: %v, want %v", val, cur)
+ }
- t.Run("default clear mask", func(t *testing.T) {
- if err := acl.Update(testFilePath, uid); err != nil {
- t.Fatalf("Update: error = %v", err)
- }
- if cur = getfacl(t, testFilePath); len(cur) != 4 {
- t.Fatalf("Update: %v", cur)
- }
- })
+ testUpdate(t, "r--", "", cur, acl.Read, true)
+ testUpdate(t, "-w-", "", cur, acl.Write, true)
+ testUpdate(t, "--x", "", cur, acl.Execute, true)
- t.Run("default clear consistency", func(t *testing.T) {
- if err := acl.Update(testFilePath, uid); err != nil {
- t.Fatalf("Update: error = %v", err)
- }
- if val := getfacl(t, testFilePath); !reflect.DeepEqual(val, cur) {
- t.Fatalf("Update: %v, want %v", val, cur)
- }
- })
+ testUpdate(
+ t, "-wx", "", cur,
+ acl.Write|acl.Execute,
+ true,
+ )
+ testUpdate(
+ t, "r-x", "", cur,
+ acl.Read|acl.Execute,
+ true,
+ )
+ testUpdate(
+ t, "rw-", "", cur,
+ acl.Read|acl.Write,
+ true,
+ )
+ testUpdate(
+ t, "rwx", "", cur,
+ acl.Read|acl.Write|acl.Execute,
+ true,
+ )
- testUpdate(t, testFilePath, "r--", cur, fAclPermRead, acl.Read)
- testUpdate(t, testFilePath, "-w-", cur, fAclPermWrite, acl.Write)
- testUpdate(t, testFilePath, "--x", cur, fAclPermExecute, acl.Execute)
- testUpdate(t, testFilePath, "-wx", cur, fAclPermWrite|fAclPermExecute, acl.Write, acl.Execute)
- testUpdate(t, testFilePath, "r-x", cur, fAclPermRead|fAclPermExecute, acl.Read, acl.Execute)
- testUpdate(t, testFilePath, "rw-", cur, fAclPermRead|fAclPermWrite, acl.Read, acl.Write)
- testUpdate(t, testFilePath, "rwx", cur, fAclPermRead|fAclPermWrite|fAclPermExecute, acl.Read, acl.Write, acl.Execute)
+ for i := range 16 {
+ testUpdate(
+ t, "r-x", " "+strconv.Itoa(i), cur,
+ acl.Read|acl.Execute,
+ false,
+ )
+ }
+
+ testUpdate(
+ t, "rwx", " cleanup", cur,
+ acl.Read|acl.Write|acl.Execute,
+ true,
+ )
}
-func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val fAclPerm, perms ...acl.Perm) {
- t.Run(name, func(t *testing.T) {
- t.Cleanup(func() {
- if err := acl.Update(testFilePath, uid); err != nil {
- t.Fatalf("Update: error = %v", err)
- }
- if v := getfacl(t, testFilePath); !reflect.DeepEqual(v, cur) {
- t.Fatalf("Update: %v, want %v", v, cur)
- }
- })
+func testUpdate(
+ t *testing.T,
+ name, suffix string,
+ cur []*getFACLResp,
+ perms acl.Perm,
+ cleanup bool,
+) {
+ t.Run(name+suffix, func(t *testing.T) {
+ t.Parallel()
- if err := acl.Update(testFilePath, uid, perms...); err != nil {
+ pathname := testFile(t)
+ if cleanup {
+ t.Cleanup(func() {
+ if err := acl.Update(pathname, uid, 0); err != nil {
+ t.Fatalf("Update: error = %v", err)
+ }
+ if v := getfacl(t, pathname); !reflect.DeepEqual(v, cur) {
+ t.Fatalf("Update: %v, want %v", v, cur)
+ }
+ })
+ }
+
+ if err := acl.Update(pathname, uid, perms); err != nil {
t.Fatalf("Update: error = %v", err)
}
- r := respByCred(getfacl(t, testFilePath), fAclTypeUser, cred)
+ r := respByCred(getfacl(t, pathname), fAclTypeUser, cred)
if r == nil {
t.Fatalf("Update did not add an ACL entry")
}
- if !r.equals(fAclTypeUser, cred, val) {
+
+ if !r.equals(&getFACLResp{
+ typ: fAclTypeUser,
+ cred: cred,
+ val: perms,
+ }) {
t.Fatalf("Update(%s) = %s", name, r)
}
})
@@ -113,31 +151,24 @@ func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val
type (
getFAclInvocation struct {
cmd *exec.Cmd
- val []*getFAclResp
+ val []*getFACLResp
pe []error
}
- getFAclResp struct {
+ getFACLResp struct {
typ fAclType
cred int32
- val fAclPerm
+ val acl.Perm
raw []byte
}
- fAclPerm uintptr
fAclType uint8
)
const fAclBufSize = 16
const (
- fAclPermRead fAclPerm = 1 << iota
- fAclPermWrite
- fAclPermExecute
-)
-
-const (
fAclTypeUser fAclType = iota
fAclTypeGroup
fAclTypeMask
@@ -149,7 +180,13 @@ func (c *getFAclInvocation) run(name string) error {
panic("attempted to run twice")
}
- c.cmd = exec.Command("getfacl", "--omit-header", "--absolute-names", "--numeric", name)
+ c.cmd = exec.Command(
+ "getfacl",
+ "--omit-header",
+ "--absolute-names",
+ "--numeric",
+ name,
+ )
c.cmd.Stderr = os.Stderr
scanErr := make(chan error, 1)
@@ -166,18 +203,17 @@ func (c *getFAclInvocation) run(name string) error {
return errors.Join(<-scanErr, c.cmd.Wait())
}
-func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) {
- c.val = make([]*getFAclResp, 0, 4+fAclBufSize)
+func (c *getFAclInvocation) parse(r io.Reader, scanErr chan error) {
+ c.val = make([]*getFACLResp, 0, 4+fAclBufSize)
- s := bufio.NewScanner(pipe)
+ s := bufio.NewScanner(r)
for s.Scan() {
fields := bytes.SplitN(s.Bytes(), []byte{':'}, 3)
if len(fields) != 3 {
continue
}
- resp := getFAclResp{}
-
+ var resp getFACLResp
switch string(fields[0]) {
case "user":
resp.typ = fAclTypeUser
@@ -213,7 +249,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) {
} else {
switch fields[2][0] {
case 'r':
- resp.val |= fAclPermRead
+ resp.val |= acl.Read
case '-':
default:
c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][0]))
@@ -221,7 +257,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) {
}
switch fields[2][1] {
case 'w':
- resp.val |= fAclPermWrite
+ resp.val |= acl.Write
case '-':
default:
c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][1]))
@@ -229,7 +265,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) {
}
switch fields[2][2] {
case 'x':
- resp.val |= fAclPermExecute
+ resp.val |= acl.Execute
case '-':
default:
c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][2]))
@@ -244,7 +280,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) {
scanErr <- s.Err()
}
-func (r *getFAclResp) String() string {
+func (r *getFACLResp) String() string {
if r.raw != nil && len(r.raw) > 0 {
return string(r.raw)
}
@@ -252,11 +288,11 @@ func (r *getFAclResp) String() string {
return "(user-initialised resp value)"
}
-func (r *getFAclResp) equals(typ fAclType, cred int32, val fAclPerm) bool {
- return r.typ == typ && r.cred == cred && r.val == val
+func (r *getFACLResp) equals(v *getFACLResp) bool {
+ return r.typ == v.typ && r.cred == v.cred && r.val == v.val
}
-func getfacl(t *testing.T, name string) []*getFAclResp {
+func getfacl(t *testing.T, name string) []*getFACLResp {
c := new(getFAclInvocation)
if err := c.run(name); err != nil {
t.Fatalf("getfacl: error = %v", err)
@@ -267,7 +303,7 @@ func getfacl(t *testing.T, name string) []*getFAclResp {
return c.val
}
-func respByCred(v []*getFAclResp, typ fAclType, cred int32) *getFAclResp {
+func respByCred(v []*getFACLResp, typ fAclType, cred int32) *getFACLResp {
j := -1
for i, r := range v {
if r.typ == typ && r.cred == cred {