github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/bot_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  
    17  	"github.com/mattermost/mattermost-server/v5/model"
    18  	"github.com/mattermost/mattermost-server/v5/utils/fileutils"
    19  )
    20  
    21  func TestCreateBot(t *testing.T) {
    22  	t.Run("invalid bot", func(t *testing.T) {
    23  		t.Run("relative to user", func(t *testing.T) {
    24  			th := Setup(t).InitBasic()
    25  			defer th.TearDown()
    26  
    27  			_, err := th.App.CreateBot(&model.Bot{
    28  				Username:    "invalid username",
    29  				Description: "a bot",
    30  				OwnerId:     th.BasicUser.Id,
    31  			})
    32  			require.NotNil(t, err)
    33  			require.Equal(t, "model.user.is_valid.username.app_error", err.Id)
    34  		})
    35  
    36  		t.Run("relative to bot", func(t *testing.T) {
    37  			th := Setup(t).InitBasic()
    38  			defer th.TearDown()
    39  
    40  			_, err := th.App.CreateBot(&model.Bot{
    41  				Username:    "username",
    42  				Description: strings.Repeat("x", 1025),
    43  				OwnerId:     th.BasicUser.Id,
    44  			})
    45  			require.NotNil(t, err)
    46  			require.Equal(t, "model.bot.is_valid.description.app_error", err.Id)
    47  		})
    48  
    49  		t.Run("username contains . character", func(t *testing.T) {
    50  			th := Setup(t).InitBasic()
    51  			defer th.TearDown()
    52  
    53  			bot, err := th.App.CreateBot(&model.Bot{
    54  				Username:    "username.",
    55  				Description: "a bot",
    56  				OwnerId:     th.BasicUser.Id,
    57  			})
    58  			require.NotNil(t, err)
    59  			require.Nil(t, bot)
    60  			require.Equal(t, "model.user.is_valid.email.app_error", err.Id)
    61  		})
    62  	})
    63  
    64  	t.Run("create bot", func(t *testing.T) {
    65  		th := Setup(t).InitBasic()
    66  		defer th.TearDown()
    67  
    68  		bot, err := th.App.CreateBot(&model.Bot{
    69  			Username:    "username",
    70  			Description: "a bot",
    71  			OwnerId:     th.BasicUser.Id,
    72  		})
    73  		require.Nil(t, err)
    74  		defer th.App.PermanentDeleteBot(bot.UserId)
    75  		assert.Equal(t, "username", bot.Username)
    76  		assert.Equal(t, "a bot", bot.Description)
    77  		assert.Equal(t, th.BasicUser.Id, bot.OwnerId)
    78  
    79  		// Check that a post was created to add bot to team and channels
    80  		channel, err := th.App.GetOrCreateDirectChannel(bot.UserId, th.BasicUser.Id)
    81  		require.Nil(t, err)
    82  		posts, err := th.App.GetPosts(channel.Id, 0, 1)
    83  		require.Nil(t, err)
    84  
    85  		postArray := posts.ToSlice()
    86  		assert.Len(t, postArray, 1)
    87  		assert.Equal(t, postArray[0].Type, model.POST_ADD_BOT_TEAMS_CHANNELS)
    88  	})
    89  
    90  	t.Run("create bot, username already used by a non-bot user", func(t *testing.T) {
    91  		th := Setup(t).InitBasic()
    92  		defer th.TearDown()
    93  
    94  		_, err := th.App.CreateBot(&model.Bot{
    95  			Username:    th.BasicUser.Username,
    96  			Description: "a bot",
    97  			OwnerId:     th.BasicUser.Id,
    98  		})
    99  		require.NotNil(t, err)
   100  		require.Equal(t, "store.sql_user.save.username_exists.app_error", err.Id)
   101  	})
   102  }
   103  
   104  func TestPatchBot(t *testing.T) {
   105  	t.Run("invalid patch for user", func(t *testing.T) {
   106  		th := Setup(t).InitBasic()
   107  		defer th.TearDown()
   108  
   109  		bot, err := th.App.CreateBot(&model.Bot{
   110  			Username:    "username",
   111  			Description: "a bot",
   112  			OwnerId:     th.BasicUser.Id,
   113  		})
   114  		require.Nil(t, err)
   115  		defer th.App.PermanentDeleteBot(bot.UserId)
   116  
   117  		botPatch := &model.BotPatch{
   118  			Username:    sToP("invalid username"),
   119  			DisplayName: sToP("an updated bot"),
   120  			Description: sToP("updated bot"),
   121  		}
   122  
   123  		_, err = th.App.PatchBot(bot.UserId, botPatch)
   124  		require.NotNil(t, err)
   125  		require.Equal(t, "model.user.is_valid.username.app_error", err.Id)
   126  	})
   127  
   128  	t.Run("invalid patch for bot", func(t *testing.T) {
   129  		th := Setup(t).InitBasic()
   130  		defer th.TearDown()
   131  
   132  		bot, err := th.App.CreateBot(&model.Bot{
   133  			Username:    "username",
   134  			Description: "a bot",
   135  			OwnerId:     th.BasicUser.Id,
   136  		})
   137  		require.Nil(t, err)
   138  		defer th.App.PermanentDeleteBot(bot.UserId)
   139  
   140  		botPatch := &model.BotPatch{
   141  			Username:    sToP("username"),
   142  			DisplayName: sToP("display name"),
   143  			Description: sToP(strings.Repeat("x", 1025)),
   144  		}
   145  
   146  		_, err = th.App.PatchBot(bot.UserId, botPatch)
   147  		require.NotNil(t, err)
   148  		require.Equal(t, "model.bot.is_valid.description.app_error", err.Id)
   149  	})
   150  
   151  	t.Run("patch bot", func(t *testing.T) {
   152  		th := Setup(t).InitBasic()
   153  		defer th.TearDown()
   154  
   155  		bot := &model.Bot{
   156  			Username:    "username",
   157  			DisplayName: "bot",
   158  			Description: "a bot",
   159  			OwnerId:     th.BasicUser.Id,
   160  		}
   161  
   162  		createdBot, err := th.App.CreateBot(bot)
   163  		require.Nil(t, err)
   164  		defer th.App.PermanentDeleteBot(createdBot.UserId)
   165  
   166  		botPatch := &model.BotPatch{
   167  			Username:    sToP("username2"),
   168  			DisplayName: sToP("updated bot"),
   169  			Description: sToP("an updated bot"),
   170  		}
   171  
   172  		patchedBot, err := th.App.PatchBot(createdBot.UserId, botPatch)
   173  		require.Nil(t, err)
   174  
   175  		// patchedBot should create a new .UpdateAt time
   176  		require.NotEqual(t, createdBot.UpdateAt, patchedBot.UpdateAt)
   177  
   178  		createdBot.Username = "username2"
   179  		createdBot.DisplayName = "updated bot"
   180  		createdBot.Description = "an updated bot"
   181  		createdBot.UpdateAt = patchedBot.UpdateAt
   182  		require.Equal(t, createdBot, patchedBot)
   183  	})
   184  
   185  	t.Run("patch bot, username already used by a non-bot user", func(t *testing.T) {
   186  		th := Setup(t).InitBasic()
   187  		defer th.TearDown()
   188  
   189  		bot, err := th.App.CreateBot(&model.Bot{
   190  			Username:    "username",
   191  			DisplayName: "bot",
   192  			Description: "a bot",
   193  			OwnerId:     th.BasicUser.Id,
   194  		})
   195  		require.Nil(t, err)
   196  		defer th.App.PermanentDeleteBot(bot.UserId)
   197  
   198  		botPatch := &model.BotPatch{
   199  			Username: sToP(th.BasicUser2.Username),
   200  		}
   201  
   202  		_, err = th.App.PatchBot(bot.UserId, botPatch)
   203  		require.NotNil(t, err)
   204  		require.Equal(t, "store.sql_user.update.username_taken.app_error", err.Id)
   205  	})
   206  }
   207  
   208  func TestGetBot(t *testing.T) {
   209  	th := Setup(t).InitBasic()
   210  	defer th.TearDown()
   211  
   212  	bot1, err := th.App.CreateBot(&model.Bot{
   213  		Username:    "username",
   214  		Description: "a bot",
   215  		OwnerId:     th.BasicUser.Id,
   216  	})
   217  	require.Nil(t, err)
   218  	defer th.App.PermanentDeleteBot(bot1.UserId)
   219  
   220  	bot2, err := th.App.CreateBot(&model.Bot{
   221  		Username:    "username2",
   222  		Description: "a second bot",
   223  		OwnerId:     th.BasicUser.Id,
   224  	})
   225  	require.Nil(t, err)
   226  	defer th.App.PermanentDeleteBot(bot2.UserId)
   227  
   228  	deletedBot, err := th.App.CreateBot(&model.Bot{
   229  		Username:    "username3",
   230  		Description: "a deleted bot",
   231  		OwnerId:     th.BasicUser.Id,
   232  	})
   233  	require.Nil(t, err)
   234  	deletedBot, err = th.App.UpdateBotActive(deletedBot.UserId, false)
   235  	require.Nil(t, err)
   236  	defer th.App.PermanentDeleteBot(deletedBot.UserId)
   237  
   238  	t.Run("get unknown bot", func(t *testing.T) {
   239  		_, err := th.App.GetBot(model.NewId(), false)
   240  		require.NotNil(t, err)
   241  		require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
   242  	})
   243  
   244  	t.Run("get bot1", func(t *testing.T) {
   245  		bot, err := th.App.GetBot(bot1.UserId, false)
   246  		require.Nil(t, err)
   247  		assert.Equal(t, bot1, bot)
   248  	})
   249  
   250  	t.Run("get bot2", func(t *testing.T) {
   251  		bot, err := th.App.GetBot(bot2.UserId, false)
   252  		require.Nil(t, err)
   253  		assert.Equal(t, bot2, bot)
   254  	})
   255  
   256  	t.Run("get deleted bot", func(t *testing.T) {
   257  		_, err := th.App.GetBot(deletedBot.UserId, false)
   258  		require.NotNil(t, err)
   259  		require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
   260  	})
   261  
   262  	t.Run("get deleted bot, include deleted", func(t *testing.T) {
   263  		bot, err := th.App.GetBot(deletedBot.UserId, true)
   264  		require.Nil(t, err)
   265  		assert.Equal(t, deletedBot, bot)
   266  	})
   267  }
   268  
   269  func TestGetBots(t *testing.T) {
   270  	th := Setup(t)
   271  	defer th.TearDown()
   272  
   273  	OwnerId1 := model.NewId()
   274  	OwnerId2 := model.NewId()
   275  
   276  	bot1, err := th.App.CreateBot(&model.Bot{
   277  		Username:    "username",
   278  		Description: "a bot",
   279  		OwnerId:     OwnerId1,
   280  	})
   281  	require.Nil(t, err)
   282  	defer th.App.PermanentDeleteBot(bot1.UserId)
   283  
   284  	deletedBot1, err := th.App.CreateBot(&model.Bot{
   285  		Username:    "username4",
   286  		Description: "a deleted bot",
   287  		OwnerId:     OwnerId1,
   288  	})
   289  	require.Nil(t, err)
   290  	deletedBot1, err = th.App.UpdateBotActive(deletedBot1.UserId, false)
   291  	require.Nil(t, err)
   292  	defer th.App.PermanentDeleteBot(deletedBot1.UserId)
   293  
   294  	bot2, err := th.App.CreateBot(&model.Bot{
   295  		Username:    "username2",
   296  		Description: "a second bot",
   297  		OwnerId:     OwnerId1,
   298  	})
   299  	require.Nil(t, err)
   300  	defer th.App.PermanentDeleteBot(bot2.UserId)
   301  
   302  	bot3, err := th.App.CreateBot(&model.Bot{
   303  		Username:    "username3",
   304  		Description: "a third bot",
   305  		OwnerId:     OwnerId1,
   306  	})
   307  	require.Nil(t, err)
   308  	defer th.App.PermanentDeleteBot(bot3.UserId)
   309  
   310  	bot4, err := th.App.CreateBot(&model.Bot{
   311  		Username:    "username5",
   312  		Description: "a fourth bot",
   313  		OwnerId:     OwnerId2,
   314  	})
   315  	require.Nil(t, err)
   316  	defer th.App.PermanentDeleteBot(bot4.UserId)
   317  
   318  	deletedBot2, err := th.App.CreateBot(&model.Bot{
   319  		Username:    "username6",
   320  		Description: "a deleted bot",
   321  		OwnerId:     OwnerId2,
   322  	})
   323  	require.Nil(t, err)
   324  	deletedBot2, err = th.App.UpdateBotActive(deletedBot2.UserId, false)
   325  	require.Nil(t, err)
   326  	defer th.App.PermanentDeleteBot(deletedBot2.UserId)
   327  
   328  	t.Run("get bots, page=0, perPage=10", func(t *testing.T) {
   329  		bots, err := th.App.GetBots(&model.BotGetOptions{
   330  			Page:           0,
   331  			PerPage:        10,
   332  			OwnerId:        "",
   333  			IncludeDeleted: false,
   334  		})
   335  		require.Nil(t, err)
   336  		assert.Equal(t, model.BotList{bot1, bot2, bot3, bot4}, bots)
   337  	})
   338  
   339  	t.Run("get bots, page=0, perPage=1", func(t *testing.T) {
   340  		bots, err := th.App.GetBots(&model.BotGetOptions{
   341  			Page:           0,
   342  			PerPage:        1,
   343  			OwnerId:        "",
   344  			IncludeDeleted: false,
   345  		})
   346  		require.Nil(t, err)
   347  		assert.Equal(t, model.BotList{bot1}, bots)
   348  	})
   349  
   350  	t.Run("get bots, page=1, perPage=2", func(t *testing.T) {
   351  		bots, err := th.App.GetBots(&model.BotGetOptions{
   352  			Page:           1,
   353  			PerPage:        2,
   354  			OwnerId:        "",
   355  			IncludeDeleted: false,
   356  		})
   357  		require.Nil(t, err)
   358  		assert.Equal(t, model.BotList{bot3, bot4}, bots)
   359  	})
   360  
   361  	t.Run("get bots, page=2, perPage=2", func(t *testing.T) {
   362  		bots, err := th.App.GetBots(&model.BotGetOptions{
   363  			Page:           2,
   364  			PerPage:        2,
   365  			OwnerId:        "",
   366  			IncludeDeleted: false,
   367  		})
   368  		require.Nil(t, err)
   369  		assert.Equal(t, model.BotList{}, bots)
   370  	})
   371  
   372  	t.Run("get bots, page=0, perPage=10, include deleted", func(t *testing.T) {
   373  		bots, err := th.App.GetBots(&model.BotGetOptions{
   374  			Page:           0,
   375  			PerPage:        10,
   376  			OwnerId:        "",
   377  			IncludeDeleted: true,
   378  		})
   379  		require.Nil(t, err)
   380  		assert.Equal(t, model.BotList{bot1, deletedBot1, bot2, bot3, bot4, deletedBot2}, bots)
   381  	})
   382  
   383  	t.Run("get bots, page=0, perPage=1, include deleted", func(t *testing.T) {
   384  		bots, err := th.App.GetBots(&model.BotGetOptions{
   385  			Page:           0,
   386  			PerPage:        1,
   387  			OwnerId:        "",
   388  			IncludeDeleted: true,
   389  		})
   390  		require.Nil(t, err)
   391  		assert.Equal(t, model.BotList{bot1}, bots)
   392  	})
   393  
   394  	t.Run("get bots, page=1, perPage=2, include deleted", func(t *testing.T) {
   395  		bots, err := th.App.GetBots(&model.BotGetOptions{
   396  			Page:           1,
   397  			PerPage:        2,
   398  			OwnerId:        "",
   399  			IncludeDeleted: true,
   400  		})
   401  		require.Nil(t, err)
   402  		assert.Equal(t, model.BotList{bot2, bot3}, bots)
   403  	})
   404  
   405  	t.Run("get bots, page=2, perPage=2, include deleted", func(t *testing.T) {
   406  		bots, err := th.App.GetBots(&model.BotGetOptions{
   407  			Page:           2,
   408  			PerPage:        2,
   409  			OwnerId:        "",
   410  			IncludeDeleted: true,
   411  		})
   412  		require.Nil(t, err)
   413  		assert.Equal(t, model.BotList{bot4, deletedBot2}, bots)
   414  	})
   415  
   416  	t.Run("get offset=0, limit=10, creator id 1", func(t *testing.T) {
   417  		bots, err := th.App.GetBots(&model.BotGetOptions{
   418  			Page:           0,
   419  			PerPage:        10,
   420  			OwnerId:        OwnerId1,
   421  			IncludeDeleted: false,
   422  		})
   423  		require.Nil(t, err)
   424  		require.Equal(t, model.BotList{bot1, bot2, bot3}, bots)
   425  	})
   426  
   427  	t.Run("get offset=0, limit=10, creator id 2", func(t *testing.T) {
   428  		bots, err := th.App.GetBots(&model.BotGetOptions{
   429  			Page:           0,
   430  			PerPage:        10,
   431  			OwnerId:        OwnerId2,
   432  			IncludeDeleted: false,
   433  		})
   434  		require.Nil(t, err)
   435  		require.Equal(t, model.BotList{bot4}, bots)
   436  	})
   437  
   438  	t.Run("get offset=0, limit=10, include deleted, creator id 1", func(t *testing.T) {
   439  		bots, err := th.App.GetBots(&model.BotGetOptions{
   440  			Page:           0,
   441  			PerPage:        10,
   442  			OwnerId:        OwnerId1,
   443  			IncludeDeleted: true,
   444  		})
   445  		require.Nil(t, err)
   446  		require.Equal(t, model.BotList{bot1, deletedBot1, bot2, bot3}, bots)
   447  	})
   448  
   449  	t.Run("get offset=0, limit=10, include deleted, creator id 2", func(t *testing.T) {
   450  		bots, err := th.App.GetBots(&model.BotGetOptions{
   451  			Page:           0,
   452  			PerPage:        10,
   453  			OwnerId:        OwnerId2,
   454  			IncludeDeleted: true,
   455  		})
   456  		require.Nil(t, err)
   457  		require.Equal(t, model.BotList{bot4, deletedBot2}, bots)
   458  	})
   459  }
   460  
   461  func TestUpdateBotActive(t *testing.T) {
   462  	t.Run("unknown bot", func(t *testing.T) {
   463  		th := Setup(t).InitBasic()
   464  		defer th.TearDown()
   465  
   466  		_, err := th.App.UpdateBotActive(model.NewId(), false)
   467  		require.NotNil(t, err)
   468  		require.Equal(t, "store.sql_user.missing_account.const", err.Id)
   469  	})
   470  
   471  	t.Run("disable/enable bot", func(t *testing.T) {
   472  		th := Setup(t).InitBasic()
   473  		defer th.TearDown()
   474  
   475  		bot, err := th.App.CreateBot(&model.Bot{
   476  			Username:    "username",
   477  			Description: "a bot",
   478  			OwnerId:     th.BasicUser.Id,
   479  		})
   480  		require.Nil(t, err)
   481  		defer th.App.PermanentDeleteBot(bot.UserId)
   482  
   483  		disabledBot, err := th.App.UpdateBotActive(bot.UserId, false)
   484  		require.Nil(t, err)
   485  		require.NotEqual(t, 0, disabledBot.DeleteAt)
   486  
   487  		// Disabling should be idempotent
   488  		disabledBotAgain, err := th.App.UpdateBotActive(bot.UserId, false)
   489  		require.Nil(t, err)
   490  		require.Equal(t, disabledBot.DeleteAt, disabledBotAgain.DeleteAt)
   491  
   492  		reenabledBot, err := th.App.UpdateBotActive(bot.UserId, true)
   493  		require.Nil(t, err)
   494  		require.EqualValues(t, 0, reenabledBot.DeleteAt)
   495  
   496  		// Re-enabling should be idempotent
   497  		reenabledBotAgain, err := th.App.UpdateBotActive(bot.UserId, true)
   498  		require.Nil(t, err)
   499  		require.Equal(t, reenabledBot.DeleteAt, reenabledBotAgain.DeleteAt)
   500  	})
   501  }
   502  
   503  func TestPermanentDeleteBot(t *testing.T) {
   504  	th := Setup(t).InitBasic()
   505  	defer th.TearDown()
   506  
   507  	bot, err := th.App.CreateBot(&model.Bot{
   508  		Username:    "username",
   509  		Description: "a bot",
   510  		OwnerId:     th.BasicUser.Id,
   511  	})
   512  	require.Nil(t, err)
   513  
   514  	require.Nil(t, th.App.PermanentDeleteBot(bot.UserId))
   515  
   516  	_, err = th.App.GetBot(bot.UserId, false)
   517  	require.NotNil(t, err)
   518  	require.Equal(t, "store.sql_bot.get.missing.app_error", err.Id)
   519  }
   520  
   521  func TestDisableUserBots(t *testing.T) {
   522  	th := Setup(t)
   523  	defer th.TearDown()
   524  
   525  	ownerId1 := model.NewId()
   526  	ownerId2 := model.NewId()
   527  
   528  	bots := []*model.Bot{}
   529  	defer func() {
   530  		for _, bot := range bots {
   531  			th.App.PermanentDeleteBot(bot.UserId)
   532  		}
   533  	}()
   534  
   535  	for i := 0; i < 46; i++ {
   536  		bot, err := th.App.CreateBot(&model.Bot{
   537  			Username:    fmt.Sprintf("username%v", i),
   538  			Description: "a bot",
   539  			OwnerId:     ownerId1,
   540  		})
   541  		require.Nil(t, err)
   542  		bots = append(bots, bot)
   543  	}
   544  	require.Len(t, bots, 46)
   545  
   546  	u2bot1, err := th.App.CreateBot(&model.Bot{
   547  		Username:    "username_nodisable",
   548  		Description: "a bot",
   549  		OwnerId:     ownerId2,
   550  	})
   551  	require.Nil(t, err)
   552  	defer th.App.PermanentDeleteBot(u2bot1.UserId)
   553  
   554  	err = th.App.disableUserBots(ownerId1)
   555  	require.Nil(t, err)
   556  
   557  	// Check all bots and corrensponding users are disabled for creator 1
   558  	for _, bot := range bots {
   559  		retbot, err2 := th.App.GetBot(bot.UserId, true)
   560  		require.Nil(t, err2)
   561  		require.NotZero(t, retbot.DeleteAt, bot.Username)
   562  	}
   563  
   564  	// Check bots and corresponding user not disabled for creator 2
   565  	bot, err := th.App.GetBot(u2bot1.UserId, true)
   566  	require.Nil(t, err)
   567  	require.Zero(t, bot.DeleteAt)
   568  
   569  	user, err := th.App.GetUser(u2bot1.UserId)
   570  	require.Nil(t, err)
   571  	require.Zero(t, user.DeleteAt)
   572  
   573  	// Bad id doesn't do anything or break horribly
   574  	err = th.App.disableUserBots(model.NewId())
   575  	require.Nil(t, err)
   576  }
   577  
   578  func TestNotifySysadminsBotOwnerDisabled(t *testing.T) {
   579  	th := Setup(t)
   580  	defer th.TearDown()
   581  
   582  	userBots := []*model.Bot{}
   583  	defer func() {
   584  		for _, bot := range userBots {
   585  			th.App.PermanentDeleteBot(bot.UserId)
   586  		}
   587  	}()
   588  
   589  	// // Create two sysadmins
   590  	sysadmin1 := model.User{
   591  		Email:    "sys1@example.com",
   592  		Nickname: "nn_sysadmin1",
   593  		Password: "hello1",
   594  		Username: "un_sysadmin1",
   595  		Roles:    model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID}
   596  	_, err := th.App.CreateUser(&sysadmin1)
   597  	require.Nil(t, err, "failed to create user")
   598  	th.App.UpdateUserRoles(sysadmin1.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false)
   599  
   600  	sysadmin2 := model.User{
   601  		Email:    "sys2@example.com",
   602  		Nickname: "nn_sysadmin2",
   603  		Password: "hello1",
   604  		Username: "un_sysadmin2",
   605  		Roles:    model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID}
   606  	_, err = th.App.CreateUser(&sysadmin2)
   607  	require.Nil(t, err, "failed to create user")
   608  	th.App.UpdateUserRoles(sysadmin2.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_ADMIN_ROLE_ID, false)
   609  
   610  	// create user to be disabled
   611  	user1, err := th.App.CreateUser(&model.User{
   612  		Email:    "user1@example.com",
   613  		Username: "user1_disabled",
   614  		Nickname: "user1",
   615  		Password: "Password1",
   616  	})
   617  	require.Nil(t, err, "failed to create user")
   618  
   619  	// create user that doesn't own any bots
   620  	user2, err := th.App.CreateUser(&model.User{
   621  		Email:    "user2@example.com",
   622  		Username: "user2_disabled",
   623  		Nickname: "user2",
   624  		Password: "Password1",
   625  	})
   626  	require.Nil(t, err, "failed to create user")
   627  
   628  	const numBotsToPrint = 10
   629  
   630  	// create bots owned by user (equal to numBotsToPrint)
   631  	var bot *model.Bot
   632  	for i := 0; i < numBotsToPrint; i++ {
   633  		bot, err = th.App.CreateBot(&model.Bot{
   634  			Username:    fmt.Sprintf("bot%v", i),
   635  			Description: "a bot",
   636  			OwnerId:     user1.Id,
   637  		})
   638  		require.Nil(t, err)
   639  		userBots = append(userBots, bot)
   640  	}
   641  	assert.Len(t, userBots, 10)
   642  
   643  	// get DM channels for sysadmin1 and sysadmin2
   644  	channelSys1, appErr := th.App.GetOrCreateDirectChannel(sysadmin1.Id, sysadmin1.Id)
   645  	require.Nil(t, appErr)
   646  	channelSys2, appErr := th.App.GetOrCreateDirectChannel(sysadmin2.Id, sysadmin2.Id)
   647  	require.Nil(t, appErr)
   648  
   649  	// send notification for user without bots
   650  	err = th.App.notifySysadminsBotOwnerDeactivated(user2.Id)
   651  	require.Nil(t, err)
   652  
   653  	// get posts from sysadmin1 and sysadmin2 DM channels
   654  	posts1, err := th.App.GetPosts(channelSys1.Id, 0, 5)
   655  	require.Nil(t, err)
   656  	assert.Empty(t, posts1.Order)
   657  
   658  	posts2, err := th.App.GetPosts(channelSys2.Id, 0, 5)
   659  	require.Nil(t, err)
   660  	assert.Empty(t, posts2.Order)
   661  
   662  	// send notification for user with bots
   663  	err = th.App.notifySysadminsBotOwnerDeactivated(user1.Id)
   664  	require.Nil(t, err)
   665  
   666  	// get posts from sysadmin1  and sysadmin2 DM channels
   667  	posts1, err = th.App.GetPosts(channelSys1.Id, 0, 5)
   668  	require.Nil(t, err)
   669  	assert.Len(t, posts1.Order, 1)
   670  
   671  	posts2, err = th.App.GetPosts(channelSys2.Id, 0, 5)
   672  	require.Nil(t, err)
   673  	assert.Len(t, posts2.Order, 1)
   674  
   675  	post := posts1.Posts[posts1.Order[0]].Message
   676  	assert.Equal(t, "user1_disabled was deactivated. They managed the following bot accounts which have now been disabled.\n\n* bot0\n* bot1\n* bot2\n* bot3\n* bot4\n* bot5\n* bot6\n* bot7\n* bot8\n* bot9\nYou can take ownership of each bot by enabling it at **Integrations > Bot Accounts** and creating new tokens for the bot.\n\nFor more information, see our [documentation](https://docs.mattermost.com/developer/bot-accounts.html#what-happens-when-a-user-who-owns-bot-accounts-is-disabled).", post)
   677  
   678  	// print all bots
   679  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated = true })
   680  	message := th.App.getDisableBotSysadminMessage(user1, userBots)
   681  	assert.Equal(t, "user1_disabled was deactivated. They managed the following bot accounts which have now been disabled.\n\n* bot0\n* bot1\n* bot2\n* bot3\n* bot4\n* bot5\n* bot6\n* bot7\n* bot8\n* bot9\nYou can take ownership of each bot by enabling it at **Integrations > Bot Accounts** and creating new tokens for the bot.\n\nFor more information, see our [documentation](https://docs.mattermost.com/developer/bot-accounts.html#what-happens-when-a-user-who-owns-bot-accounts-is-disabled).", message)
   682  
   683  	// print all bots
   684  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated = false })
   685  	message = th.App.getDisableBotSysadminMessage(user1, userBots)
   686  	assert.Equal(t, "user1_disabled was deactivated. They managed the following bot accounts which are still enabled.\n\n* bot0\n* bot1\n* bot2\n* bot3\n* bot4\n* bot5\n* bot6\n* bot7\n* bot8\n* bot9\n\nWe strongly recommend you to take ownership of each bot by re-enabling it at **Integrations > Bot Accounts** and creating new tokens for the bot.\n\nFor more information, see our [documentation](https://docs.mattermost.com/developer/bot-accounts.html#what-happens-when-a-user-who-owns-bot-accounts-is-disabled).\n\nIf you want bot accounts to disable automatically after owner deactivation, set “Disable bot accounts when owner is deactivated” in **System Console > Integrations > Bot Accounts** to true.", message)
   687  
   688  	// create additional bot to go over the printable limit
   689  	for i := numBotsToPrint; i < numBotsToPrint+1; i++ {
   690  		bot, err = th.App.CreateBot(&model.Bot{
   691  			Username:    fmt.Sprintf("bot%v", i),
   692  			Description: "a bot",
   693  			OwnerId:     user1.Id,
   694  		})
   695  		require.Nil(t, err)
   696  		userBots = append(userBots, bot)
   697  	}
   698  	assert.Len(t, userBots, 11)
   699  
   700  	// truncate number bots printed
   701  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated = true })
   702  	message = th.App.getDisableBotSysadminMessage(user1, userBots)
   703  	assert.Equal(t, "user1_disabled was deactivated. They managed 11 bot accounts which have now been disabled, including the following:\n\n* bot0\n* bot1\n* bot2\n* bot3\n* bot4\n* bot5\n* bot6\n* bot7\n* bot8\n* bot9\nYou can take ownership of each bot by enabling it at **Integrations > Bot Accounts** and creating new tokens for the bot.\n\nFor more information, see our [documentation](https://docs.mattermost.com/developer/bot-accounts.html#what-happens-when-a-user-who-owns-bot-accounts-is-disabled).", message)
   704  
   705  	// truncate number bots printed
   706  	th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated = false })
   707  	message = th.App.getDisableBotSysadminMessage(user1, userBots)
   708  	assert.Equal(t, "user1_disabled was deactivated. They managed 11 bot accounts which are still enabled, including the following:\n\n* bot0\n* bot1\n* bot2\n* bot3\n* bot4\n* bot5\n* bot6\n* bot7\n* bot8\n* bot9\nWe strongly recommend you to take ownership of each bot by re-enabling it at **Integrations > Bot Accounts** and creating new tokens for the bot.\n\nFor more information, see our [documentation](https://docs.mattermost.com/developer/bot-accounts.html#what-happens-when-a-user-who-owns-bot-accounts-is-disabled).\n\nIf you want bot accounts to disable automatically after owner deactivation, set “Disable bot accounts when owner is deactivated” in **System Console > Integrations > Bot Accounts** to true.", message)
   709  }
   710  
   711  func TestConvertUserToBot(t *testing.T) {
   712  	t.Run("invalid user", func(t *testing.T) {
   713  		t.Run("invalid user id", func(t *testing.T) {
   714  			th := Setup(t).InitBasic()
   715  			defer th.TearDown()
   716  
   717  			_, err := th.App.ConvertUserToBot(&model.User{
   718  				Username: "username",
   719  				Id:       "",
   720  			})
   721  			require.NotNil(t, err)
   722  			require.Equal(t, "model.bot.is_valid.user_id.app_error", err.Id)
   723  		})
   724  
   725  		t.Run("invalid username", func(t *testing.T) {
   726  			th := Setup(t).InitBasic()
   727  			defer th.TearDown()
   728  
   729  			_, err := th.App.ConvertUserToBot(&model.User{
   730  				Username: "invalid username",
   731  				Id:       th.BasicUser.Id,
   732  			})
   733  			require.NotNil(t, err)
   734  			require.Equal(t, "model.bot.is_valid.username.app_error", err.Id)
   735  		})
   736  	})
   737  
   738  	t.Run("valid user", func(t *testing.T) {
   739  		th := Setup(t).InitBasic()
   740  		defer th.TearDown()
   741  
   742  		bot, err := th.App.ConvertUserToBot(&model.User{
   743  			Username: "username",
   744  			Id:       th.BasicUser.Id,
   745  		})
   746  		require.Nil(t, err)
   747  		defer th.App.PermanentDeleteBot(bot.UserId)
   748  		assert.Equal(t, "username", bot.Username)
   749  		assert.Equal(t, th.BasicUser.Id, bot.OwnerId)
   750  	})
   751  }
   752  
   753  func TestSetBotIconImage(t *testing.T) {
   754  	t.Run("invalid bot", func(t *testing.T) {
   755  		th := Setup(t).InitBasic()
   756  		defer th.TearDown()
   757  
   758  		path, _ := fileutils.FindDir("tests")
   759  		svgFile, fileErr := os.Open(filepath.Join(path, "test.svg"))
   760  		require.NoError(t, fileErr)
   761  		defer svgFile.Close()
   762  
   763  		err := th.App.SetBotIconImage("invalid_bot_id", svgFile)
   764  		require.NotNil(t, err)
   765  	})
   766  
   767  	t.Run("valid bot", func(t *testing.T) {
   768  		th := Setup(t).InitBasic()
   769  		defer th.TearDown()
   770  
   771  		// Set an icon image
   772  		path, _ := fileutils.FindDir("tests")
   773  		svgFile, fileErr := os.Open(filepath.Join(path, "test.svg"))
   774  		require.NoError(t, fileErr)
   775  		defer svgFile.Close()
   776  
   777  		expectedData, fileErr := ioutil.ReadAll(svgFile)
   778  		require.Nil(t, fileErr)
   779  		require.NotNil(t, expectedData)
   780  
   781  		bot, err := th.App.ConvertUserToBot(&model.User{
   782  			Username: "username",
   783  			Id:       th.BasicUser.Id,
   784  		})
   785  		require.Nil(t, err)
   786  		defer th.App.PermanentDeleteBot(bot.UserId)
   787  
   788  		fpath := fmt.Sprintf("/bots/%v/icon.svg", bot.UserId)
   789  		exists, err := th.App.FileExists(fpath)
   790  		require.Nil(t, err)
   791  		require.False(t, exists, "icon.svg shouldn't exist for the bot")
   792  
   793  		svgFile.Seek(0, 0)
   794  		err = th.App.SetBotIconImage(bot.UserId, svgFile)
   795  		require.Nil(t, err)
   796  
   797  		exists, err = th.App.FileExists(fpath)
   798  		require.Nil(t, err)
   799  		require.True(t, exists, "icon.svg should exist for the bot")
   800  
   801  		actualData, err := th.App.ReadFile(fpath)
   802  		require.Nil(t, err)
   803  		require.NotNil(t, actualData)
   804  
   805  		require.Equal(t, expectedData, actualData)
   806  	})
   807  }
   808  
   809  func TestGetBotIconImage(t *testing.T) {
   810  	t.Run("invalid bot", func(t *testing.T) {
   811  		th := Setup(t).InitBasic()
   812  		defer th.TearDown()
   813  
   814  		actualData, err := th.App.GetBotIconImage("invalid_bot_id")
   815  		require.NotNil(t, err)
   816  		require.Nil(t, actualData)
   817  	})
   818  
   819  	t.Run("valid bot", func(t *testing.T) {
   820  		th := Setup(t).InitBasic()
   821  		defer th.TearDown()
   822  
   823  		// Set an icon image
   824  		path, _ := fileutils.FindDir("tests")
   825  		svgFile, fileErr := os.Open(filepath.Join(path, "test.svg"))
   826  		require.NoError(t, fileErr)
   827  		defer svgFile.Close()
   828  
   829  		expectedData, fileErr := ioutil.ReadAll(svgFile)
   830  		require.Nil(t, fileErr)
   831  		require.NotNil(t, expectedData)
   832  
   833  		bot, err := th.App.ConvertUserToBot(&model.User{
   834  			Username: "username",
   835  			Id:       th.BasicUser.Id,
   836  		})
   837  		require.Nil(t, err)
   838  		defer th.App.PermanentDeleteBot(bot.UserId)
   839  
   840  		svgFile.Seek(0, 0)
   841  		fpath := fmt.Sprintf("/bots/%v/icon.svg", bot.UserId)
   842  		_, err = th.App.WriteFile(svgFile, fpath)
   843  		require.Nil(t, err)
   844  
   845  		actualBytes, err := th.App.GetBotIconImage(bot.UserId)
   846  		require.Nil(t, err)
   847  		require.NotNil(t, actualBytes)
   848  
   849  		actualData, err := th.App.ReadFile(fpath)
   850  		require.Nil(t, err)
   851  		require.NotNil(t, actualData)
   852  
   853  		require.Equal(t, expectedData, actualData)
   854  	})
   855  }
   856  
   857  func TestDeleteBotIconImage(t *testing.T) {
   858  	t.Run("invalid bot", func(t *testing.T) {
   859  		th := Setup(t).InitBasic()
   860  		defer th.TearDown()
   861  
   862  		err := th.App.DeleteBotIconImage("invalid_bot_id")
   863  		require.NotNil(t, err)
   864  	})
   865  
   866  	t.Run("valid bot", func(t *testing.T) {
   867  		th := Setup(t).InitBasic()
   868  		defer th.TearDown()
   869  
   870  		// Set an icon image
   871  		path, _ := fileutils.FindDir("tests")
   872  		svgFile, fileErr := os.Open(filepath.Join(path, "test.svg"))
   873  		require.NoError(t, fileErr)
   874  		defer svgFile.Close()
   875  
   876  		expectedData, fileErr := ioutil.ReadAll(svgFile)
   877  		require.Nil(t, fileErr)
   878  		require.NotNil(t, expectedData)
   879  
   880  		bot, err := th.App.ConvertUserToBot(&model.User{
   881  			Username: "username",
   882  			Id:       th.BasicUser.Id,
   883  		})
   884  		require.Nil(t, err)
   885  		defer th.App.PermanentDeleteBot(bot.UserId)
   886  
   887  		// Set icon
   888  		svgFile.Seek(0, 0)
   889  		err = th.App.SetBotIconImage(bot.UserId, svgFile)
   890  		require.Nil(t, err)
   891  
   892  		// Get icon
   893  		actualData, err := th.App.GetBotIconImage(bot.UserId)
   894  		require.Nil(t, err)
   895  		require.NotNil(t, actualData)
   896  		require.Equal(t, expectedData, actualData)
   897  
   898  		// Bot icon should exist
   899  		fpath := fmt.Sprintf("/bots/%v/icon.svg", bot.UserId)
   900  		exists, err := th.App.FileExists(fpath)
   901  		require.Nil(t, err)
   902  		require.True(t, exists, "icon.svg should exist for the bot")
   903  
   904  		// Delete icon
   905  		err = th.App.DeleteBotIconImage(bot.UserId)
   906  		require.Nil(t, err)
   907  
   908  		// Bot icon should not exist
   909  		exists, err = th.App.FileExists(fpath)
   910  		require.Nil(t, err)
   911  		require.False(t, exists, "icon.svg should be deleted for the bot")
   912  	})
   913  }
   914  
   915  func sToP(s string) *string {
   916  	return &s
   917  }