Skip to content

Commit

Permalink
adding test
Browse files Browse the repository at this point in the history
  • Loading branch information
steiler committed Nov 7, 2023
1 parent 514be46 commit cf9ec7b
Show file tree
Hide file tree
Showing 5 changed files with 320 additions and 4 deletions.
5 changes: 5 additions & 0 deletions aclentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ func (a *ACLEntry) equalTagID(e *ACLEntry) bool {
return true
}

// Equal returns true if the given ACLEntry equals the actual ACLEntry
func (a *ACLEntry) Equal(e *ACLEntry) bool {
return a.id == e.id && a.tag == e.tag && a.perm == e.perm
}

// ToByteSlice returns the ACLEntry as a byte slice in
// little endian order, which is the representation required
// for the Setxattr(...) call
Expand Down
21 changes: 17 additions & 4 deletions acls.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ func (a *ACL) bootstrapACL(fsPath string) error {
// either access or default ACLs to the given filesstem path
func (a *ACL) Apply(fsPath string, attr ACLAttr) error {
b := &bytes.Buffer{}
a.toByteSlice(b)
a.ToByteSlice(b)
return unix.Setxattr(fsPath, string(attr), b.Bytes(), 0)
}

// toByteSlice return the ACL in its byte slice representation
// ToByteSlice return the ACL in its byte slice representation
// read to be used by Setxattr(...)
func (a *ACL) toByteSlice(result *bytes.Buffer) {
func (a *ACL) ToByteSlice(result *bytes.Buffer) {
a.sort()
binary.Write(result, binary.LittleEndian, a.version)
for _, e := range a.entries {
Expand Down Expand Up @@ -138,6 +138,19 @@ func (a *ACL) EntryExists(e *ACLEntry) int {
return -1
}

// Equal returns true if the given ACL equals the actual ACL
func (a *ACL) Equal(e *ACL) bool {
if !(len(a.entries) == len(e.entries) && a.version == e.version) {
return false
}
for id, val := range a.entries {
if !val.Equal(e.entries[id]) {
return false
}
}
return true
}

// parse parses the byte slice that contains the ACLEntries
// and add them to a.entries.
func (a *ACL) parse(b []byte) error {
Expand Down Expand Up @@ -174,7 +187,7 @@ func (a *ACL) String() string {
sb.WriteString("\n")
}

return fmt.Sprintf("Version: %d\nEntries:\n%s\n", a.version, sb.String())
return fmt.Sprintf("Version: %d\nEntries:\n%s", a.version, sb.String())
}

// sort Sorts the ACLEntries stored in a.entries
Expand Down
295 changes: 295 additions & 0 deletions acls_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
package acls

import (
"bytes"
"encoding/hex"
"math"
"testing"
)

func TestACL_String(t *testing.T) {
type fields struct {
version uint32
entries []*ACLEntry
}
tests := []struct {
name string
fields fields
want string
}{
{
name: "Regular, two entries",
fields: fields{
version: 2,
entries: []*ACLEntry{
NewEntry(TAG_ACL_USER, 55, 7),
NewEntry(TAG_ACL_GROUP, 5000, 6),
},
},
want: `Version: 2
Entries:
Tag: USER ( 2), ID: 55, Perm: rwx (7)
Tag: GROUP ( 8), ID: 5000, Perm: rw- (6)
`,
},
{
name: "No Entries",
fields: fields{
version: 2,
entries: []*ACLEntry{},
},
want: `Version: 2
Entries:
`,
},
{
name: "Regular, two entries max uint32 UID",
fields: fields{
version: 2,
entries: []*ACLEntry{
NewEntry(TAG_ACL_USER, math.MaxUint32, 7),
NewEntry(TAG_ACL_GROUP, math.MaxUint32, 2),
},
},
want: `Version: 2
Entries:
Tag: USER ( 2), ID: 4294967295, Perm: rwx (7)
Tag: GROUP ( 8), ID: 4294967295, Perm: -w- (2)
`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &ACL{
version: tt.fields.version,
entries: tt.fields.entries,
}
if got := a.String(); got != tt.want {
t.Errorf("ACL.String() = %v, want %v", got, tt.want)
}
})
}
}

var unsortedACLEntries = []*ACLEntry{
NewEntry(TAG_ACL_USER_OBJ, 2222, 7),
NewEntry(TAG_ACL_EVERYONE, math.MaxUint32, 2),
NewEntry(TAG_ACL_OTHER, math.MaxUint32, 2),
NewEntry(TAG_ACL_MASK, math.MaxUint32, 2),
NewEntry(TAG_ACL_GROUP_OBJ, 6666, 2),
NewEntry(TAG_ACL_GROUP, 7777, 2),
NewEntry(TAG_ACL_USER, 1111, 2),
}

func TestACL_sort(t *testing.T) {
type fields struct {
version uint32
entries []*ACLEntry
}
tests := []struct {
name string
fields fields
want *ACL
}{
{
name: "one",
fields: fields{
version: 2,
entries: unsortedACLEntries,
},
want: &ACL{
version: 2,
entries: []*ACLEntry{
unsortedACLEntries[0],
unsortedACLEntries[6],
unsortedACLEntries[4],
unsortedACLEntries[5],
unsortedACLEntries[3],
unsortedACLEntries[2],
unsortedACLEntries[1],
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := &ACL{
version: tt.fields.version,
entries: tt.fields.entries,
}
a.sort()
for id, val := range a.entries {
if tt.want.entries[id] != val {
t.Logf("Position %d should be %v but is %v", id, tt.want.entries[id], val)
t.Fail()
}
}
})
}
}

func TestACL_parse(t *testing.T) {
type args struct {
s string
}
tests := []struct {
name string
result *ACL
args args
wantErr bool
}{
{
name: "parse",
result: &ACL{
version: 2,
entries: []*ACLEntry{
NewEntry(TAG_ACL_USER_OBJ, 4294967295, 7),
NewEntry(TAG_ACL_GROUP_OBJ, 4294967295, 7),
NewEntry(TAG_ACL_GROUP, 5558, 7),
NewEntry(TAG_ACL_MASK, 4294967295, 7),
NewEntry(TAG_ACL_OTHER, 4294967295, 5),
},
},
args: args{
s: "0200000001000700ffffffff04000700ffffffff08000700b615000010000700ffffffff20000500ffffffff",
},
wantErr: false,
},
{
name: "input to short",
args: args{
s: "0200",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, err := hex.DecodeString(tt.args.s)
acl := &ACL{}
if err != nil {
t.Errorf("failed to decode hex string %q", tt.args.s)
}
if err := acl.parse(b); (err != nil) != tt.wantErr {
t.Errorf("ACL.parse() error = %v, wantErr %v", err, tt.wantErr)
}
if tt.wantErr {
// should not continue with equal check then we expect an error
return
}
if !tt.result.Equal(acl) {
t.Errorf("expected %s, got %s", tt.result.String(), acl.String())
}
})
}
}

func TestACL_ToByteSlice(t *testing.T) {
tests := []struct {
name string
acl *ACL
result string
}{
{
name: "Entries sorted",
acl: &ACL{
version: 2,
entries: []*ACLEntry{
NewEntry(TAG_ACL_USER_OBJ, 4294967295, 7),
NewEntry(TAG_ACL_GROUP_OBJ, 4294967295, 7),
NewEntry(TAG_ACL_GROUP, 5558, 7),
NewEntry(TAG_ACL_MASK, 4294967295, 7),
NewEntry(TAG_ACL_OTHER, 4294967295, 5),
},
},
result: "0200000001000700ffffffff04000700ffffffff08000700b615000010000700ffffffff20000500ffffffff",
},
{
name: "Entries unsorted",
acl: &ACL{
version: 2,
entries: []*ACLEntry{
NewEntry(TAG_ACL_MASK, 4294967295, 7),
NewEntry(TAG_ACL_OTHER, 4294967295, 5),
NewEntry(TAG_ACL_USER_OBJ, 4294967295, 7),
NewEntry(TAG_ACL_GROUP, 5558, 7),
NewEntry(TAG_ACL_GROUP_OBJ, 4294967295, 7),
},
},
result: "0200000001000700ffffffff04000700ffffffff08000700b615000010000700ffffffff20000500ffffffff",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &bytes.Buffer{}
tt.acl.ToByteSlice(b)
result := hex.EncodeToString(b.Bytes())
if result != tt.result {
t.Errorf("byte representations do not match. expected %q, got %q", tt.result, result)
}
})
}
}

func TestACL_AddEntry(t *testing.T) {
tests := []struct {
name string
acl *ACL
addEntry *ACLEntry
wantErr bool
entriesLen int
}{
{
name: "Add to empty",
acl: &ACL{},
addEntry: NewEntry(TAG_ACL_GROUP, 5555, 7),
entriesLen: 1,
wantErr: false,
},
{
name: "Add to existing list",
acl: &ACL{
entries: []*ACLEntry{
NewEntry(TAG_ACL_GROUP, 5556, 7),
NewEntry(TAG_ACL_EVERYONE, math.MaxUint32, 7),
NewEntry(TAG_ACL_GROUP, 8845, 7),
},
},
addEntry: NewEntry(TAG_ACL_GROUP, 5555, 7),
entriesLen: 4,
wantErr: false,
},
{
name: "Add overwriting existing Tag+ID",
acl: &ACL{
entries: []*ACLEntry{
NewEntry(TAG_ACL_EVERYONE, math.MaxUint32, 7),
NewEntry(TAG_ACL_GROUP, 5556, 7),
},
},
addEntry: NewEntry(TAG_ACL_GROUP, 5556, 5),
entriesLen: 2,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.acl.AddEntry(tt.addEntry); (err != nil) != tt.wantErr {
t.Errorf("ACL.AddEntry() error = %v, wantErr %v", err, tt.wantErr)
}
if len(tt.acl.entries) != tt.entriesLen {
t.Errorf("expected %d entries, but contains %d", tt.entriesLen, len(tt.acl.entries))
}
exists := false
for _, e := range tt.acl.entries {
if e.Equal(tt.addEntry) {
exists = true
break
}
}
if !exists {
t.Errorf("expected entry\n%s not found", tt.addEntry.String())
}
})
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/steiler/acls
go 1.20

require (
github.com/google/go-cmp v0.6.0
github.com/sirupsen/logrus v1.9.3
golang.org/x/sys v0.13.0
)
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
Expand Down

0 comments on commit cf9ec7b

Please sign in to comment.