package app import ( "testing" "github.com/mattermost/focalboard/server/model" "github.com/mattermost/focalboard/server/utils" "github.com/stretchr/testify/assert" ) func TestCreateCategory(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("base case", func(t *testing.T) { th.Store.EXPECT().CreateCategory(utils.Anything).Return(nil) th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", }, nil) category := &model.Category{ Name: "Category", UserID: "user_id", TeamID: "team_id", Type: "custom", } createdCategory, err := th.App.CreateCategory(category) assert.NotNil(t, createdCategory) assert.NoError(t, err) }) t.Run("creating invalid category", func(t *testing.T) { category := &model.Category{ Name: "", // empty name shouldn't be allowed UserID: "user_id", TeamID: "team_id", Type: "custom", } createdCategory, err := th.App.CreateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.Name = "Name" category.UserID = "" // empty creator user id shouldn't be allowed createdCategory, err = th.App.CreateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.UserID = "user_id" category.TeamID = "" // empty TeamID shouldn't be allowed createdCategory, err = th.App.CreateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.Type = "invalid" // unknown type shouldn't be allowed createdCategory, err = th.App.CreateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) }) } func TestUpdateCategory(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("base case", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "custom", }, nil) th.Store.EXPECT().UpdateCategory(utils.Anything).Return(nil) th.Store.EXPECT().GetCategory("category_id_1").Return(&model.Category{ ID: "category_id_1", Name: "Category", }, nil) category := &model.Category{ ID: "category_id_1", Name: "Category", UserID: "user_id_1", TeamID: "team_id_1", Type: "custom", } updatedCategory, err := th.App.UpdateCategory(category) assert.NotNil(t, updatedCategory) assert.NoError(t, err) }) t.Run("updating invalid category", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "custom", }, nil) category := &model.Category{ ID: "category_id_1", Name: "Name", UserID: "user_id", TeamID: "team_id", Type: "custom", } category.ID = "" createdCategory, err := th.App.UpdateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.ID = "category_id_1" category.Name = "" createdCategory, err = th.App.UpdateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.Name = "Name" category.UserID = "" // empty creator user id shouldn't be allowed createdCategory, err = th.App.UpdateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.UserID = "user_id" category.TeamID = "" // empty TeamID shouldn't be allowed createdCategory, err = th.App.UpdateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) category.Type = "invalid" // unknown type shouldn't be allowed createdCategory, err = th.App.UpdateCategory(category) assert.Nil(t, createdCategory) assert.Error(t, err) }) t.Run("trying to update someone else's category", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "custom", }, nil) category := &model.Category{ ID: "category_id_1", Name: "Category", UserID: "user_id_2", TeamID: "team_id_1", Type: "custom", } updatedCategory, err := th.App.UpdateCategory(category) assert.Nil(t, updatedCategory) assert.Error(t, err) }) t.Run("trying to update some other team's category", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "custom", }, nil) category := &model.Category{ ID: "category_id_1", Name: "Category", UserID: "user_id_1", TeamID: "team_id_2", Type: "custom", } updatedCategory, err := th.App.UpdateCategory(category) assert.Nil(t, updatedCategory) assert.Error(t, err) }) t.Run("should not be allowed to rename system category", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "system", }, nil).Times(1) th.Store.EXPECT().UpdateCategory(utils.Anything).Return(nil) th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "system", Collapsed: true, }, nil).Times(1) category := &model.Category{ ID: "category_id_1", Name: "Updated Name", UserID: "user_id_1", TeamID: "team_id_1", Type: "system", } updatedCategory, err := th.App.UpdateCategory(category) assert.NotNil(t, updatedCategory) assert.NoError(t, err) assert.Equal(t, "Category", updatedCategory.Name) }) t.Run("should be allowed to collapse and expand any category type", func(t *testing.T) { th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "system", Collapsed: false, }, nil).Times(1) th.Store.EXPECT().UpdateCategory(utils.Anything).Return(nil) th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "category_id_1", Name: "Category", TeamID: "team_id_1", UserID: "user_id_1", Type: "system", Collapsed: true, }, nil).Times(1) category := &model.Category{ ID: "category_id_1", Name: "Updated Name", UserID: "user_id_1", TeamID: "team_id_1", Type: "system", Collapsed: true, } updatedCategory, err := th.App.UpdateCategory(category) assert.NotNil(t, updatedCategory) assert.NoError(t, err) assert.Equal(t, "Category", updatedCategory.Name, "The name should have not been updated") assert.True(t, updatedCategory.Collapsed) }) } func TestDeleteCategory(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("base case", func(t *testing.T) { th.Store.EXPECT().GetCategory("category_id_1").Return(&model.Category{ ID: "category_id_1", DeleteAt: 0, UserID: "user_id_1", TeamID: "team_id_1", Type: "custom", }, nil) th.Store.EXPECT().DeleteCategory("category_id_1", "user_id_1", "team_id_1").Return(nil) th.Store.EXPECT().GetCategory("category_id_1").Return(&model.Category{ DeleteAt: 10000, }, nil) th.Store.EXPECT().GetUserCategoryBoards("user_id_1", "team_id_1").Return([]model.CategoryBoards{ { Category: model.Category{ ID: "category_id_default", DeleteAt: 0, UserID: "user_id_1", TeamID: "team_id_1", Type: "default", Name: "Boards", }, BoardIDs: []string{}, }, { Category: model.Category{ ID: "category_id_1", DeleteAt: 0, UserID: "user_id_1", TeamID: "team_id_1", Type: "custom", Name: "Category 1", }, BoardIDs: []string{}, }, }, nil) th.Store.EXPECT().AddUpdateCategoryBoard("user_id_1", utils.Anything).Return(nil) deletedCategory, err := th.App.DeleteCategory("category_id_1", "user_id_1", "team_id_1") assert.NotNil(t, deletedCategory) assert.NoError(t, err) }) t.Run("trying to delete already deleted category", func(t *testing.T) { th.Store.EXPECT().GetCategory("category_id_1").Return(&model.Category{ ID: "category_id_1", DeleteAt: 1000, UserID: "user_id_1", TeamID: "team_id_1", Type: "custom", }, nil) deletedCategory, err := th.App.DeleteCategory("category_id_1", "user_id_1", "team_id_1") assert.NotNil(t, deletedCategory) assert.NoError(t, err) }) t.Run("trying to delete system category", func(t *testing.T) { th.Store.EXPECT().GetCategory("category_id_1").Return(&model.Category{ ID: "category_id_1", DeleteAt: 0, UserID: "user_id_1", TeamID: "team_id_1", Type: "system", }, nil) deletedCategory, err := th.App.DeleteCategory("category_id_1", "user_id_1", "team_id_1") assert.Nil(t, deletedCategory) assert.Error(t, err) }) } func TestMoveBoardsToDefaultCategory(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("When default category already exists", func(t *testing.T) { th.Store.EXPECT().GetUserCategoryBoards("user_id", "team_id").Return([]model.CategoryBoards{ { Category: model.Category{ ID: "category_id_1", Name: "Boards", Type: "system", }, }, { Category: model.Category{ ID: "category_id_2", Name: "Custom Category 1", Type: "custom", }, }, }, nil) th.Store.EXPECT().AddUpdateCategoryBoard("user_id", utils.Anything).Return(nil) err := th.App.moveBoardsToDefaultCategory("user_id", "team_id", "category_id_2") assert.NoError(t, err) }) t.Run("When default category doesn't already exists", func(t *testing.T) { th.Store.EXPECT().GetUserCategoryBoards("user_id", "team_id").Return([]model.CategoryBoards{ { Category: model.Category{ ID: "category_id_2", Name: "Custom Category 1", Type: "custom", }, }, }, nil) th.Store.EXPECT().CreateCategory(utils.Anything).Return(nil) th.Store.EXPECT().GetCategory(utils.Anything).Return(&model.Category{ ID: "default_category_id", Name: "Boards", Type: "system", }, nil) th.Store.EXPECT().GetMembersForUser("user_id").Return([]*model.BoardMember{}, nil) th.Store.EXPECT().GetBoardsForUserAndTeam("user_id", "team_id", false).Return([]*model.Board{}, nil) th.Store.EXPECT().AddUpdateCategoryBoard("user_id", utils.Anything).Return(nil) err := th.App.moveBoardsToDefaultCategory("user_id", "team_id", "category_id_2") assert.NoError(t, err) }) } func TestReorderCategories(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("base case", func(t *testing.T) { th.Store.EXPECT().GetUserCategories("user_id", "team_id").Return([]model.Category{ { ID: "category_id_1", Name: "Boards", Type: "system", }, { ID: "category_id_2", Name: "Category 2", Type: "custom", }, { ID: "category_id_3", Name: "Category 3", Type: "custom", }, }, nil) th.Store.EXPECT().ReorderCategories("user_id", "team_id", []string{"category_id_2", "category_id_3", "category_id_1"}). Return([]string{"category_id_2", "category_id_3", "category_id_1"}, nil) newOrder, err := th.App.ReorderCategories("user_id", "team_id", []string{"category_id_2", "category_id_3", "category_id_1"}) assert.NoError(t, err) assert.Equal(t, 3, len(newOrder)) }) t.Run("not specifying all categories should fail", func(t *testing.T) { th.Store.EXPECT().GetUserCategories("user_id", "team_id").Return([]model.Category{ { ID: "category_id_1", Name: "Boards", Type: "system", }, { ID: "category_id_2", Name: "Category 2", Type: "custom", }, { ID: "category_id_3", Name: "Category 3", Type: "custom", }, }, nil) newOrder, err := th.App.ReorderCategories("user_id", "team_id", []string{"category_id_2", "category_id_3"}) assert.Error(t, err) assert.Nil(t, newOrder) }) } func TestVerifyNewCategoriesMatchExisting(t *testing.T) { th, tearDown := SetupTestHelper(t) defer tearDown() t.Run("base case", func(t *testing.T) { th.Store.EXPECT().GetUserCategories("user_id", "team_id").Return([]model.Category{ { ID: "category_id_1", Name: "Boards", Type: "system", }, { ID: "category_id_2", Name: "Category 2", Type: "custom", }, { ID: "category_id_3", Name: "Category 3", Type: "custom", }, }, nil) err := th.App.verifyNewCategoriesMatchExisting("user_id", "team_id", []string{ "category_id_2", "category_id_3", "category_id_1", }) assert.NoError(t, err) }) t.Run("different category counts", func(t *testing.T) { th.Store.EXPECT().GetUserCategories("user_id", "team_id").Return([]model.Category{ { ID: "category_id_1", Name: "Boards", Type: "system", }, { ID: "category_id_2", Name: "Category 2", Type: "custom", }, { ID: "category_id_3", Name: "Category 3", Type: "custom", }, }, nil) err := th.App.verifyNewCategoriesMatchExisting("user_id", "team_id", []string{ "category_id_2", "category_id_3", }) assert.Error(t, err) }) }