github.com/minio/console@v1.3.0/api/admin_groups_test.go (about) 1 // This file is part of MinIO Console Server 2 // Copyright (c) 2021 MinIO, Inc. 3 // 4 // This program is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Affero General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // This program is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Affero General Public License for more details. 13 // 14 // You should have received a copy of the GNU Affero General Public License 15 // along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "testing" 24 25 "github.com/go-openapi/swag" 26 "github.com/minio/console/models" 27 "github.com/minio/madmin-go/v3" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 func TestListGroups(t *testing.T) { 32 assert := assert.New(t) 33 adminClient := AdminClientMock{} 34 ctx, cancel := context.WithCancel(context.Background()) 35 defer cancel() 36 // Test-1 : listGroups() Get response from minio client with two Groups and return the same number on listGroups() 37 mockGroupsList := []string{"group1", "group2"} 38 39 // mock function response from listGroups() 40 minioListGroupsMock = func() ([]string, error) { 41 return mockGroupsList, nil 42 } 43 // get list Groups response this response should have Name, CreationDate, Size and Access 44 // as part of of each Groups 45 function := "listGroups()" 46 groupsList, err := adminClient.listGroups(ctx) 47 if err != nil { 48 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 49 } 50 // verify length of Groupss is correct 51 assert.Equal(len(mockGroupsList), len(groupsList), fmt.Sprintf("Failed on %s: length of Groups's lists is not the same", function)) 52 53 for i, g := range groupsList { 54 assert.Equal(mockGroupsList[i], g) 55 } 56 57 // Test-2 : listGroups() Return error and see that the error is handled correctly and returned 58 minioListGroupsMock = func() ([]string, error) { 59 return nil, errors.New("error") 60 } 61 _, err = adminClient.listGroups(ctx) 62 if assert.Error(err) { 63 assert.Equal("error", err.Error()) 64 } 65 } 66 67 func TestAddGroup(t *testing.T) { 68 assert := assert.New(t) 69 adminClient := AdminClientMock{} 70 ctx, cancel := context.WithCancel(context.Background()) 71 defer cancel() 72 // Test-1 : addGroup() add a new group with two members 73 newGroup := "acmeGroup" 74 groupMembers := []string{"user1", "user2"} 75 // mock function response from updateGroupMembers() 76 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 77 return nil 78 } 79 function := "addGroup()" 80 if err := addGroup(ctx, adminClient, newGroup, groupMembers); err != nil { 81 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 82 } 83 84 // Test-2 : addGroup() Return error and see that the error is handled correctly and returned 85 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 86 return errors.New("error") 87 } 88 89 if err := addGroup(ctx, adminClient, newGroup, groupMembers); assert.Error(err) { 90 assert.Equal("error", err.Error()) 91 } 92 } 93 94 func TestRemoveGroup(t *testing.T) { 95 assert := assert.New(t) 96 adminClient := AdminClientMock{} 97 ctx, cancel := context.WithCancel(context.Background()) 98 defer cancel() 99 // Test-1 : removeGroup() remove group assume it has no members 100 groupToRemove := "acmeGroup" 101 // mock function response from updateGroupMembers() 102 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 103 return nil 104 } 105 function := "removeGroup()" 106 if err := removeGroup(ctx, adminClient, groupToRemove); err != nil { 107 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 108 } 109 110 // Test-2 : removeGroup() Return error and see that the error is handled correctly and returned 111 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 112 return errors.New("error") 113 } 114 if err := removeGroup(ctx, adminClient, groupToRemove); assert.Error(err) { 115 assert.Equal("error", err.Error()) 116 } 117 } 118 119 func TestGroupInfo(t *testing.T) { 120 assert := assert.New(t) 121 adminClient := AdminClientMock{} 122 ctx, cancel := context.WithCancel(context.Background()) 123 defer cancel() 124 // Test-1 : groupInfo() get group info 125 groupName := "acmeGroup" 126 mockResponse := &madmin.GroupDesc{ 127 Name: groupName, 128 Policy: "policyTest", 129 Members: []string{"user1", "user2"}, 130 Status: "enabled", 131 } 132 // mock function response from updateGroupMembers() 133 minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) { 134 return mockResponse, nil 135 } 136 function := "groupInfo()" 137 info, err := groupInfo(ctx, adminClient, groupName) 138 if err != nil { 139 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 140 } 141 assert.Equal(groupName, info.Name) 142 assert.Equal("policyTest", info.Policy) 143 assert.ElementsMatch([]string{"user1", "user2"}, info.Members) 144 assert.Equal("enabled", info.Status) 145 146 // Test-2 : groupInfo() Return error and see that the error is handled correctly and returned 147 minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) { 148 return nil, errors.New("error") 149 } 150 _, err = groupInfo(ctx, adminClient, groupName) 151 if assert.Error(err) { 152 assert.Equal("error", err.Error()) 153 } 154 } 155 156 func TestUpdateGroup(t *testing.T) { 157 assert := assert.New(t) 158 adminClient := AdminClientMock{} 159 ctx, cancel := context.WithCancel(context.Background()) 160 defer cancel() 161 // Test-1 : addOrDeleteMembers() update group members add user3 and delete user2 162 function := "addOrDeleteMembers()" 163 groupName := "acmeGroup" 164 mockGroupDesc := &madmin.GroupDesc{ 165 Name: groupName, 166 Policy: "policyTest", 167 Members: []string{"user1", "user2"}, 168 Status: "enabled", 169 } 170 membersDesired := []string{"user3", "user1"} 171 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 172 return nil 173 } 174 if err := addOrDeleteMembers(ctx, adminClient, mockGroupDesc, membersDesired); err != nil { 175 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 176 } 177 178 // Test-2 : addOrDeleteMembers() handle error correctly 179 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 180 return errors.New("error") 181 } 182 if err := addOrDeleteMembers(ctx, adminClient, mockGroupDesc, membersDesired); assert.Error(err) { 183 assert.Equal("error", err.Error()) 184 } 185 186 // Test-3 : addOrDeleteMembers() only add members but handle error on adding 187 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 188 return errors.New("error") 189 } 190 membersDesired = []string{"user3", "user1", "user2"} 191 if err := addOrDeleteMembers(ctx, adminClient, mockGroupDesc, membersDesired); assert.Error(err) { 192 assert.Equal("error", err.Error()) 193 } 194 195 // Test-4: addOrDeleteMembers() no updates needed so error shall not be triggered or handled. 196 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 197 return errors.New("error") 198 } 199 membersDesired = []string{"user1", "user2"} 200 if err := addOrDeleteMembers(ctx, adminClient, mockGroupDesc, membersDesired); err != nil { 201 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 202 } 203 204 // Test-5 : groupUpdate() integrate all from getting current group to update it and see if it changed. 205 // This test mocks one function twice and makes sure it returns different content on each call. 206 function = "groupUpdate()" 207 groupName = "acmeGroup" 208 membersDesired = []string{"user1", "user2", "user3"} 209 expectedGroupUpdate := &models.UpdateGroupRequest{ 210 Members: membersDesired, 211 Status: swag.String("disabled"), 212 } 213 mockResponseBeforeUpdate := &madmin.GroupDesc{ 214 Name: groupName, 215 Policy: "policyTest", 216 Members: []string{"user1", "user2"}, 217 Status: "enabled", 218 } 219 mockResponseAfterUpdate := &madmin.GroupDesc{ 220 Name: groupName, 221 Policy: "policyTest", 222 Members: []string{"user1", "user2", "user3"}, 223 Status: "disabled", 224 } 225 // groupUpdate uses getInfo() twice which uses getGroupDescription() so we need to mock as if it called 226 // the function twice but the second time returned an error 227 is2ndRunGroupInfo := false 228 // mock function response from updateGroupMembers() 229 minioGetGroupDescriptionMock = func(_ string) (*madmin.GroupDesc, error) { 230 if is2ndRunGroupInfo { 231 return mockResponseAfterUpdate, nil 232 } 233 is2ndRunGroupInfo = true 234 return mockResponseBeforeUpdate, nil 235 } 236 minioUpdateGroupMembersMock = func(madmin.GroupAddRemove) error { 237 return nil 238 } 239 minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error { 240 return nil 241 } 242 groupUpdated, err := groupUpdate(ctx, adminClient, groupName, expectedGroupUpdate) 243 if err != nil { 244 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 245 } 246 // assert elements were updated as expected 247 assert.ElementsMatch(membersDesired, groupUpdated.Members) 248 assert.Equal(groupName, groupUpdated.Name) 249 assert.Equal(*expectedGroupUpdate.Status, groupUpdated.Status) 250 } 251 252 func TestSetGroupStatus(t *testing.T) { 253 assert := assert.New(t) 254 adminClient := AdminClientMock{} 255 function := "setGroupStatus()" 256 groupName := "acmeGroup" 257 ctx, cancel := context.WithCancel(context.Background()) 258 defer cancel() 259 // Test-1: setGroupStatus() update valid disabled status 260 expectedStatus := "disabled" 261 minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error { 262 return nil 263 } 264 if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); err != nil { 265 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 266 } 267 // Test-2: setGroupStatus() update valid enabled status 268 expectedStatus = "enabled" 269 minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error { 270 return nil 271 } 272 if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); err != nil { 273 t.Errorf("Failed on %s:, error occurred: %s", function, err.Error()) 274 } 275 // Test-3: setGroupStatus() update invalid status, should send error 276 expectedStatus = "invalid" 277 minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error { 278 return nil 279 } 280 if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); assert.Error(err) { 281 assert.Equal("status not valid", err.Error()) 282 } 283 // Test-4: setGroupStatus() handler error correctly 284 expectedStatus = "enabled" 285 minioSetGroupStatusMock = func(_ string, _ madmin.GroupStatus) error { 286 return errors.New("error") 287 } 288 if err := setGroupStatus(ctx, adminClient, groupName, expectedStatus); assert.Error(err) { 289 assert.Equal("error", err.Error()) 290 } 291 }