192 lines
6.8 KiB
Go
192 lines
6.8 KiB
Go
|
package app
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"testing"
|
||
|
|
||
|
"github.com/golang/mock/gomock"
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/mattermost/focalboard/server/model"
|
||
|
)
|
||
|
|
||
|
type contentOrderMatcher struct {
|
||
|
contentOrder []string
|
||
|
}
|
||
|
|
||
|
func NewContentOrderMatcher(contentOrder []string) contentOrderMatcher {
|
||
|
return contentOrderMatcher{contentOrder}
|
||
|
}
|
||
|
|
||
|
func (com contentOrderMatcher) Matches(x interface{}) bool {
|
||
|
patch, ok := x.(*model.BlockPatch)
|
||
|
if !ok {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
contentOrderData, ok := patch.UpdatedFields["contentOrder"]
|
||
|
if !ok {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
contentOrder, ok := contentOrderData.([]interface{})
|
||
|
if !ok {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if len(contentOrder) != len(com.contentOrder) {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
for i := range contentOrder {
|
||
|
if contentOrder[i] != com.contentOrder[i] {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (com contentOrderMatcher) String() string {
|
||
|
return fmt.Sprint(&model.BlockPatch{UpdatedFields: map[string]interface{}{"contentOrder": com.contentOrder}})
|
||
|
}
|
||
|
|
||
|
func TestMoveContentBlock(t *testing.T) {
|
||
|
th, tearDown := SetupTestHelper(t)
|
||
|
defer tearDown()
|
||
|
|
||
|
ttCases := []struct {
|
||
|
name string
|
||
|
srcBlock model.Block
|
||
|
dstBlock model.Block
|
||
|
parentBlock *model.Block
|
||
|
where string
|
||
|
userID string
|
||
|
mockPatch bool
|
||
|
mockPatchError error
|
||
|
errorMessage string
|
||
|
expectedContentOrder []string
|
||
|
}{
|
||
|
{
|
||
|
name: "not matching parents",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "other-test-card"},
|
||
|
parentBlock: nil,
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
errorMessage: "not matching parent test-card and other-test-card",
|
||
|
},
|
||
|
{
|
||
|
name: "parent not found",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "invalid-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "invalid-card"},
|
||
|
parentBlock: &model.Block{ID: "invalid-card"},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
errorMessage: "{test} not found",
|
||
|
},
|
||
|
{
|
||
|
name: "valid parent without content order",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card"},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
errorMessage: "source block test-1 not found",
|
||
|
},
|
||
|
{
|
||
|
name: "valid parent with content order but without test-1 in it",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-2"}}},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
errorMessage: "source block test-1 not found",
|
||
|
},
|
||
|
{
|
||
|
name: "valid parent with content order but without test-2 in it",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-1"}}},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
errorMessage: "destination block test-2 not found",
|
||
|
},
|
||
|
{
|
||
|
name: "valid request but fail on patchparent with content order",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-1", "test-2"}}},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
mockPatch: true,
|
||
|
mockPatchError: errors.New("test error"),
|
||
|
errorMessage: "test error",
|
||
|
},
|
||
|
{
|
||
|
name: "valid request with not real change",
|
||
|
srcBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-1", "test-2", "test-3"}}, BoardID: "test-board"},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
mockPatch: true,
|
||
|
errorMessage: "",
|
||
|
expectedContentOrder: []string{"test-1", "test-2", "test-3"},
|
||
|
},
|
||
|
{
|
||
|
name: "valid request changing order with before",
|
||
|
srcBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-1", "test-2", "test-3"}}, BoardID: "test-board"},
|
||
|
where: "before",
|
||
|
userID: "user-id",
|
||
|
mockPatch: true,
|
||
|
errorMessage: "",
|
||
|
expectedContentOrder: []string{"test-2", "test-1", "test-3"},
|
||
|
},
|
||
|
{
|
||
|
name: "valid request changing order with after",
|
||
|
srcBlock: model.Block{ID: "test-1", ParentID: "test-card"},
|
||
|
dstBlock: model.Block{ID: "test-2", ParentID: "test-card"},
|
||
|
parentBlock: &model.Block{ID: "test-card", Fields: map[string]interface{}{"contentOrder": []interface{}{"test-1", "test-2", "test-3"}}, BoardID: "test-board"},
|
||
|
where: "after",
|
||
|
userID: "user-id",
|
||
|
mockPatch: true,
|
||
|
errorMessage: "",
|
||
|
expectedContentOrder: []string{"test-2", "test-1", "test-3"},
|
||
|
},
|
||
|
}
|
||
|
|
||
|
for _, tc := range ttCases {
|
||
|
t.Run(tc.name, func(t *testing.T) {
|
||
|
if tc.parentBlock != nil {
|
||
|
if tc.parentBlock.ID == "invalid-card" {
|
||
|
th.Store.EXPECT().GetBlock(tc.srcBlock.ParentID).Return(nil, model.NewErrNotFound("test"))
|
||
|
} else {
|
||
|
th.Store.EXPECT().GetBlock(tc.parentBlock.ID).Return(tc.parentBlock, nil)
|
||
|
if tc.mockPatch {
|
||
|
if tc.mockPatchError != nil {
|
||
|
th.Store.EXPECT().GetBlock(tc.parentBlock.ID).Return(nil, tc.mockPatchError)
|
||
|
} else {
|
||
|
th.Store.EXPECT().GetBlock(tc.parentBlock.ID).Return(tc.parentBlock, nil)
|
||
|
th.Store.EXPECT().PatchBlock(tc.parentBlock.ID, NewContentOrderMatcher(tc.expectedContentOrder), gomock.Eq("user-id")).Return(nil)
|
||
|
th.Store.EXPECT().GetBlock(tc.parentBlock.ID).Return(tc.parentBlock, nil)
|
||
|
th.Store.EXPECT().GetBoard(tc.parentBlock.BoardID).Return(&model.Board{ID: "test-board"}, nil)
|
||
|
// this call comes from the WS server notification
|
||
|
th.Store.EXPECT().GetMembersForBoard(gomock.Any()).Times(1)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
err := th.App.MoveContentBlock(&tc.srcBlock, &tc.dstBlock, tc.where, tc.userID)
|
||
|
if tc.errorMessage == "" {
|
||
|
require.NoError(t, err)
|
||
|
} else {
|
||
|
require.EqualError(t, err, tc.errorMessage)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
}
|