Skip to content

Commit

Permalink
adds the missing tests for aclFile (#13)
Browse files Browse the repository at this point in the history
* adds aclfile: false to the loop tests

* implement tests for TestSaveAclFile and TestLoadAclFile

* move to aclFile

* adds the missing tests
  • Loading branch information
ncode authored Apr 18, 2024
1 parent 78ebd10 commit bce6e2d
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 31 deletions.
28 changes: 14 additions & 14 deletions pkg/aclmanager/aclmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type AclManager struct {
RedisClient *redis.Client
primary atomic.Bool
nodes map[string]int
aclfile bool
aclFile bool
}

// New creates a new AclManager
Expand All @@ -51,7 +51,7 @@ func New(addr string, username string, password string, aclfile bool) *AclManage
Password: password,
RedisClient: redisClient,
nodes: make(map[string]int),
aclfile: aclfile,
aclFile: aclfile,
}
}

Expand Down Expand Up @@ -126,7 +126,7 @@ func (a *AclManager) Primary(ctx context.Context) (primary *AclManager, err erro

for address, function := range a.nodes {
if function == Primary {
return New(address, a.Username, a.Password, a.aclfile), err
return New(address, a.Username, a.Password, a.aclFile), err
}
}

Expand Down Expand Up @@ -166,21 +166,21 @@ func listAcls(ctx context.Context, client *redis.Client) (acls []string, err err
return acls, nil
}

// saveAclFile call the redis command ACL SAVE to save the acls to the aclfile
// saveAclFile call the redis command ACL SAVE to save the acls to the aclFile
func saveAclFile(ctx context.Context, client *redis.Client) error {
slog.Debug("Saving acls to aclfile")
slog.Debug("Saving acls to aclFile")
if err := client.Do(ctx, "ACL", "SAVE").Err(); err != nil {
return fmt.Errorf("error saving acls to aclfile: %v", err)
return fmt.Errorf("error saving acls to aclFile: %v", err)
}

return nil
}

// loadAclFile call the redis command ACL LOAD to load the acls from the aclfile
// loadAclFile call the redis command ACL LOAD to load the acls from the aclFile
func loadAclFile(ctx context.Context, client *redis.Client) error {
slog.Debug("Loading acls from aclfile")
slog.Debug("Loading acls from aclFile")
if err := client.Do(ctx, "ACL", "LOAD").Err(); err != nil {
return fmt.Errorf("error loading acls from aclfile: %v", err)
return fmt.Errorf("error loading acls from aclFile: %v", err)
}

return nil
Expand All @@ -198,10 +198,10 @@ func (a *AclManager) SyncAcls(ctx context.Context, primary *AclManager) (updated
return nil, nil, fmt.Errorf("error listing source acls: %v", err)
}

if a.aclfile {
if a.aclFile {
err = saveAclFile(ctx, primary.RedisClient)
if err != nil {
return nil, nil, fmt.Errorf("error saving primary acls to aclfile: %v", err)
return nil, nil, fmt.Errorf("error saving primary acls to aclFile: %v", err)
}
}

Expand Down Expand Up @@ -251,14 +251,14 @@ func (a *AclManager) SyncAcls(ctx context.Context, primary *AclManager) (updated
updated = append(updated, username)
}

if a.aclfile {
if a.aclFile {
err = saveAclFile(ctx, a.RedisClient)
if err != nil {
return nil, nil, fmt.Errorf("error saving acls to aclfile: %v", err)
return nil, nil, fmt.Errorf("error saving acls to aclFile: %v", err)
}
err = loadAclFile(ctx, a.RedisClient)
if err != nil {
return nil, nil, fmt.Errorf("error loading synced acls from aclfile: %v", err)
return nil, nil, fmt.Errorf("error loading synced acls from aclFile: %v", err)
}
}

Expand Down
164 changes: 147 additions & 17 deletions pkg/aclmanager/aclmanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,11 @@ func TestSyncAcls(t *testing.T) {
expectedUpdated []string
listAclsError error
redisDoError error
saveAclError error
loadAclError error
wantSourceErr bool
wantDestinationErr bool
aclFile bool
}{
{
name: "ACLs synced with deletions",
Expand Down Expand Up @@ -274,6 +277,37 @@ func TestSyncAcls(t *testing.T) {
name: "Invalid aclManagerPrimary",
listAclsError: fmt.Errorf("error listing destination ACLs"),
},
{
name: "ACLs synced with deletions, aclFile",
sourceAcls: []interface{}{"user acl1", "user acl2"},
destinationAcls: []interface{}{"user acl1", "user acl3"},
expectedDeleted: []string{"acl3"},
expectedUpdated: []string{"acl2"},
aclFile: true,
},
{
name: "Error on save ACL file on primary, aclFile",
sourceAcls: []interface{}{"user acl1", "user acl2"},
saveAclError: fmt.Errorf("failed to save ACL on primary"),
aclFile: true,
wantSourceErr: true,
},
{
name: "Error on save ACL file on destination, aclFile",
sourceAcls: []interface{}{"user acl1", "user acl2"},
destinationAcls: []interface{}{"user acl1", "user acl3"},
saveAclError: fmt.Errorf("failed to save ACL on destination"),
aclFile: true,
wantDestinationErr: true,
},
{
name: "Error on load ACL file, aclFile",
sourceAcls: []interface{}{"user acl1", "user acl2"},
destinationAcls: []interface{}{"user acl1", "user acl3"},
loadAclError: fmt.Errorf("failed to load ACL"),
aclFile: true,
wantDestinationErr: true,
},
}

for _, tt := range tests {
Expand Down Expand Up @@ -322,6 +356,30 @@ func TestSyncAcls(t *testing.T) {
}
}

if tt.listAclsError != nil && tt.wantDestinationErr {
destMock.ExpectDo("ACL", "LIST").SetErr(tt.listAclsError)
} else {
destMock.ExpectDo("ACL", "LIST").SetVal(tt.destinationAcls)
}

if tt.aclFile {
if tt.saveAclError != nil {
sourceMock.ExpectDo("ACL", "SAVE").SetErr(tt.saveAclError)
if !tt.wantSourceErr {
destMock.ExpectDo("ACL", "SAVE").SetErr(tt.saveAclError)
}
} else {
sourceMock.ExpectDo("ACL", "SAVE").SetVal("OK")
destMock.ExpectDo("ACL", "SAVE").SetVal("OK")
}

if tt.loadAclError != nil && !tt.wantSourceErr {
destMock.ExpectDo("ACL", "LOAD").SetErr(tt.loadAclError)
} else {
destMock.ExpectDo("ACL", "LOAD").SetVal("OK")
}
}

added, deleted, err := aclManagerFollower.SyncAcls(context.Background(), aclManagerPrimary)
if err != nil {
if tt.wantSourceErr {
Expand Down Expand Up @@ -531,6 +589,7 @@ func TestAclManager_Loop(t *testing.T) {
Addr: "localhost:6379",
Password: "password",
Username: "username",
aclFile: false,
nodes: make(map[string]int),
},
wantErr: false,
Expand All @@ -541,6 +600,7 @@ func TestAclManager_Loop(t *testing.T) {
Addr: "localhost:6379",
Password: "password",
Username: "username",
aclFile: false,
nodes: make(map[string]int),
},
wantErr: true,
Expand All @@ -552,6 +612,7 @@ func TestAclManager_Loop(t *testing.T) {
Addr: "localhost:6379",
Password: "password",
Username: "username",
aclFile: false,
nodes: make(map[string]int),
},
wantErr: true,
Expand All @@ -563,6 +624,7 @@ func TestAclManager_Loop(t *testing.T) {
Addr: "localhost:6379",
Password: "password",
Username: "username",
aclFile: false,
nodes: make(map[string]int),
},
wantErr: false,
Expand Down Expand Up @@ -650,20 +712,88 @@ func TestClosePanic(t *testing.T) {
assert.Panics(t, func() { aclManager.Close() })
}

//func BenchmarkParseRedisOutputFollower(b *testing.B) {
// for i := 0; i < b.N; i++ {
// _, err := parseRedisOutput(followerOutput)
// if err != nil {
// b.Fatal(err)
// }
// }
//}
//
//func BenchmarkParseRedisOutputMaster(b *testing.B) {
// for i := 0; i < b.N; i++ {
// _, err := parseRedisOutput(primaryOutput)
// if err != nil {
// b.Fatal(err)
// }
// }
//}
func TestSaveAclFile(t *testing.T) {
tests := []struct {
name string
wantErr bool
err error
}{
{
name: "successful ACL save",
wantErr: false,
},
{
name: "error saving ACL to file",
wantErr: true,
err: fmt.Errorf("failed to save ACL"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
redisClient, mock := redismock.NewClientMock()
if tt.wantErr {
mock.ExpectDo("ACL", "SAVE").SetErr(tt.err)
} else {
mock.ExpectDo("ACL", "SAVE").SetVal("OK")
}

ctx := context.Background()
err := saveAclFile(ctx, redisClient)
if (err != nil) != tt.wantErr {
t.Errorf("saveAclFile() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.wantErr && !strings.HasSuffix(err.Error(), tt.err.Error()) {
t.Errorf("saveAclFile() got unexpected error = %v, want %v", err, tt.err)
}

assertExpectations(t, mock)
})
}
}

func assertExpectations(t *testing.T, mock redismock.ClientMock) {
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("there were unmet expectations: %s", err)
}
}

func TestLoadAclFile(t *testing.T) {
tests := []struct {
name string
wantErr bool
err error
}{
{
name: "successful ACL load",
wantErr: false,
},
{
name: "error loading ACL from file",
wantErr: true,
err: fmt.Errorf("failed to load ACL"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
redisClient, mock := redismock.NewClientMock()
if tt.wantErr {
mock.ExpectDo("ACL", "LOAD").SetErr(tt.err)
} else {
mock.ExpectDo("ACL", "LOAD").SetVal("OK")
}

ctx := context.Background()
err := loadAclFile(ctx, redisClient)
if (err != nil) != tt.wantErr {
t.Errorf("loadAclFile() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.wantErr && !strings.HasSuffix(err.Error(), tt.err.Error()) {
t.Errorf("loadAclFile() got unexpected error = %v, want %v", err, tt.err)
}

assertExpectations(t, mock)
})
}
}

0 comments on commit bce6e2d

Please sign in to comment.