focalboard/server/app/boards_test.go
Scott Bishel af2727085d
Fix template websocket (#3747)
* fix websockets with templates

* add more unit tests

* add synthetic, update tests

* Update mattermost-plugin/server/manifest.go

* clean up lint, reduce cyclomatic complexity

* update tests that call patchBoard with patch.Type set

* cleanup messages

* cleanup code more readable

* fixes from code review

* fix null check

* remove log lines
2022-09-04 16:51:31 -06:00

366 lines
10 KiB
Go

package app
import (
"testing"
"github.com/mattermost/focalboard/server/model"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestAddMemberToBoard(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
t.Run("base case", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_1"
boardMember := &model.BoardMember{
BoardID: boardID,
UserID: userID,
SchemeEditor: true,
}
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
TeamID: "team_id_1",
}, nil)
th.Store.EXPECT().GetMemberForBoard(boardID, userID).Return(nil, nil)
th.Store.EXPECT().SaveMember(mock.MatchedBy(func(i interface{}) bool {
p := i.(*model.BoardMember)
return p.BoardID == boardID && p.UserID == userID
})).Return(&model.BoardMember{
BoardID: boardID,
}, nil)
// for WS change broadcast
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil)
addedBoardMember, err := th.App.AddMemberToBoard(boardMember)
require.NoError(t, err)
require.Equal(t, boardID, addedBoardMember.BoardID)
})
t.Run("return existing non-synthetic membership if any", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_1"
boardMember := &model.BoardMember{
BoardID: boardID,
UserID: userID,
SchemeEditor: true,
}
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
TeamID: "team_id_1",
}, nil)
th.Store.EXPECT().GetMemberForBoard(boardID, userID).Return(&model.BoardMember{
UserID: userID,
BoardID: boardID,
Synthetic: false,
}, nil)
addedBoardMember, err := th.App.AddMemberToBoard(boardMember)
require.NoError(t, err)
require.Equal(t, boardID, addedBoardMember.BoardID)
})
t.Run("should convert synthetic membership into natural membership", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_1"
boardMember := &model.BoardMember{
BoardID: boardID,
UserID: userID,
SchemeEditor: true,
}
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
TeamID: "team_id_1",
}, nil)
th.Store.EXPECT().GetMemberForBoard(boardID, userID).Return(&model.BoardMember{
UserID: userID,
BoardID: boardID,
Synthetic: true,
}, nil)
th.Store.EXPECT().SaveMember(mock.MatchedBy(func(i interface{}) bool {
p := i.(*model.BoardMember)
return p.BoardID == boardID && p.UserID == userID
})).Return(&model.BoardMember{
UserID: userID,
BoardID: boardID,
Synthetic: false,
}, nil)
// for WS change broadcast
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil)
addedBoardMember, err := th.App.AddMemberToBoard(boardMember)
require.NoError(t, err)
require.Equal(t, boardID, addedBoardMember.BoardID)
})
}
func TestPatchBoard(t *testing.T) {
th, tearDown := SetupTestHelper(t)
defer tearDown()
t.Run("base case, title patch", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_1"
const teamID = "team_id_1"
patchTitle := "Patched Title"
patch := &model.BoardPatch{
Title: &patchTitle,
}
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
Title: patchTitle,
},
nil)
// for WS BroadcastBoardChange
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil).Times(1)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, patchTitle, patchedBoard.Title)
})
t.Run("patch type open, no users", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypeOpen
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 2 times
// - for WS BroadcastBoardChange
// - for AddTeamMembers check
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil).Times(2)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
t.Run("patch type private, no users", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypePrivate
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 2 times
// - for WS BroadcastBoardChange
// - for AddTeamMembers check
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil).Times(2)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
t.Run("patch type open, single user", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypeOpen
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{{ID: userID}}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 3 times
// for WS BroadcastBoardChange
// for AddTeamMembers check
// for WS BroadcastMemberChange
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil).Times(3)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
t.Run("patch type private, single user", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypePrivate
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{{ID: userID}}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 3 times
// for WS BroadcastBoardChange
// for AddTeamMembers check
// for WS BroadcastMemberChange
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{}, nil).Times(3)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
t.Run("patch type open, user with member", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypeOpen
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{{ID: userID}}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 2 times
// for WS BroadcastBoardChange
// for AddTeamMembers check
// We are returning the user as a direct Board Member, so BroadcastMemberDelete won't be called
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{{BoardID: boardID, UserID: userID, SchemeEditor: true}}, nil).Times(2)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
t.Run("patch type private, user with member", func(t *testing.T) {
const boardID = "board_id_1"
const userID = "user_id_2"
const teamID = "team_id_1"
patchType := model.BoardTypePrivate
patch := &model.BoardPatch{
Type: &patchType,
}
// Type not nil, will cause board to be reteived
// to check isTemplate
th.Store.EXPECT().GetBoard(boardID).Return(&model.Board{
ID: boardID,
TeamID: teamID,
IsTemplate: true,
}, nil)
// Type not null will retrieve team members
th.Store.EXPECT().GetUsersByTeam(teamID, "").Return([]*model.User{{ID: userID}}, nil)
th.Store.EXPECT().PatchBoard(boardID, patch, userID).Return(
&model.Board{
ID: boardID,
TeamID: teamID,
},
nil)
// Should call GetMembersForBoard 2 times
// for WS BroadcastBoardChange
// for AddTeamMembers check
// We are returning the user as a direct Board Member, so BroadcastMemberDelete won't be called
th.Store.EXPECT().GetMembersForBoard(boardID).Return([]*model.BoardMember{{BoardID: boardID, UserID: userID, SchemeEditor: true}}, nil).Times(2)
patchedBoard, err := th.App.PatchBoard(patch, boardID, userID)
require.NoError(t, err)
require.Equal(t, boardID, patchedBoard.ID)
})
}