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  }