// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package commands import ( "context" "encoding/json" "fmt" "net/http" "os" "strings" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer" "github.com/hashicorp/go-multierror" "github.com/pkg/errors" "github.com/spf13/cobra" ) func (s *MmctlUnitTestSuite) TestUserActivateCmd() { s.Run("Activate user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, true). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userActivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Try to activate unexistent user", func() { printer.Clean() emailArg := "example@example.com" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUser(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) err := userActivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %s not found\n\n", emailArg), printer.GetErrorLines()[0]) }) s.Run("Fail to activate user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, true). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) err := userActivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("unable to change activation status of user %v: mock error", mockUser.Id), printer.GetErrorLines()[0]) }) s.Run("Activate several users with unexistent ones and failed ones", func() { printer.Clean() emailArgs := []string{"example0@example0.com", "null", "example2@example2.com", "failure@failure.com", "example4@example4.com"} mockUser0 := model.User{Id: "example0", Username: "ExampleUser0", Email: emailArgs[0]} mockUser2 := model.User{Id: "example2", AuthService: "other", Username: "ExampleUser2", Email: emailArgs[2]} mockUser3 := model.User{Id: "failure", Username: "FailureUser", Email: emailArgs[3]} mockUser4 := model.User{Id: "example4", Username: "ExampleUser4", Email: emailArgs[4]} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[0], ""). Return(&mockUser0, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), emailArgs[1], ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUser(context.TODO(), emailArgs[1], ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[2], ""). Return(&mockUser2, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[3], ""). Return(&mockUser3, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[4], ""). Return(&mockUser4, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser0.Id, true). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser2.Id, true). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser3.Id, true). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser4.Id, true). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userActivateCmdF(s.client, &cobra.Command{}, emailArgs) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 2) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %s not found\n\n", emailArgs[1]), printer.GetErrorLines()[0]) s.Require().Equal(fmt.Sprintf("unable to change activation status of user %v: mock error", mockUser3.Id), printer.GetErrorLines()[1]) }) s.Run("shell completion", func() { s.Run("one element matches", func() { mockUsers := []*model.User{ { Id: "0_id", Username: "0_username", Email: "0_email@example.org", }, { Id: "1_id", Username: "1_username", Email: "1_email@example.org", }, { Id: "2_id", Username: "2_username", Email: "2_email@example.org", }, } s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.Background(), 0, DefaultPageSize, "inactive=true", ""). Return(mockUsers, &model.Response{}, nil). Times(1) r, dir := userActivateCompletionF(context.Background(), s.client, nil, nil, "1") s.Equal(cobra.ShellCompDirectiveNoFileComp, dir) s.Equal([]string{"1_id"}, r) }) }) } func (s *MmctlUnitTestSuite) TestDeactivateUserCmd() { s.Run("Deactivate user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Try to deactivate unexistent user", func() { printer.Clean() emailArg := "example@example.com" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUser(context.TODO(), emailArg, ""). Return(nil, &model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %v not found\n\n", emailArg), printer.GetErrorLines()[0]) }) s.Run("Fail to deactivate user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("unable to change activation status of user %v: mock error", mockUser.Id), printer.GetErrorLines()[0]) }) s.Run("Deactivate SSO user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", AuthService: "other", Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal("You must also deactivate user "+mockUser.Id+" in the SSO provider or they will be reactivated on next login or sync.", printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Deactivate several users with unexistent ones, SSO ones and failed ones", func() { printer.Clean() emailArgs := []string{"example0@example0.com", "null", "example2@example2.com", "failure@failure.com", "example4@example4.com"} mockUser0 := model.User{Id: "example0", Username: "ExampleUser0", Email: emailArgs[0]} mockUser2 := model.User{Id: "example2", AuthService: "other", Username: "ExampleUser2", Email: emailArgs[2]} mockUser3 := model.User{Id: "failure", Username: "FailureUser", Email: emailArgs[3]} mockUser4 := model.User{Id: "example4", Username: "ExampleUser4", Email: emailArgs[4]} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[0], ""). Return(&mockUser0, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), emailArgs[1], ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUser(context.TODO(), emailArgs[1], ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("mock error")). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[2], ""). Return(&mockUser2, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[3], ""). Return(&mockUser3, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArgs[4], ""). Return(&mockUser4, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser0.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser2.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser3.Id, false). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser4.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, emailArgs) s.Require().Error(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal("You must also deactivate user "+mockUser2.Id+" in the SSO provider or they will be reactivated on next login or sync.", printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 2) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %v not found\n\n", emailArgs[1]), printer.GetErrorLines()[0]) s.Require().Equal(fmt.Sprintf("unable to change activation status of user %v: mock error", mockUser3.Id), printer.GetErrorLines()[1]) }) } func (s *MmctlUnitTestSuite) TestDeleteUsersCmd() { email1 := "user1@example.com" email2 := "user2@example.com" userID1 := model.NewId() userID2 := model.NewId() mockUser1 := model.User{Username: "User1", Email: email1, Id: userID1} mockUser2 := model.User{Username: "User2", Email: email2, Id: userID2} s.Run("Delete users with confirm false returns an error", func() { cmd := &cobra.Command{} cmd.Flags().Bool("confirm", false, "") err := deleteUsersCmdF(s.client, cmd, []string{"some"}) s.Require().NotNil(err) s.Require().Equal("could not proceed, either enable --confirm flag or use an interactive shell to complete operation: this is not an interactive shell", err.Error()) }) s.Run("Delete user that does not exist in db returns an error", func() { printer.Clean() arg := "userdoesnotexist@example.com" var expectedErr *multierror.Error expectedErr = multierror.Append(expectedErr, fmt.Errorf("user %s not found", arg)) s.client. EXPECT(). GetUserByEmail(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") err := deleteUsersCmdF(s.client, cmd, []string{arg}) s.Require().Error(err) s.Require().EqualError(err, expectedErr.Error()) }) s.Run("Delete users should delete users", func() { printer.Clean() s.client. EXPECT(). GetUserByEmail(context.TODO(), email1, ""). Return(&mockUser1, &model.Response{}, nil). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID1). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), email2, ""). Return(&mockUser2, &model.Response{}, nil). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID2). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") err := deleteUsersCmdF(s.client, cmd, []string{email1, email2}) s.Require().Nil(err) s.Require().Equal(&mockUser1, printer.GetLines()[0]) s.Require().Equal(&mockUser2, printer.GetLines()[1]) }) s.Run("Delete users with error on PermanentDeleteUser returns an error", func() { printer.Clean() mockError := errors.New("an error occurred on deleting a user") var expectedErr *multierror.Error expectedErr = multierror.Append(expectedErr, fmt.Errorf("unable to delete user %s error: %w", mockUser1.Username, mockError)) s.client. EXPECT(). GetUserByEmail(context.TODO(), email1, ""). Return(&mockUser1, &model.Response{}, nil). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID1). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") err := deleteUsersCmdF(s.client, cmd, []string{email1}) s.Require().EqualError(err, expectedErr.Error()) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Delete two users, first fails with error other passes", func() { printer.Clean() mockError := errors.New("an error occurred on deleting a user") var expectedErr *multierror.Error expectedErr = multierror.Append(expectedErr, fmt.Errorf("unable to delete user %s error: %w", mockUser1.Username, mockError)) s.client. EXPECT(). GetUserByEmail(context.TODO(), email1, ""). Return(&mockUser1, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByEmail(context.TODO(), email2, ""). Return(&mockUser2, &model.Response{}, nil). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID1). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID2). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") err := deleteUsersCmdF(s.client, cmd, []string{email1, email2}) s.Require().NotNil(err) s.Require().EqualError(err, expectedErr.Error()) s.Require().Equal(&mockUser2, printer.GetLines()[0]) }) s.Run("partial delete of user, i.e failing to delete profile image gives a warning on the console.", func() { printer.Clean() var expectedErr *multierror.Error expectedErr = multierror.Append(expectedErr, fmt.Errorf("unable to delete the profile image of the user, please delete it manually, id:%s", mockUser1.Username)) s.client. EXPECT(). GetUserByEmail(context.TODO(), email1, ""). Return(&mockUser1, &model.Response{}, nil). Times(1) s.client. EXPECT(). PermanentDeleteUser(context.TODO(), userID1). Return(&model.Response{StatusCode: http.StatusAccepted}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") err := deleteUsersCmdF(s.client, cmd, []string{email1}) s.Require().NotNil(err) s.Require().EqualError(err, expectedErr.Error()) }) } func (s *MmctlUnitTestSuite) TestDeleteAllUsersCmd() { s.Run("Delete all users", func() { printer.Clean() cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") s.client. EXPECT(). PermanentDeleteAllUsers(context.TODO()). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := deleteAllUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Len(printer.GetErrorLines(), 0) s.Require().Equal(printer.GetLines()[0], "All users successfully deleted") }) s.Run("Delete all users call fails", func() { printer.Clean() cmd := &cobra.Command{} cmd.Flags().Bool("confirm", true, "") s.client. EXPECT(). PermanentDeleteAllUsers(context.TODO()). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("mock error")). Times(1) err := deleteAllUsersCmdF(s.client, cmd, []string{}) s.Require().NotNil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) } func (s *MmctlUnitTestSuite) TestSearchUserCmd() { s.Run("Search for an existing user", func() { emailArg := "example@example.com" mockUser := &model.User{Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(mockUser, &model.Response{}, nil). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Nil(err) s.Require().Equal(userOut{User: mockUser, Deactivated: false}, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Search for a disabled user", func() { printer.Clean() emailArg := "example@example.com" mockUser := &model.User{Username: "ExampleUser", Email: emailArg, DeleteAt: 1234} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(mockUser, &model.Response{}, nil). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(userOut{User: mockUser, Deactivated: true}, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Search for a user with authData", func() { printer.Clean() emailArg := "example@example.com" mockUser := &model.User{Username: "ExampleUser", Email: emailArg, AuthData: model.NewPointer("1234"), AuthService: model.UserAuthServiceLdap} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(mockUser, &model.Response{}, nil). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(userOut{User: mockUser, Deactivated: false, AuthData: "1234"}, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Search for a nonexistent user", func() { printer.Clean() arg := "example@example.com" s.client. EXPECT(). GetUserByEmail(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{arg}) s.Require().NotNil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Equal("1 error occurred:\n\t* user example@example.com not found\n\n", printer.GetErrorLines()[0]) }) s.Run("Avoid path traversal", func() { printer.Clean() arg := "test/../hello?@mattermost.com" err := searchUserCmdF(s.client, &cobra.Command{}, []string{arg}) s.Require().NotNil(err) s.Require().Equal("1 error occurred:\n\t* user test/../hello?@mattermost.com not found\n\n", printer.GetErrorLines()[0]) }) s.Run("Error while getting user by email", func() { printer.Clean() emailArg := "example@mailexample.com" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(nil, &model.Response{}, errors.New("Error while getting user by email")). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NotNil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Equal("1 error occurred:\n\t* Error while getting user by email\n\n", err.Error()) s.Require().Equal("1 error occurred:\n\t* Error while getting user by email\n\n", printer.GetErrorLines()[0]) }) s.Run("Error while getting user by username", func() { printer.Clean() usernameArg := "exampleUser" s.client. EXPECT(). GetUserByUsername(context.TODO(), usernameArg, ""). Return(nil, &model.Response{}, errors.New("Error while getting user by username")). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{usernameArg}) s.Require().NotNil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Equal("1 error occurred:\n\t* Error while getting user by username\n\n", err.Error()) s.Require().Equal("1 error occurred:\n\t* Error while getting user by username\n\n", printer.GetErrorLines()[0]) }) s.Run("Error while getting user", func() { printer.Clean() userArg := "exampleUser" s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), userArg, ""). Return(nil, &model.Response{}, errors.New("Error while getting user")). Times(1) err := searchUserCmdF(s.client, &cobra.Command{}, []string{userArg}) s.Require().NotNil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Equal("1 error occurred:\n\t* Error while getting user\n\n", err.Error()) s.Require().Equal("1 error occurred:\n\t* Error while getting user\n\n", printer.GetErrorLines()[0]) }) } func (s *MmctlUnitTestSuite) TestChangePasswordUserCmdF() { s.Run("Change password for oneself", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} currentPassword := "current-password" password := "password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserPassword(context.TODO(), mockUser.Id, currentPassword, password). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", password, "") cmd.Flags().String("current", currentPassword, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Change password for another user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} password := "password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserPassword(context.TODO(), mockUser.Id, "", password). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", password, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Error when changing password for oneself", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} mockError := errors.New("mock error") currentPassword := "current-password" password := "password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserPassword(context.TODO(), mockUser.Id, currentPassword, password). Return(&model.Response{StatusCode: http.StatusOK}, mockError). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", password, "") cmd.Flags().String("current", currentPassword, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().Error(err) s.Require().EqualError(err, "changing user password failed: mock error") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Error when changing password for another user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} mockError := errors.New("mock error") password := "password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserPassword(context.TODO(), mockUser.Id, "", password). Return(&model.Response{StatusCode: http.StatusOK}, mockError). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", password, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().Error(err) s.Require().EqualError(err, "changing user password failed: mock error") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Error changing password for a nonexisting user", func() { printer.Clean() arg := "example@example.com" password := "password" s.client. EXPECT(). GetUserByEmail(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", password, "") err := changePasswordUserCmdF(s.client, cmd, []string{arg}) s.Require().Error(err) s.Require().EqualError(err, "user example@example.com not found") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Change password by a hashed one", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} hashedPassword := "hashed-password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserHashedPassword(context.TODO(), mockUser.Id, hashedPassword). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", hashedPassword, "") cmd.Flags().Bool("hashed", true, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Error when changing password by a hashed one", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "userId", Username: "ExampleUser", Email: emailArg} mockError := errors.New("mock error") hashedPassword := "hashed-password" s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserHashedPassword(context.TODO(), mockUser.Id, hashedPassword). Return(&model.Response{StatusCode: http.StatusOK}, mockError). Times(1) cmd := &cobra.Command{} cmd.Flags().String("password", hashedPassword, "") cmd.Flags().Bool("hashed", true, "") err := changePasswordUserCmdF(s.client, cmd, []string{emailArg}) s.Require().EqualError(err, "changing user hashed password failed: mock error") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) } func (s *MmctlUnitTestSuite) TestSendPasswordResetEmailCmd() { s.Run("Send one reset email", func() { printer.Clean() emailArg := "example@example.com" s.client. EXPECT(). SendPasswordResetEmail(context.TODO(), emailArg). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) err := sendPasswordResetEmailCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Send one reset email and receive error on email validation", func() { printer.Clean() emailArg := "invalid.Email@example.com" var expected error expected = multierror.Append(expected, fmt.Errorf("invalid email '%s'", emailArg)) err := sendPasswordResetEmailCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal("Invalid email '"+emailArg+"'", printer.GetErrorLines()[0]) }) s.Run("Send one reset email and receive error on email sending", func() { printer.Clean() emailArg := "example@example.com" mockError := errors.New("mock error") s.client. EXPECT(). SendPasswordResetEmail(context.TODO(), emailArg). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) var expected error expected = multierror.Append(expected, fmt.Errorf("unable send reset password email to email %s: %w", emailArg, mockError)) err := sendPasswordResetEmailCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal("Unable send reset password email to email "+emailArg+". Error: "+mockError.Error(), printer.GetErrorLines()[0]) }) s.Run("Send several reset emails and receive some errors", func() { printer.Clean() emailArg := []string{ "example1@example.com", "error1@example.com", "invalid.Email@example.com", "example2@example.com", "example3@example.com"} mockError := errors.New("mock error") var expected error for _, email := range emailArg { switch { case strings.HasPrefix(email, "error"): s.client. EXPECT(). SendPasswordResetEmail(context.TODO(), email). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) expected = multierror.Append(expected, fmt.Errorf("unable send reset password email to email %s: %w", email, mockError)) case strings.ToLower(email) != email: expected = multierror.Append(expected, fmt.Errorf("invalid email '%s'", email)) default: s.client. EXPECT(). SendPasswordResetEmail(context.TODO(), email). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) } } err := sendPasswordResetEmailCmdF(s.client, &cobra.Command{}, emailArg) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 2) s.Require().Equal("Unable send reset password email to email "+emailArg[1]+". Error: "+mockError.Error(), printer.GetErrorLines()[0]) s.Require().Equal("Invalid email '"+emailArg[2]+"'", printer.GetErrorLines()[1]) }) } func (s *MmctlUnitTestSuite) TestUserInviteCmd() { s.Run("Invite user to an existing team by Id", func() { printer.Clean() argUser := "example@example.com" argTeam := "teamId" s.client. EXPECT(). GetTeam(context.TODO(), argTeam, ""). Return(&model.Team{Id: argTeam}, &model.Response{}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), argTeam, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) err := userInviteCmdF(s.client, &cobra.Command{}, []string{argUser, argTeam}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal("Invites may or may not have been sent.", printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invite user to an existing team by name", func() { printer.Clean() argUser := "example@example.com" argTeam := "teamName" resultID := "teamId" s.client. EXPECT(). GetTeam(context.TODO(), argTeam, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam, ""). Return(&model.Team{Id: resultID}, &model.Response{}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultID, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) err := userInviteCmdF(s.client, &cobra.Command{}, []string{argUser, argTeam}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal("Invites may or may not have been sent.", printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invite user to several existing teams by name and id", func() { printer.Clean() argUser := "example@example.com" argTeam := []string{"teamName1", "teamId2", "teamId3", "teamName4"} resultTeamModels := [4]*model.Team{ {Id: "teamId1"}, {Id: "teamId2"}, {Id: "teamId3"}, {Id: "teamId4"}, } // Setup GetTeam s.client. EXPECT(). GetTeam(context.TODO(), argTeam[0], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[1], ""). Return(resultTeamModels[1], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[2], ""). Return(resultTeamModels[2], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[3], ""). Return(nil, &model.Response{}, nil). Times(1) // Setup GetTeamByName s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam[0], ""). Return(resultTeamModels[0], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam[3], ""). Return(resultTeamModels[3], &model.Response{}, nil). Times(1) // Setup InviteUsersToTeam for _, resultTeamModel := range resultTeamModels { s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModel.Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) } err := userInviteCmdF(s.client, &cobra.Command{}, append([]string{argUser}, argTeam...)) s.Require().Nil(err) s.Require().Len(printer.GetLines(), len(argTeam)) for i := range argTeam { s.Require().Equal("Invites may or may not have been sent.", printer.GetLines()[i]) } s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invite user to an un-existing team", func() { printer.Clean() argUser := "example@example.com" argTeam := "unexistent" s.client. EXPECT(). GetTeam(context.TODO(), argTeam, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam, ""). Return(nil, &model.Response{}, nil). Times(1) err := userInviteCmdF(s.client, &cobra.Command{}, []string{argUser, argTeam}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal("can't find team '"+argTeam+"'", printer.GetErrorLines()[0]) }) s.Run("Invite user to an existing team and fail invite", func() { printer.Clean() argUser := "example@example.com" argTeam := "teamId" resultName := "teamName" mockError := errors.New("mock error") s.client. EXPECT(). GetTeam(context.TODO(), argTeam, ""). Return(&model.Team{Id: argTeam, Name: resultName}, &model.Response{}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), argTeam, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) err := userInviteCmdF(s.client, &cobra.Command{}, []string{argUser, argTeam}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal("Unable to invite user with email "+argUser+" to team "+resultName+". Error: "+mockError.Error(), printer.GetErrorLines()[0]) }) s.Run("Invite user to several existing and non-existing teams by name and id and reject one invite", func() { printer.Clean() argUser := "example@example.com" argTeam := []string{"teamName1", "unexistent", "teamId3", "teamName4", "reject", "teamId6"} resultTeamModels := [6]*model.Team{ {Id: "teamId1", Name: "teamName1"}, nil, {Id: "teamId3", Name: "teamName3"}, {Id: "teamId4", Name: "teamName4"}, {Id: "reject", Name: "rejectName"}, {Id: "teamId6", Name: "teamName6"}, } mockError := model.NewAppError("", "mock error", nil, "", 0) // Setup GetTeam s.client. EXPECT(). GetTeam(context.TODO(), argTeam[0], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[1], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[2], ""). Return(resultTeamModels[2], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[3], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[4], ""). Return(resultTeamModels[4], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeam(context.TODO(), argTeam[5], ""). Return(resultTeamModels[5], &model.Response{}, nil). Times(1) // Setup GetTeamByName s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam[0], ""). Return(resultTeamModels[0], &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam[1], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetTeamByName(context.TODO(), argTeam[3], ""). Return(resultTeamModels[3], &model.Response{}, nil). Times(1) // Setup InviteUsersToTeam s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModels[0].Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModels[2].Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModels[3].Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModels[4].Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) s.client. EXPECT(). InviteUsersToTeam(context.TODO(), resultTeamModels[5].Id, []string{argUser}). Return(&model.Response{StatusCode: http.StatusBadRequest}, nil). Times(1) err := userInviteCmdF(s.client, &cobra.Command{}, append([]string{argUser}, argTeam...)) s.Require().Error(err) s.Require().Len(printer.GetLines(), 4) for i := range 4 { s.Require().Equal("Invites may or may not have been sent.", printer.GetLines()[i]) } s.Require().Len(printer.GetErrorLines(), 2) s.Require().Equal("can't find team '"+argTeam[1]+"'", printer.GetErrorLines()[0]) s.Require().Equal("Unable to invite user with email "+argUser+" to team "+resultTeamModels[4].Name+". Error: "+mockError.Error(), printer.GetErrorLines()[1]) }) } func (s *MmctlUnitTestSuite) TestUserCreateCmd() { mockUser := model.User{ Username: "username", Password: "password", Email: "email", } s.Run("Create user with email missing", func() { printer.Clean() command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("password", mockUser.Password, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Equal("Email is required: flag accessed but not defined: email", err.Error()) }) s.Run("Create user with username missing", func() { printer.Clean() command := cobra.Command{} command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Equal("Username is required: flag accessed but not defined: username", err.Error()) }) s.Run("Create user with password missing", func() { printer.Clean() command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Equal("Password is required: flag accessed but not defined: password", err.Error()) }) s.Run("Create a regular user", func() { printer.Clean() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, nil). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Nil(err) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Create a regular user with welcome email disabled", func() { printer.Clean() oldDisableWelcomeEmail := mockUser.DisableWelcomeEmail mockUser.DisableWelcomeEmail = true defer func() { mockUser.DisableWelcomeEmail = oldDisableWelcomeEmail }() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, nil). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") command.Flags().Bool("disable-welcome-email", mockUser.DisableWelcomeEmail, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Nil(err) printerLines := printer.GetLines()[0] printedUser := printerLines.(*model.User) s.Require().Equal(&mockUser, printerLines) s.Require().Equal(true, printedUser.DisableWelcomeEmail) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Create a regular user with client returning error", func() { printer.Clean() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, errors.New("remote error")). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Equal("Unable to create user. Error: remote error", err.Error()) }) s.Run("Create a sysAdmin user", func() { printer.Clean() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserRoles(context.TODO(), mockUser.Id, "system_user system_admin"). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") command.Flags().Bool("system-admin", true, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Nil(err) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Create a guest user", func() { printer.Clean() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). DemoteUserToGuest(context.TODO(), mockUser.Id). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") command.Flags().Bool("guest", true, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Nil(err) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Create a sysAdmin user with client returning error", func() { printer.Clean() s.client. EXPECT(). CreateUser(context.TODO(), &mockUser). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserRoles(context.TODO(), mockUser.Id, "system_user system_admin"). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("remote error")). Times(1) command := cobra.Command{} command.Flags().String("username", mockUser.Username, "") command.Flags().String("email", mockUser.Email, "") command.Flags().String("password", mockUser.Password, "") command.Flags().Bool("system-admin", true, "") err := userCreateCmdF(s.client, &command, []string{}) s.Require().Equal("Unable to update user roles. Error: remote error", err.Error()) }) } func (s *MmctlUnitTestSuite) TestResetUserMfaCmd() { s.Run("One user without problems", func() { printer.Clean() s.client. EXPECT(). GetUserByUsername(context.TODO(), "userId", ""). Return(&model.User{Id: "userId"}, nil, nil). Times(1) s.client. EXPECT(). UpdateUserMfa(context.TODO(), "userId", "", false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := resetUserMfaCmdF(s.client, &cobra.Command{}, []string{"userId"}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Cannot find one user", func() { printer.Clean() s.client. EXPECT(). GetUserByUsername(context.TODO(), "userId", ""). Return(nil, nil, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), "userId", ""). Return(nil, nil, nil). Times(1) err := resetUserMfaCmdF(s.client, &cobra.Command{}, []string{"userId"}) var expected error expected = multierror.Append( expected, ExtractErrorFromResponse( &model.Response{StatusCode: http.StatusNotFound}, ErrEntityNotFound{Type: "user", ID: "userId"}, ), ) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) }) s.Run("One user, unable to reset", func() { printer.Clean() mockError := errors.New("mock error") s.client. EXPECT(). GetUserByUsername(context.TODO(), "userId", ""). Return(&model.User{Id: "userId"}, nil, nil). Times(1) s.client. EXPECT(). UpdateUserMfa(context.TODO(), "userId", "", false). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) err := resetUserMfaCmdF(s.client, &cobra.Command{}, []string{"userId"}) var expected error expected = multierror.Append( expected, fmt.Errorf("unable to reset user \"userId\" MFA. Error: %s", mockError.Error()), ) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) }) s.Run("Several users, with unknown users and users unable to be reset", func() { printer.Clean() users := []string{"user0", "error1", "user2", "notfounduser", "user4"} mockError := errors.New("mock error") for _, user := range users { if user == "notfounduser" { s.client. EXPECT(). GetUserByUsername(context.TODO(), user, ""). Return(nil, nil, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), user, ""). Return(nil, nil, nil). Times(1) } else { s.client. EXPECT(). GetUserByUsername(context.TODO(), user, ""). Return(&model.User{Id: user}, nil, nil). Times(1) } } for _, user := range users { if user == "error1" { s.client. EXPECT(). UpdateUserMfa(context.TODO(), user, "", false). Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError). Times(1) } else if user != "notfounduser" { s.client. EXPECT(). UpdateUserMfa(context.TODO(), user, "", false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) } } err := resetUserMfaCmdF(s.client, &cobra.Command{}, users) var expected *multierror.Error expected = multierror.Append( expected, ExtractErrorFromResponse( &model.Response{StatusCode: http.StatusNotFound}, ErrEntityNotFound{Type: "user", ID: users[3]}, ), ) expected = multierror.Append( expected, fmt.Errorf("unable to reset user \"%s\" MFA. Error: %s", users[1], mockError.Error()), ) s.Require().EqualError(err, expected.ErrorOrNil().Error()) s.Require().Len(printer.GetLines(), 0) }) } func (s *MmctlUnitTestSuite) TestListUserCmdF() { s.Run("Listing users with paging", func() { printer.Clean() email := "example@example.com" mockUser := model.User{Username: "ExampleUser", Email: email} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", ""). Return([]*model.User{&mockUser}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) }) s.Run("Listing all the users", func() { printer.Clean() email1 := "example1@example.com" mockUser1 := model.User{Username: "ExampleUser1", Email: email1} email2 := "example2@example.com" mockUser2 := model.User{Username: "ExampleUser2", Email: email2} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("all", "true")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", ""). Return([]*model.User{&mockUser1}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "", ""). Return([]*model.User{&mockUser2}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", ""). Return([]*model.User{}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 2) s.Require().Equal(&mockUser1, printer.GetLines()[0]) s.Require().Equal(&mockUser2, printer.GetLines()[1]) }) s.Run("Listing all users including inactive", func() { printer.Clean() email1 := "example1@example.com" mockUser1 := model.User{Username: "ExampleUser1", Email: email1} email2 := "example2@example.com" mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("all", "true")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", ""). Return([]*model.User{&mockUser1}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "", ""). Return([]*model.User{&mockUser2}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", ""). Return([]*model.User{}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 2) s.Require().Equal(&mockUser1, printer.GetLines()[0]) s.Require().Equal(&mockUser2, printer.GetLines()[1]) }) s.Run("Listing all inactive users", func() { printer.Clean() email2 := "example2@example.com" mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()} email3 := "example3@example.com" mockUser3 := model.User{Username: "ExampleUser3", Email: email3, DeleteAt: model.GetMillis()} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("all", "true")) s.Require().NoError(cmd.Flags().Set("inactive", "true")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "inactive=true", ""). Return([]*model.User{&mockUser2}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "inactive=true", ""). Return([]*model.User{&mockUser3}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "inactive=true", ""). Return([]*model.User{}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 2) s.Require().Equal(&mockUser2, printer.GetLines()[0]) s.Require().Equal(&mockUser3, printer.GetLines()[1]) }) s.Run("Listing inactive users with paging skipping 1 page", func() { printer.Clean() email := "del@example.com" _ = model.User{Username: "ExampleUser", Email: email, DeleteAt: model.GetMillis()} email1 := "del1@example.com" mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "1")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("inactive", "true")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "inactive=true", ""). Return([]*model.User{&mockUser1}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser1, printer.GetLines()[0]) }) s.Run("Try to list all the users when there are no uses in store", func() { printer.Clean() cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "0")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", ""). Return([]*model.User{}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("Return an error from GetUsersWithCustomQueryParameters call and verify that error is properly returned", func() { printer.Clean() cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "0")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) mockError := errors.New("mock error") mockErrorW := errors.Wrap(mockError, "Failed to fetch users") s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "", ""). Return(nil, &model.Response{}, mockError). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().NotNil(err) s.Require().EqualError(err, mockErrorW.Error()) }) s.Run("Start with page 2 where a server has total 3 pages", func() { printer.Clean() email := "example@example.com" mockUser := model.User{Username: "ExampleUser", Email: email} cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "2")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "", ""). Return([]*model.User{&mockUser}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) }) s.Run("Listing users for given team", func() { printer.Clean() email := "example@example.com" mockUser := model.User{Username: "ExampleUser", Email: email} resultID := "teamId" team := "teamName" cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "0")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("team", team)) s.client. EXPECT(). GetTeamByName(context.TODO(), team, ""). Return(&model.Team{Id: resultID}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, ""). Return([]*model.User{&mockUser}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) }) s.Run("Listing inactive users for given team", func() { printer.Clean() email := "example@example.com" _ = model.User{Username: "ExampleUser", Email: email} email1 := "example1@example.com" mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()} resultID := "teamId" team := "teamName" cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "0")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("team", team)) s.client. EXPECT(). GetTeamByName(context.TODO(), team, ""). Return(&model.Team{Id: resultID}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, ""). Return([]*model.User{&mockUser1}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser1, printer.GetLines()[0]) }) s.Run("Listing all inactive users for given team", func() { printer.Clean() email := "example@example.com" _ = model.User{Username: "ExampleUser", Email: email} email1 := "example1@example.com" mockUser1 := model.User{Username: "ExampleUser1", Email: email1, DeleteAt: model.GetMillis()} email2 := "example2@example.com" mockUser2 := model.User{Username: "ExampleUser2", Email: email2, DeleteAt: model.GetMillis()} resultID := "teamId" team := "teamName" cmd := ResetListUsersCmd(s.T()) s.Require().NoError(cmd.Flags().Set("page", "0")) s.Require().NoError(cmd.Flags().Set("per-page", "1")) s.Require().NoError(cmd.Flags().Set("team", team)) s.Require().NoError(cmd.Flags().Set("all", "true")) s.client. EXPECT(). GetTeamByName(context.TODO(), team, ""). Return(&model.Team{Id: resultID}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 0, 1, "in_team="+resultID, ""). Return([]*model.User{&mockUser1}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 1, 1, "in_team="+resultID, ""). Return([]*model.User{&mockUser2}, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUsersWithCustomQueryParameters(context.TODO(), 2, 1, "in_team="+resultID, ""). Return([]*model.User{}, &model.Response{}, nil). Times(1) err := listUsersCmdF(s.client, cmd, []string{}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 2) s.Require().Equal(&mockUser1, printer.GetLines()[0]) s.Require().Equal(&mockUser2, printer.GetLines()[1]) }) } func (s *MmctlUnitTestSuite) TestUserDeactivateCmd() { s.Run("Deactivate an existing user using email", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Username: "ExampleUser", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{mockUser.Email}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Deactivate an existing user by username", func() { printer.Clean() emailArg := "example@exam.com" usernameArg := "ExampleUser" mockUser := model.User{Username: usernameArg, Email: emailArg} s.client. EXPECT(). GetUserByUsername(context.TODO(), usernameArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{mockUser.Username}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Deactivate an existing user by id", func() { printer.Clean() mockUser := model.User{Id: "userId1", Username: "ExampleUser", Email: "example@exam.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), mockUser.Id, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), mockUser.Id, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{mockUser.Id}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Deactivate SSO user", func() { printer.Clean() arg := "example@example.com" mockUser := model.User{Id: "example-user", Username: "ExampleUser", Email: arg, AuthService: "SSO"} s.client. EXPECT(). GetUserByEmail(context.TODO(), arg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{arg}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal("You must also deactivate user "+mockUser.Id+" in the SSO provider or they will be reactivated on next login or sync.", printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Deactivate nonexistent user", func() { printer.Clean() arg := "example@example.com" s.client. EXPECT(). GetUserByEmail(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), arg, ""). Return(nil, &model.Response{}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{arg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %s not found\n\n", arg), printer.GetErrorLines()[0]) }) s.Run("Delete multiple users", func() { printer.Clean() mockUser1 := model.User{Id: "userId1", Email: "user1@example.com", Username: "user1"} mockUser2 := model.User{Id: "userId2", Email: "user2@example.com", Username: "user2"} mockUser3 := model.User{Id: "userId3", Email: "user3@example.com", Username: "user3"} argEmails := []string{mockUser1.Email, mockUser2.Email, mockUser3.Email} argUsers := []model.User{mockUser1, mockUser2, mockUser3} for i := range argEmails { s.client. EXPECT(). GetUserByEmail(context.TODO(), argEmails[i], ""). Return(&argUsers[i], &model.Response{}, nil). Times(1) } for i := range argEmails { s.client. EXPECT(). UpdateUserActive(context.TODO(), argUsers[i].Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) } err := userDeactivateCmdF(s.client, &cobra.Command{}, argEmails) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Delete multiple users with argument mixture of emails usernames and userIds", func() { printer.Clean() mockUser1 := model.User{Id: "userId1", Email: "user1@example.com", Username: "user1"} mockUser2 := model.User{Id: "userId2", Email: "user2@example.com", Username: "user2"} mockUser3 := model.User{Id: "userId3", Email: "user3@example.com", Username: "user3"} argsDelete := []string{mockUser1.Id, mockUser2.Email, mockUser3.Username} argUsers := []model.User{mockUser1, mockUser2, mockUser3} // mockUser1 s.client. EXPECT(). GetUserByUsername(context.TODO(), argsDelete[0], ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), argsDelete[0], ""). Return(&argUsers[0], &model.Response{}, nil). Times(1) // mockUser2 s.client. EXPECT(). GetUserByEmail(context.TODO(), argsDelete[1], ""). Return(&argUsers[1], &model.Response{}, nil). Times(1) // mockUser3 s.client. EXPECT(). GetUserByUsername(context.TODO(), argsDelete[2], ""). Return(&argUsers[2], &model.Response{}, nil). Times(1) for _, user := range argUsers { s.client. EXPECT(). UpdateUserActive(context.TODO(), user.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) } err := userDeactivateCmdF(s.client, &cobra.Command{}, argsDelete) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Delete multiple users with an non existent user", func() { printer.Clean() mockUser1 := model.User{Id: "userId1", Email: "user1@example.com", Username: "user1"} nonexistentEmail := "example@example.com" // mockUser1 s.client. EXPECT(). GetUserByEmail(context.TODO(), mockUser1.Email, ""). Return(&mockUser1, &model.Response{}, nil). Times(1) // nonexistent email s.client. EXPECT(). GetUserByEmail(context.TODO(), nonexistentEmail, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUserByUsername(context.TODO(), nonexistentEmail, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), nonexistentEmail, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserActive(context.TODO(), mockUser1.Id, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := userDeactivateCmdF(s.client, &cobra.Command{}, []string{mockUser1.Email, nonexistentEmail}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("1 error occurred:\n\t* user %s not found\n\n", nonexistentEmail), printer.GetErrorLines()[0]) }) } func (s *MmctlUnitTestSuite) TestVerifyUserEmailWithoutTokenCmd() { s.Run("Verify user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). VerifyUserEmailWithoutToken(context.TODO(), mockUser.Id). Return(&mockUser, &model.Response{}, nil). Times(1) err := verifyUserEmailWithoutTokenCmdF(s.client, &cobra.Command{}, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Couldn't find the user", func() { printer.Clean() userArg := "bad-user-id" s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("")). Times(1) s.client. EXPECT(). GetUser(context.TODO(), userArg, ""). Return(nil, &model.Response{StatusCode: http.StatusNotFound}, errors.New("")). Times(1) err := verifyUserEmailWithoutTokenCmdF(s.client, &cobra.Command{}, []string{userArg}) var expected error expected = multierror.Append( expected, ExtractErrorFromResponse( &model.Response{StatusCode: http.StatusNotFound}, ErrEntityNotFound{Type: "user", ID: userArg}, ), ) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) }) s.Run("Could not verify user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). VerifyUserEmailWithoutToken(context.TODO(), mockUser.Id). Return(nil, &model.Response{}, errors.New("some-message")). Times(1) err := verifyUserEmailWithoutTokenCmdF(s.client, &cobra.Command{}, []string{emailArg}) var expected error expected = multierror.Append( expected, fmt.Errorf("unable to verify user %s email: %s", mockUser.Id, errors.New("some-message")), ) s.Require().EqualError(err, expected.Error()) s.Require().Len(printer.GetLines(), 0) }) } func (s *MmctlUnitTestSuite) TestUserConvertCmd() { s.Run("convert user to a bot", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} mockBot := model.Bot{UserId: "example"} cmd := &cobra.Command{} cmd.Flags().Bool("bot", true, "") s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). ConvertUserToBot(context.TODO(), mockUser.Id). Return(&mockBot, &model.Response{}, nil). Times(1) err := userConvertCmdF(s.client, cmd, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockBot, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("convert bot to a user", func() { printer.Clean() userNameArg := "example-bot" mockUser := model.User{Id: "example", Email: "example@example.com"} mockBot := model.Bot{UserId: "example"} mockBotUser := model.User{Id: "example", Username: userNameArg, IsBot: true} userPatch := model.UserPatch{ Email: model.NewPointer("example@example.com"), Password: model.NewPointer("password"), Username: model.NewPointer("example-user"), } cmd := &cobra.Command{} cmd.Flags().Bool("user", true, "") cmd.Flags().String("password", "password", "") cmd.Flags().String("email", "example@example.com", "") cmd.Flags().String("username", "example-user", "") s.client. EXPECT(). GetUserByUsername(context.TODO(), userNameArg, ""). Return(&mockBotUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). ConvertBotToUser(context.TODO(), mockBot.UserId, &userPatch, false). Return(&mockUser, &model.Response{}, nil). Times(1) err := userConvertCmdF(s.client, cmd, []string{userNameArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("fail for not providing either user or bot flag", func() { printer.Clean() emailArg := "example@example.com" cmd := &cobra.Command{} err := userConvertCmdF(s.client, cmd, []string{emailArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("got error while converting a user to a bot", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} cmd := &cobra.Command{} cmd.Flags().Bool("bot", true, "") s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). ConvertUserToBot(context.TODO(), mockUser.Id). Return(nil, &model.Response{}, errors.New("some-message")). Times(1) err := userConvertCmdF(s.client, cmd, []string{emailArg}) s.Require().Error(err) s.Require().Equal("1 error occurred:\n\t* some-message\n\n", err.Error()) s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("got error while converting a bot to a user", func() { printer.Clean() userNameArg := "example-bot" mockBot := model.Bot{UserId: "example"} mockBotUser := model.User{Id: "example", Username: userNameArg, IsBot: true} userPatch := model.UserPatch{ Email: model.NewPointer("example@example.com"), Password: model.NewPointer("password"), Username: model.NewPointer("example-user"), } cmd := &cobra.Command{} cmd.Flags().Bool("user", true, "") cmd.Flags().String("password", "password", "") cmd.Flags().String("email", "example@example.com", "") cmd.Flags().String("username", "example-user", "") s.client. EXPECT(). GetUserByUsername(context.TODO(), userNameArg, ""). Return(&mockBotUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). ConvertBotToUser(context.TODO(), mockBot.UserId, &userPatch, false). Return(nil, &model.Response{}, errors.New("some-message")). Times(1) err := userConvertCmdF(s.client, cmd, []string{userNameArg}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) } func (s *MmctlUnitTestSuite) TestMigrateAuthCmd() { s.Run("Successfully convert auth to LDAP", func() { printer.Clean() fromAuth := "email" toAuth := "ldap" matchField := "username" cmd := &cobra.Command{} cmd.Flags().Bool("force", false, "") s.client. EXPECT(). MigrateAuthToLdap(context.TODO(), fromAuth, matchField, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, matchField}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Successfully convert auth to SAML", func() { printer.Clean() fromAuth := "email" toAuth := "saml" file, err := os.CreateTemp("", "users.json") s.Require().NoError(err) defer os.Remove(file.Name()) usersFile := file.Name() userData := map[string]string{ "usr1@email.com": "usr.one", "usr2@email.com": "usr.two", } b, err := json.MarshalIndent(userData, "", " ") s.Require().NoError(err) _, err = file.Write(b) s.Require().NoError(err) err = file.Sync() s.Require().NoError(err) cmd := &cobra.Command{} cmd.Flags().Bool("auto", false, "") s.client. EXPECT(). MigrateAuthToSaml(context.TODO(), fromAuth, userData, false). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err = migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, usersFile}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Successfully convert auth to SAML (auto)", func() { printer.Clean() fromAuth := "email" toAuth := "saml" cmd := &cobra.Command{} cmd.Flags().Bool("auto", true, "") cmd.Flags().Bool("confirm", true, "") s.client. EXPECT(). MigrateAuthToSaml(context.TODO(), fromAuth, map[string]string{}, true). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invalid from auth type", func() { printer.Clean() fromAuth := "onelogin" toAuth := "ldap" matchField := "username" cmd := &cobra.Command{} cmd.Flags().Bool("auto", true, "") cmd.Flags().Bool("confirm", true, "") err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, matchField}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("Invalid matchfiled type for migrating auth to LDAP", func() { printer.Clean() fromAuth := "email" toAuth := "ldap" matchField := "groups" cmd := &cobra.Command{} cmd.Flags().Bool("force", false, "") err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, matchField}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("Fail on convert auth to SAML due to invalid file", func() { printer.Clean() fromAuth := "email" toAuth := "saml" usersFile := "./nofile.json" cmd := &cobra.Command{} cmd.Flags().Bool("auto", false, "") err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, usersFile}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("Failed to convert auth to LDAP from server", func() { printer.Clean() fromAuth := "email" toAuth := "ldap" matchField := "username" cmd := &cobra.Command{} cmd.Flags().Bool("force", false, "") s.client. EXPECT(). MigrateAuthToLdap(context.TODO(), fromAuth, matchField, false). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")). Times(1) err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth, matchField}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) s.Run("Failed to convert auth to SAML (auto) from server", func() { printer.Clean() fromAuth := "email" toAuth := "saml" cmd := &cobra.Command{} cmd.Flags().Bool("auto", true, "") cmd.Flags().Bool("confirm", true, "") s.client. EXPECT(). MigrateAuthToSaml(context.TODO(), fromAuth, map[string]string{}, true). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")). Times(1) err := migrateAuthCmdF(s.client, cmd, []string{fromAuth, toAuth}) s.Require().Error(err) s.Require().Len(printer.GetLines(), 0) }) } func (s *MmctlUnitTestSuite) TestPromoteGuestToUserCmd() { s.Run("promote a guest to a user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). PromoteGuestToUser(context.TODO(), mockUser.Id). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := promoteGuestToUserCmdF(s.client, nil, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("cannot promote a guest to a user", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). PromoteGuestToUser(context.TODO(), mockUser.Id). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")). Times(1) err := promoteGuestToUserCmdF(s.client, nil, []string{emailArg}) s.Require().ErrorContains(err, "unable to promote guest") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("unable to promote guest %s: %s", emailArg, "some-error"), printer.GetErrorLines()[0]) }) } func (s *MmctlUnitTestSuite) TestDemoteUserToGuestCmd() { s.Run("demote a user to a guest", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). DemoteUserToGuest(context.TODO(), mockUser.Id). Return(&model.Response{StatusCode: http.StatusOK}, nil). Times(1) err := demoteUserToGuestCmdF(s.client, nil, []string{emailArg}) s.Require().NoError(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("cannot demote a user to a guest", func() { printer.Clean() emailArg := "example@example.com" mockUser := model.User{Id: "example", Email: emailArg} s.client. EXPECT(). GetUserByEmail(context.TODO(), emailArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). DemoteUserToGuest(context.TODO(), mockUser.Id). Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")). Times(1) err := demoteUserToGuestCmdF(s.client, nil, []string{emailArg}) s.Require().ErrorContains(err, "unable to demote user") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 1) s.Require().Equal(fmt.Sprintf("unable to demote user %s: %s", emailArg, "some-error"), printer.GetErrorLines()[0]) }) } func (s *MmctlUnitTestSuite) TestUserEditUsernameCmd() { s.Run("User not found", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newUsername := "newusername" s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) err := userEditUsernameCmdF(s.client, &command, []string{userArg, newUsername}) s.Require().EqualError(err, "user testUser not found") }) s.Run("Edit username successfully", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newUsername := "newusername" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} updatedUser := model.User{Id: "userId", Username: "newusername", Email: "test@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUser(context.TODO(), &updatedUser). Return(&updatedUser, &model.Response{}, nil). Times(1) err := userEditUsernameCmdF(s.client, &command, []string{userArg, newUsername}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&updatedUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invalid username", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newUsername := "!invalid!" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) err := userEditUsernameCmdF(s.client, &command, []string{userArg, newUsername}) s.Require().EqualError(err, "invalid username: '!invalid!'") }) s.Run("UpdateUser API error", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newUsername := "newusername" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} updatedUser := model.User{Id: "userId", Username: "newusername", Email: "test@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUser(context.TODO(), &updatedUser). Return(nil, &model.Response{}, errors.New("API error")). Times(1) err := userEditUsernameCmdF(s.client, &command, []string{userArg, newUsername}) s.Require().EqualError(err, "failed to update user username: API error") }) } func (s *MmctlUnitTestSuite) TestUserEditEmailCmd() { s.Run("User not found", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newEmail := "newemail@example.com" s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) err := userEditEmailCmdF(s.client, &command, []string{userArg, newEmail}) s.Require().EqualError(err, "user testUser not found") }) s.Run("Edit email successfully", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newEmail := "newemail@example.com" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} updatedUser := model.User{Id: "userId", Username: "testUser", Email: "newemail@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUser(context.TODO(), &updatedUser). Return(&updatedUser, &model.Response{}, nil). Times(1) err := userEditEmailCmdF(s.client, &command, []string{userArg, newEmail}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&updatedUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Invalid email", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newEmail := "invalidemail" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) err := userEditEmailCmdF(s.client, &command, []string{userArg, newEmail}) s.Require().EqualError(err, "invalid email: 'invalidemail'") }) s.Run("UpdateUser API error", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newEmail := "newemail@example.com" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} updatedUser := model.User{Id: "userId", Username: "testUser", Email: "newemail@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUser(context.TODO(), &updatedUser). Return(nil, &model.Response{}, errors.New("API error")). Times(1) err := userEditEmailCmdF(s.client, &command, []string{userArg, newEmail}) s.Require().EqualError(err, "failed to update user email: API error") }) } func (s *MmctlUnitTestSuite) TestUserEditAuthdataCmd() { s.Run("User not found", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newAuthdata := "newauth123" s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) s.client. EXPECT(). GetUser(context.TODO(), userArg, ""). Return(nil, &model.Response{}, nil). Times(1) err := userEditAuthdataCmdF(s.client, &command, []string{userArg, newAuthdata}) s.Require().EqualError(err, "user testUser not found") }) s.Run("Edit authdata successfully", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newAuthdata := "newauth123" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com", AuthData: nil} userAuth := model.UserAuth{AuthData: &newAuthdata, AuthService: mockUser.AuthService} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserAuth(context.TODO(), mockUser.Id, &userAuth). Return(&userAuth, &model.Response{}, nil). Times(1) err := userEditAuthdataCmdF(s.client, &command, []string{userArg, newAuthdata}) s.Require().Nil(err) s.Require().Len(printer.GetLines(), 1) s.Require().Equal(&mockUser, printer.GetLines()[0]) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Clear authdata returns error", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newAuthdata := "" authData := "existingauth" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com", AuthData: &authData, AuthService: model.UserAuthServiceGitlab} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) err := userEditAuthdataCmdF(s.client, &command, []string{userArg, newAuthdata}) s.Require().EqualError(err, "cannot clear authdata as the user is using gitlab to log in") s.Require().Len(printer.GetLines(), 0) s.Require().Len(printer.GetErrorLines(), 0) }) s.Run("Authdata too long", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newAuthdata := strings.Repeat("x", model.UserAuthDataMaxLength+1) mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com"} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) err := userEditAuthdataCmdF(s.client, &command, []string{userArg, newAuthdata}) s.Require().EqualError(err, fmt.Sprintf("authdata too long. Maximum length is %d characters", model.UserAuthDataMaxLength)) }) s.Run("UpdateUser API error", func() { printer.Clean() command := cobra.Command{} userArg := "testUser" newAuthdata := "newauth123" mockUser := model.User{Id: "userId", Username: "testUser", Email: "test@example.com", AuthData: nil} userAuth := model.UserAuth{AuthData: &newAuthdata, AuthService: mockUser.AuthService} s.client. EXPECT(). GetUserByUsername(context.TODO(), userArg, ""). Return(&mockUser, &model.Response{}, nil). Times(1) s.client. EXPECT(). UpdateUserAuth(context.TODO(), mockUser.Id, &userAuth). Return(nil, &model.Response{}, errors.New("API error")). Times(1) err := userEditAuthdataCmdF(s.client, &command, []string{userArg, newAuthdata}) s.Require().EqualError(err, "failed to update user authdata: API error") }) }