mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* Moving mlog to corelibs * Regenerating app layers * Fix golangci-lint problem * Fixing golangci-lint errors * Renaming from corelibs to shared * Renaming from corelibs to shared * Fixing import * Fixing merge problems * Fixing build
1973 lines
57 KiB
Go
1973 lines
57 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
|
|
"github.com/mattermost/mattermost-server/v5/services/imageproxy"
|
|
"github.com/mattermost/mattermost-server/v5/services/searchengine/mocks"
|
|
"github.com/mattermost/mattermost-server/v5/shared/mlog"
|
|
"github.com/mattermost/mattermost-server/v5/store/storetest"
|
|
storemocks "github.com/mattermost/mattermost-server/v5/store/storetest/mocks"
|
|
"github.com/mattermost/mattermost-server/v5/testlib"
|
|
)
|
|
|
|
func TestCreatePostDeduplicate(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
t.Run("duplicate create post is idempotent", func(t *testing.T) {
|
|
pendingPostId := model.NewId()
|
|
post, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, "message", post.Message)
|
|
|
|
duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, post.Id, duplicatePost.Id, "should have returned previously created post id")
|
|
require.Equal(t, "message", duplicatePost.Message)
|
|
})
|
|
|
|
t.Run("post rejected by plugin leaves cache ready for non-deduplicated try", func(t *testing.T) {
|
|
setupPluginApiTest(t, `
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
allow bool
|
|
}
|
|
|
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
|
if !p.allow {
|
|
p.allow = true
|
|
return nil, "rejected"
|
|
}
|
|
|
|
return nil, ""
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`, `{"id": "testrejectfirstpost", "backend": {"executable": "backend.exe"}}`, "testrejectfirstpost", th.App)
|
|
|
|
pendingPostId := model.NewId()
|
|
post, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, "Post rejected by plugin. rejected", err.Id)
|
|
require.Nil(t, post)
|
|
|
|
duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, "message", duplicatePost.Message)
|
|
})
|
|
|
|
t.Run("slow posting after cache entry blocks duplicate request", func(t *testing.T) {
|
|
setupPluginApiTest(t, `
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
"time"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
instant bool
|
|
}
|
|
|
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
|
if !p.instant {
|
|
p.instant = true
|
|
time.Sleep(3 * time.Second)
|
|
}
|
|
|
|
return nil, ""
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`, `{"id": "testdelayfirstpost", "backend": {"executable": "backend.exe"}}`, "testdelayfirstpost", th.App)
|
|
|
|
var post *model.Post
|
|
pendingPostId := model.NewId()
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
// Launch a goroutine to make the first CreatePost call that will get delayed
|
|
// by the plugin above.
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
var appErr *model.AppError
|
|
post, appErr = th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "plugin delayed",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, appErr)
|
|
require.Equal(t, post.Message, "plugin delayed")
|
|
}()
|
|
|
|
// Give the goroutine above a chance to start and get delayed by the plugin.
|
|
time.Sleep(2 * time.Second)
|
|
|
|
// Try creating a duplicate post
|
|
duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "plugin delayed",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, "api.post.deduplicate_create_post.pending", err.Id)
|
|
require.Nil(t, duplicatePost)
|
|
|
|
// Wait for the first CreatePost to finish to ensure assertions are made.
|
|
wg.Wait()
|
|
})
|
|
|
|
t.Run("duplicate create post after cache expires is not idempotent", func(t *testing.T) {
|
|
pendingPostId := model.NewId()
|
|
post, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, err)
|
|
require.Equal(t, "message", post.Message)
|
|
|
|
time.Sleep(PendingPostIDsCacheTTL)
|
|
|
|
duplicatePost, err := th.App.CreatePostAsUser(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "message",
|
|
PendingPostId: pendingPostId,
|
|
}, "", true)
|
|
require.Nil(t, err)
|
|
require.NotEqual(t, post.Id, duplicatePost.Id, "should have created new post id")
|
|
require.Equal(t, "message", duplicatePost.Message)
|
|
})
|
|
}
|
|
|
|
func TestAttachFilesToPost(t *testing.T) {
|
|
t.Run("should attach files", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
info1, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
|
|
CreatorId: th.BasicUser.Id,
|
|
Path: "path.txt",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
info2, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
|
|
CreatorId: th.BasicUser.Id,
|
|
Path: "path.txt",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
post := th.BasicPost
|
|
post.FileIds = []string{info1.Id, info2.Id}
|
|
|
|
appErr := th.App.attachFilesToPost(post)
|
|
assert.Nil(t, appErr)
|
|
|
|
infos, appErr := th.App.GetFileInfosForPost(post.Id, false)
|
|
assert.Nil(t, appErr)
|
|
assert.Len(t, infos, 2)
|
|
})
|
|
|
|
t.Run("should update File.PostIds after failing to add files", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
info1, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
|
|
CreatorId: th.BasicUser.Id,
|
|
Path: "path.txt",
|
|
PostId: model.NewId(),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
info2, err := th.App.Srv().Store.FileInfo().Save(&model.FileInfo{
|
|
CreatorId: th.BasicUser.Id,
|
|
Path: "path.txt",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
post := th.BasicPost
|
|
post.FileIds = []string{info1.Id, info2.Id}
|
|
|
|
appErr := th.App.attachFilesToPost(post)
|
|
assert.Nil(t, appErr)
|
|
|
|
infos, appErr := th.App.GetFileInfosForPost(post.Id, false)
|
|
assert.Nil(t, appErr)
|
|
assert.Len(t, infos, 1)
|
|
assert.Equal(t, info2.Id, infos[0].Id)
|
|
|
|
updated, appErr := th.App.GetSinglePost(post.Id)
|
|
require.Nil(t, appErr)
|
|
assert.Len(t, updated.FileIds, 1)
|
|
assert.Contains(t, updated.FileIds, info2.Id)
|
|
})
|
|
}
|
|
|
|
func TestUpdatePostEditAt(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
post := &model.Post{}
|
|
post = th.BasicPost.Clone()
|
|
|
|
post.IsPinned = true
|
|
saved, err := th.App.UpdatePost(post, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, saved.EditAt, post.EditAt, "shouldn't have updated post.EditAt when pinning post")
|
|
post = saved.Clone()
|
|
|
|
time.Sleep(time.Millisecond * 100)
|
|
|
|
post.Message = model.NewId()
|
|
saved, err = th.App.UpdatePost(post, true)
|
|
require.Nil(t, err)
|
|
assert.NotEqual(t, saved.EditAt, post.EditAt, "should have updated post.EditAt when updating post message")
|
|
|
|
time.Sleep(time.Millisecond * 200)
|
|
}
|
|
|
|
func TestUpdatePostTimeLimit(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
post := &model.Post{}
|
|
post = th.BasicPost.Clone()
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostEditTimeLimit = -1
|
|
})
|
|
_, err := th.App.UpdatePost(post, true)
|
|
require.Nil(t, err)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostEditTimeLimit = 1000000000
|
|
})
|
|
post.Message = model.NewId()
|
|
|
|
_, err = th.App.UpdatePost(post, true)
|
|
require.Nil(t, err, "should allow you to edit the post")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostEditTimeLimit = 1
|
|
})
|
|
post.Message = model.NewId()
|
|
_, err = th.App.UpdatePost(post, true)
|
|
require.NotNil(t, err, "should fail on update old post")
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.PostEditTimeLimit = -1
|
|
})
|
|
}
|
|
|
|
func TestUpdatePostInArchivedChannel(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
archivedChannel := th.CreateChannel(th.BasicTeam)
|
|
post := th.CreatePost(archivedChannel)
|
|
th.App.DeleteChannel(archivedChannel, "")
|
|
|
|
_, err := th.App.UpdatePost(post, true)
|
|
require.NotNil(t, err)
|
|
require.Equal(t, "api.post.update_post.can_not_update_post_in_deleted.error", err.Id)
|
|
}
|
|
|
|
func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
|
|
// This test ensures that when replying to a root post made by a user who has since left the channel, the reply
|
|
// post completes successfully. This is a regression test for PLT-6523.
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
channel := th.BasicChannel
|
|
userInChannel := th.BasicUser2
|
|
userNotInChannel := th.BasicUser
|
|
rootPost := th.BasicPost
|
|
|
|
_, err := th.App.AddUserToChannel(userInChannel, channel)
|
|
require.Nil(t, err)
|
|
|
|
err = th.App.RemoveUserFromChannel(userNotInChannel.Id, "", channel)
|
|
require.Nil(t, err)
|
|
replyPost := model.Post{
|
|
Message: "asd",
|
|
ChannelId: channel.Id,
|
|
RootId: rootPost.Id,
|
|
ParentId: rootPost.Id,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: userInChannel.Id,
|
|
CreateAt: 0,
|
|
}
|
|
|
|
_, err = th.App.CreatePostAsUser(&replyPost, "", true)
|
|
require.Nil(t, err)
|
|
}
|
|
|
|
func TestPostAttachPostToChildPost(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
channel := th.BasicChannel
|
|
user := th.BasicUser
|
|
rootPost := th.BasicPost
|
|
|
|
replyPost1 := model.Post{
|
|
Message: "reply one",
|
|
ChannelId: channel.Id,
|
|
RootId: rootPost.Id,
|
|
ParentId: rootPost.Id,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: user.Id,
|
|
CreateAt: 0,
|
|
}
|
|
|
|
res1, err := th.App.CreatePostAsUser(&replyPost1, "", true)
|
|
require.Nil(t, err)
|
|
|
|
replyPost2 := model.Post{
|
|
Message: "reply two",
|
|
ChannelId: channel.Id,
|
|
RootId: res1.Id,
|
|
ParentId: res1.Id,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: user.Id,
|
|
CreateAt: 0,
|
|
}
|
|
|
|
_, err = th.App.CreatePostAsUser(&replyPost2, "", true)
|
|
assert.Equalf(t, err.StatusCode, http.StatusBadRequest, "Expected BadRequest error, got %v", err)
|
|
|
|
replyPost3 := model.Post{
|
|
Message: "reply three",
|
|
ChannelId: channel.Id,
|
|
RootId: rootPost.Id,
|
|
ParentId: rootPost.Id,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: user.Id,
|
|
CreateAt: 0,
|
|
}
|
|
|
|
_, err = th.App.CreatePostAsUser(&replyPost3, "", true)
|
|
assert.Nil(t, err)
|
|
}
|
|
|
|
func TestPostChannelMentions(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
channel := th.BasicChannel
|
|
user := th.BasicUser
|
|
|
|
channelToMention, err := th.App.CreateChannel(&model.Channel{
|
|
DisplayName: "Mention Test",
|
|
Name: "mention-test",
|
|
Type: model.CHANNEL_OPEN,
|
|
TeamId: th.BasicTeam.Id,
|
|
}, false)
|
|
require.Nil(t, err)
|
|
defer th.App.PermanentDeleteChannel(channelToMention)
|
|
|
|
_, err = th.App.AddUserToChannel(user, channel)
|
|
require.Nil(t, err)
|
|
|
|
post := &model.Post{
|
|
Message: fmt.Sprintf("hello, ~%v!", channelToMention.Name),
|
|
ChannelId: channel.Id,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: user.Id,
|
|
CreateAt: 0,
|
|
}
|
|
|
|
result, err := th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, map[string]interface{}{
|
|
"mention-test": map[string]interface{}{
|
|
"display_name": "Mention Test",
|
|
"team_name": th.BasicTeam.Name,
|
|
},
|
|
}, result.GetProp("channel_mentions"))
|
|
|
|
post.Message = fmt.Sprintf("goodbye, ~%v!", channelToMention.Name)
|
|
result, err = th.App.UpdatePost(post, false)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, map[string]interface{}{
|
|
"mention-test": map[string]interface{}{
|
|
"display_name": "Mention Test",
|
|
"team_name": th.BasicTeam.Name,
|
|
},
|
|
}, result.GetProp("channel_mentions"))
|
|
}
|
|
|
|
func TestImageProxy(t *testing.T) {
|
|
th := SetupWithStoreMock(t)
|
|
defer th.TearDown()
|
|
|
|
mockStore := th.App.Srv().Store.(*storemocks.Store)
|
|
mockUserStore := storemocks.UserStore{}
|
|
mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
|
|
mockPostStore := storemocks.PostStore{}
|
|
mockPostStore.On("GetMaxPostSize").Return(65535, nil)
|
|
mockSystemStore := storemocks.SystemStore{}
|
|
mockSystemStore.On("GetByName", "UpgradedFromTE").Return(&model.System{Name: "UpgradedFromTE", Value: "false"}, nil)
|
|
mockSystemStore.On("GetByName", "InstallationDate").Return(&model.System{Name: "InstallationDate", Value: "10"}, nil)
|
|
mockSystemStore.On("GetByName", "FirstServerRunTimestamp").Return(&model.System{Name: "FirstServerRunTimestamp", Value: "10"}, nil)
|
|
|
|
mockStore.On("User").Return(&mockUserStore)
|
|
mockStore.On("Post").Return(&mockPostStore)
|
|
mockStore.On("System").Return(&mockSystemStore)
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
|
|
})
|
|
|
|
th.Server.ImageProxy = imageproxy.MakeImageProxy(th.Server, th.Server.HTTPService, th.Server.Log)
|
|
|
|
for name, tc := range map[string]struct {
|
|
ProxyType string
|
|
ProxyURL string
|
|
ProxyOptions string
|
|
ImageURL string
|
|
ProxiedImageURL string
|
|
ProxiedRemovedImageURL string
|
|
}{
|
|
"atmos/camo": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
|
|
ProxyURL: "https://127.0.0.1",
|
|
ProxyOptions: "foo",
|
|
ImageURL: "http://mydomain.com/myimage",
|
|
ProxiedRemovedImageURL: "http://mydomain.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage",
|
|
},
|
|
"atmos/camo_SameSite": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
|
|
ProxyURL: "https://127.0.0.1",
|
|
ProxyOptions: "foo",
|
|
ImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedRemovedImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/myimage",
|
|
},
|
|
"atmos/camo_PathOnly": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
|
|
ProxyURL: "https://127.0.0.1",
|
|
ProxyOptions: "foo",
|
|
ImageURL: "/myimage",
|
|
ProxiedRemovedImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/myimage",
|
|
},
|
|
"atmos/camo_EmptyImageURL": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO,
|
|
ProxyURL: "https://127.0.0.1",
|
|
ProxyOptions: "foo",
|
|
ImageURL: "",
|
|
ProxiedRemovedImageURL: "",
|
|
ProxiedImageURL: "",
|
|
},
|
|
"local": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_LOCAL,
|
|
ImageURL: "http://mydomain.com/myimage",
|
|
ProxiedRemovedImageURL: "http://mydomain.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage",
|
|
},
|
|
"local_SameSite": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_LOCAL,
|
|
ImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedRemovedImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/myimage",
|
|
},
|
|
"local_PathOnly": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_LOCAL,
|
|
ImageURL: "/myimage",
|
|
ProxiedRemovedImageURL: "http://mymattermost.com/myimage",
|
|
ProxiedImageURL: "http://mymattermost.com/myimage",
|
|
},
|
|
"local_EmptyImageURL": {
|
|
ProxyType: model.IMAGE_PROXY_TYPE_LOCAL,
|
|
ImageURL: "",
|
|
ProxiedRemovedImageURL: "",
|
|
ProxiedImageURL: "",
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
cfg.ImageProxySettings.Enable = model.NewBool(true)
|
|
cfg.ImageProxySettings.ImageProxyType = model.NewString(tc.ProxyType)
|
|
cfg.ImageProxySettings.RemoteImageProxyOptions = model.NewString(tc.ProxyOptions)
|
|
cfg.ImageProxySettings.RemoteImageProxyURL = model.NewString(tc.ProxyURL)
|
|
})
|
|
|
|
post := &model.Post{
|
|
Id: model.NewId(),
|
|
Message: "",
|
|
}
|
|
|
|
list := model.NewPostList()
|
|
list.Posts[post.Id] = post
|
|
|
|
assert.Equal(t, "", th.App.PostWithProxyAddedToImageURLs(post).Message)
|
|
|
|
assert.Equal(t, "", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
|
|
post.Message = ""
|
|
assert.Equal(t, "", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
|
|
|
|
if tc.ImageURL != "" {
|
|
post.Message = ""
|
|
assert.Equal(t, "", th.App.PostWithProxyAddedToImageURLs(post).Message)
|
|
assert.Equal(t, "", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
|
|
post.Message = ""
|
|
assert.Equal(t, "", th.App.PostWithProxyRemovedFromImageURLs(post).Message)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMaxPostSize(t *testing.T) {
|
|
t.Skip("TODO: fix flaky test")
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
Description string
|
|
StoreMaxPostSize int
|
|
ExpectedMaxPostSize int
|
|
}{
|
|
{
|
|
"Max post size less than model.model.POST_MESSAGE_MAX_RUNES_V1 ",
|
|
0,
|
|
model.POST_MESSAGE_MAX_RUNES_V1,
|
|
},
|
|
{
|
|
"4000 rune limit",
|
|
4000,
|
|
4000,
|
|
},
|
|
{
|
|
"16383 rune limit",
|
|
16383,
|
|
16383,
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase := testCase
|
|
t.Run(testCase.Description, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
mockStore := &storetest.Store{}
|
|
defer mockStore.AssertExpectations(t)
|
|
|
|
mockStore.PostStore.On("GetMaxPostSize").Return(testCase.StoreMaxPostSize)
|
|
|
|
app := App{
|
|
srv: &Server{
|
|
Store: mockStore,
|
|
},
|
|
}
|
|
|
|
assert.Equal(t, testCase.ExpectedMaxPostSize, app.MaxPostSize())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeletePostWithFileAttachments(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
// Create a post with a file attachment.
|
|
teamID := th.BasicTeam.Id
|
|
channelID := th.BasicChannel.Id
|
|
userID := th.BasicUser.Id
|
|
filename := "test"
|
|
data := []byte("abcd")
|
|
|
|
info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamID, channelID, userID, filename, data)
|
|
require.Nil(t, err)
|
|
defer func() {
|
|
th.App.Srv().Store.FileInfo().PermanentDelete(info1.Id)
|
|
th.App.RemoveFile(info1.Path)
|
|
}()
|
|
|
|
post := &model.Post{
|
|
Message: "asd",
|
|
ChannelId: channelID,
|
|
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
|
|
UserId: userID,
|
|
CreateAt: 0,
|
|
FileIds: []string{info1.Id},
|
|
}
|
|
|
|
post, err = th.App.CreatePost(post, th.BasicChannel, false, true)
|
|
assert.Nil(t, err)
|
|
|
|
// Delete the post.
|
|
post, err = th.App.DeletePost(post.Id, userID)
|
|
assert.Nil(t, err)
|
|
|
|
// Wait for the cleanup routine to finish.
|
|
time.Sleep(time.Millisecond * 100)
|
|
|
|
// Check that the file can no longer be reached.
|
|
_, err = th.App.GetFileInfo(info1.Id)
|
|
assert.NotNil(t, err)
|
|
}
|
|
|
|
func TestDeletePostInArchivedChannel(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
archivedChannel := th.CreateChannel(th.BasicTeam)
|
|
post := th.CreatePost(archivedChannel)
|
|
th.App.DeleteChannel(archivedChannel, "")
|
|
|
|
_, err := th.App.DeletePost(post.Id, "")
|
|
require.NotNil(t, err)
|
|
require.Equal(t, "api.post.delete_post.can_not_delete_post_in_deleted.error", err.Id)
|
|
}
|
|
|
|
func TestCreatePost(t *testing.T) {
|
|
t.Run("call PreparePostForClient before returning", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
|
|
*cfg.ImageProxySettings.Enable = true
|
|
*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
|
|
*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
|
|
*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
|
|
})
|
|
|
|
th.Server.ImageProxy = imageproxy.MakeImageProxy(th.Server, th.Server.HTTPService, th.Server.Log)
|
|
|
|
imageURL := "http://mydomain.com/myimage"
|
|
proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
|
|
rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, "", rpost.Message)
|
|
})
|
|
|
|
t.Run("Sets prop MENTION_HIGHLIGHT_DISABLED when it should", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
th.AddUserToChannel(th.BasicUser, th.BasicChannel)
|
|
|
|
t.Run("Does not set prop when user has USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
|
postWithNoMention := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "This post does not have mentions",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
|
|
postWithMention := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "This post has @here mention @all",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
})
|
|
|
|
t.Run("Sets prop when post has mentions and user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
|
th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
|
|
|
|
postWithNoMention := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "This post does not have mentions",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
|
|
postWithMention := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "This post has @here mention @all",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
|
|
|
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestPatchPost(t *testing.T) {
|
|
t.Run("call PreparePostForClient before returning", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
|
|
*cfg.ImageProxySettings.Enable = true
|
|
*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
|
|
*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
|
|
*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
|
|
})
|
|
|
|
th.Server.ImageProxy = imageproxy.MakeImageProxy(th.Server, th.Server.HTTPService, th.Server.Log)
|
|
|
|
imageURL := "http://mydomain.com/myimage"
|
|
proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
|
|
rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.NotEqual(t, "", rpost.Message)
|
|
|
|
patch := &model.PostPatch{
|
|
Message: model.NewString(""),
|
|
}
|
|
|
|
rpost, err = th.App.PatchPost(rpost.Id, patch)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, "", rpost.Message)
|
|
})
|
|
|
|
t.Run("Sets Prop MENTION_HIGHLIGHT_DISABLED when it should", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
th.AddUserToChannel(th.BasicUser, th.BasicChannel)
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "This post does not have mentions",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
|
|
rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
t.Run("Does not set prop when user has USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
|
patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch has no channel mention")}
|
|
|
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
|
|
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
|
|
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
})
|
|
|
|
t.Run("Sets prop when user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
|
th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
|
th.RemovePermissionFromRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
|
|
|
|
patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch still does not have a mention")}
|
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
|
|
|
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
|
|
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
|
|
|
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_ADMIN_ROLE_ID)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestCreatePostAsUser(t *testing.T) {
|
|
t.Run("marks channel as viewed for regular user", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
|
|
channelMemberBefore, err := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
_, appErr := th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, appErr)
|
|
|
|
channelMemberAfter, err := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
require.Greater(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
|
|
})
|
|
|
|
t.Run("does not mark channel as viewed for webhook from user", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
post.AddProp("from_webhook", "true")
|
|
|
|
channelMemberBefore, err := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
_, appErr := th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, appErr)
|
|
|
|
channelMemberAfter, err := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
|
|
})
|
|
|
|
t.Run("does not mark channel as viewed for bot user in channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
bot := th.CreateBot()
|
|
|
|
botUser, appErr := th.App.GetUser(bot.UserId)
|
|
require.Nil(t, appErr)
|
|
|
|
th.LinkUserToTeam(botUser, th.BasicTeam)
|
|
th.AddUserToChannel(botUser, th.BasicChannel)
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test",
|
|
UserId: bot.UserId,
|
|
}
|
|
|
|
channelMemberBefore, nErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, nErr)
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
_, appErr = th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, appErr)
|
|
|
|
channelMemberAfter, nErr := th.App.Srv().Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)
|
|
require.NoError(t, nErr)
|
|
|
|
require.Equal(t, channelMemberAfter.LastViewedAt, channelMemberBefore.LastViewedAt)
|
|
})
|
|
|
|
t.Run("logs warning for user not in channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user := th.CreateUser()
|
|
th.LinkUserToTeam(user, th.BasicTeam)
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test",
|
|
UserId: user.Id,
|
|
}
|
|
|
|
_, appErr := th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, appErr)
|
|
|
|
testlib.AssertLog(t, th.LogBuffer, mlog.LevelWarn, "Failed to get membership")
|
|
})
|
|
|
|
t.Run("does not log warning for bot user not in channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
bot := th.CreateBot()
|
|
|
|
botUser, appErr := th.App.GetUser(bot.UserId)
|
|
require.Nil(t, appErr)
|
|
|
|
th.LinkUserToTeam(botUser, th.BasicTeam)
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "test",
|
|
UserId: bot.UserId,
|
|
}
|
|
|
|
_, appErr = th.App.CreatePostAsUser(post, "", true)
|
|
require.Nil(t, appErr)
|
|
|
|
testlib.AssertNoLog(t, th.LogBuffer, mlog.LevelWarn, "Failed to get membership")
|
|
})
|
|
}
|
|
|
|
func TestPatchPostInArchivedChannel(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
archivedChannel := th.CreateChannel(th.BasicTeam)
|
|
post := th.CreatePost(archivedChannel)
|
|
th.App.DeleteChannel(archivedChannel, "")
|
|
|
|
_, err := th.App.PatchPost(post.Id, &model.PostPatch{IsPinned: model.NewBool(true)})
|
|
require.NotNil(t, err)
|
|
require.Equal(t, "api.post.patch_post.can_not_update_post_in_deleted.error", err.Id)
|
|
}
|
|
|
|
func TestUpdatePost(t *testing.T) {
|
|
t.Run("call PreparePostForClient before returning", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.SiteURL = "http://mymattermost.com"
|
|
*cfg.ImageProxySettings.Enable = true
|
|
*cfg.ImageProxySettings.ImageProxyType = "atmos/camo"
|
|
*cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1"
|
|
*cfg.ImageProxySettings.RemoteImageProxyOptions = "foo"
|
|
})
|
|
|
|
th.Server.ImageProxy = imageproxy.MakeImageProxy(th.Server, th.Server.HTTPService, th.Server.Log)
|
|
|
|
imageURL := "http://mydomain.com/myimage"
|
|
proxiedImageURL := "http://mymattermost.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage"
|
|
|
|
post := &model.Post{
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: "",
|
|
UserId: th.BasicUser.Id,
|
|
}
|
|
|
|
rpost, err := th.App.CreatePost(post, th.BasicChannel, false, true)
|
|
require.Nil(t, err)
|
|
assert.NotEqual(t, "", rpost.Message)
|
|
|
|
post.Id = rpost.Id
|
|
post.Message = ""
|
|
|
|
rpost, err = th.App.UpdatePost(post, false)
|
|
require.Nil(t, err)
|
|
assert.Equal(t, "", rpost.Message)
|
|
})
|
|
}
|
|
|
|
func TestSearchPostsInTeamForUser(t *testing.T) {
|
|
perPage := 5
|
|
searchTerm := "searchTerm"
|
|
|
|
setup := func(t *testing.T, enableElasticsearch bool) (*TestHelper, []*model.Post) {
|
|
th := Setup(t).InitBasic()
|
|
|
|
posts := make([]*model.Post, 7)
|
|
for i := 0; i < cap(posts); i++ {
|
|
post, err := th.App.CreatePost(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: th.BasicChannel.Id,
|
|
Message: searchTerm,
|
|
}, th.BasicChannel, false, true)
|
|
|
|
require.Nil(t, err)
|
|
|
|
posts[i] = post
|
|
}
|
|
|
|
if enableElasticsearch {
|
|
th.App.Srv().SetLicense(model.NewTestLicense("elastic_search"))
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ElasticsearchSettings.EnableIndexing = true
|
|
*cfg.ElasticsearchSettings.EnableSearching = true
|
|
})
|
|
} else {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ElasticsearchSettings.EnableSearching = false
|
|
})
|
|
}
|
|
|
|
return th, posts
|
|
}
|
|
|
|
t.Run("should return everything as first page of posts from database", func(t *testing.T) {
|
|
th, posts := setup(t, false)
|
|
defer th.TearDown()
|
|
|
|
page := 0
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, []string{
|
|
posts[6].Id,
|
|
posts[5].Id,
|
|
posts[4].Id,
|
|
posts[3].Id,
|
|
posts[2].Id,
|
|
posts[1].Id,
|
|
posts[0].Id,
|
|
}, results.Order)
|
|
})
|
|
|
|
t.Run("should not return later pages of posts from database", func(t *testing.T) {
|
|
th, _ := setup(t, false)
|
|
defer th.TearDown()
|
|
|
|
page := 1
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, []string{}, results.Order)
|
|
})
|
|
|
|
t.Run("should return first page of posts from ElasticSearch", func(t *testing.T) {
|
|
th, posts := setup(t, true)
|
|
defer th.TearDown()
|
|
|
|
page := 0
|
|
resultsPage := []string{
|
|
posts[6].Id,
|
|
posts[5].Id,
|
|
posts[4].Id,
|
|
posts[3].Id,
|
|
posts[2].Id,
|
|
}
|
|
|
|
es := &mocks.SearchEngineInterface{}
|
|
es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(resultsPage, nil, nil)
|
|
es.On("GetName").Return("mock")
|
|
es.On("Start").Return(nil).Maybe()
|
|
es.On("IsActive").Return(true)
|
|
es.On("IsSearchEnabled").Return(true)
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = es
|
|
defer func() {
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = nil
|
|
}()
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, resultsPage, results.Order)
|
|
es.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("should return later pages of posts from ElasticSearch", func(t *testing.T) {
|
|
th, posts := setup(t, true)
|
|
defer th.TearDown()
|
|
|
|
page := 1
|
|
resultsPage := []string{
|
|
posts[1].Id,
|
|
posts[0].Id,
|
|
}
|
|
|
|
es := &mocks.SearchEngineInterface{}
|
|
es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(resultsPage, nil, nil)
|
|
es.On("GetName").Return("mock")
|
|
es.On("Start").Return(nil).Maybe()
|
|
es.On("IsActive").Return(true)
|
|
es.On("IsSearchEnabled").Return(true)
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = es
|
|
defer func() {
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = nil
|
|
}()
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, resultsPage, results.Order)
|
|
es.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("should fall back to database if ElasticSearch fails on first page", func(t *testing.T) {
|
|
th, posts := setup(t, true)
|
|
defer th.TearDown()
|
|
|
|
page := 0
|
|
|
|
es := &mocks.SearchEngineInterface{}
|
|
es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(nil, nil, &model.AppError{})
|
|
es.On("GetName").Return("mock")
|
|
es.On("Start").Return(nil).Maybe()
|
|
es.On("IsActive").Return(true)
|
|
es.On("IsSearchEnabled").Return(true)
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = es
|
|
defer func() {
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = nil
|
|
}()
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, []string{
|
|
posts[6].Id,
|
|
posts[5].Id,
|
|
posts[4].Id,
|
|
posts[3].Id,
|
|
posts[2].Id,
|
|
posts[1].Id,
|
|
posts[0].Id,
|
|
}, results.Order)
|
|
es.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("should return nothing if ElasticSearch fails on later pages", func(t *testing.T) {
|
|
th, _ := setup(t, true)
|
|
defer th.TearDown()
|
|
|
|
page := 1
|
|
|
|
es := &mocks.SearchEngineInterface{}
|
|
es.On("SearchPosts", mock.Anything, mock.Anything, page, perPage).Return(nil, nil, &model.AppError{})
|
|
es.On("GetName").Return("mock")
|
|
es.On("Start").Return(nil).Maybe()
|
|
es.On("IsActive").Return(true)
|
|
es.On("IsSearchEnabled").Return(true)
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = es
|
|
defer func() {
|
|
th.App.Srv().SearchEngine.ElasticsearchEngine = nil
|
|
}()
|
|
|
|
results, err := th.App.SearchPostsInTeamForUser(searchTerm, th.BasicUser.Id, th.BasicTeam.Id, false, false, 0, page, perPage)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, []string{}, results.Order)
|
|
es.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestCountMentionsFromPost(t *testing.T) {
|
|
t.Run("should not count posts without mentions", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test3",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, count)
|
|
})
|
|
|
|
t.Run("should count keyword mentions", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.MENTION_KEYS_NOTIFY_PROP] = "apple"
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "apple",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post1 and post3 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, count)
|
|
})
|
|
|
|
t.Run("should count channel-wide mentions when enabled", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@channel",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@all",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post2 and post3 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, count)
|
|
})
|
|
|
|
t.Run("should not count channel-wide mentions when disabled for user", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "false"
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@channel",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@all",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, count)
|
|
})
|
|
|
|
t.Run("should not count channel-wide mentions when disabled for channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP] = "true"
|
|
|
|
_, err := th.App.UpdateChannelMemberNotifyProps(map[string]string{
|
|
model.IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP: model.IGNORE_CHANNEL_MENTIONS_ON,
|
|
}, channel.Id, user2.Id)
|
|
require.Nil(t, err)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@channel",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "@all",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, count)
|
|
})
|
|
|
|
t.Run("should count comment mentions when using COMMENTS_NOTIFY_ROOT", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ROOT
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post1.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
post3, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test3",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post3.Id,
|
|
Message: "test4",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post3.Id,
|
|
Message: "test5",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post2 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 1, count)
|
|
})
|
|
|
|
t.Run("should count comment mentions when using COMMENTS_NOTIFY_ANY", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ANY
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post1.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
post3, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test3",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post3.Id,
|
|
Message: "test4",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post3.Id,
|
|
Message: "test5",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post2 and post5 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, count)
|
|
})
|
|
|
|
t.Run("should count mentions caused by being added to the channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
Type: model.POST_ADD_TO_CHANNEL,
|
|
Props: map[string]interface{}{
|
|
model.POST_PROPS_ADDED_USER_ID: model.NewId(),
|
|
},
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test2",
|
|
Type: model.POST_ADD_TO_CHANNEL,
|
|
Props: map[string]interface{}{
|
|
model.POST_PROPS_ADDED_USER_ID: user2.Id,
|
|
},
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test3",
|
|
Type: model.POST_ADD_TO_CHANNEL,
|
|
Props: map[string]interface{}{
|
|
model.POST_PROPS_ADDED_USER_ID: user2.Id,
|
|
},
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// should be mentioned by post2 and post3
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, count)
|
|
})
|
|
|
|
t.Run("should return the number of posts made by the other user for a direct channel", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel, err := th.App.createDirectChannel(user1.Id, user2.Id)
|
|
require.Nil(t, err)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 2, count)
|
|
|
|
count, err = th.App.countMentionsFromPost(user1, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 0, count)
|
|
})
|
|
|
|
t.Run("should not count mentions from the before the given post", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
_, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
post2, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post1 and post3 should mention the user, but we only count post3
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post2)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 1, count)
|
|
})
|
|
|
|
t.Run("should not count mentions from the user's own posts", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post2 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 1, count)
|
|
})
|
|
|
|
t.Run("should include comments made before the given post when counting comment mentions", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
user2.NotifyProps[model.COMMENTS_NOTIFY_PROP] = model.COMMENTS_NOTIFY_ANY
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test1",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post1.Id,
|
|
Message: "test2",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
post3, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test3",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post1.Id,
|
|
Message: "test4",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post4 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post3)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 1, count)
|
|
})
|
|
|
|
t.Run("should count mentions from the user's webhook posts", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test1",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
Props: map[string]interface{}{
|
|
"from_webhook": "true",
|
|
},
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// post3 should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, 1, count)
|
|
})
|
|
|
|
t.Run("should count multiple pages of mentions", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
numPosts := 215
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
for i := 0; i < numPosts-1; i++ {
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
}
|
|
|
|
// Every post should mention the user
|
|
|
|
count, err := th.App.countMentionsFromPost(user2, post1)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, numPosts, count)
|
|
})
|
|
}
|
|
|
|
func TestFillInPostProps(t *testing.T) {
|
|
t.Run("should not add disable group highlight to post props for user with group mention permissions", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
user1 := th.BasicUser
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test123123 @group1 @group2 blah blah blah",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
err = th.App.FillInPostProps(post1, channel)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, post1.Props, model.StringInterface{})
|
|
})
|
|
|
|
t.Run("should not add disable group highlight to post props for app without license", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
id := model.NewId()
|
|
guest := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: "Password1",
|
|
EmailVerified: true,
|
|
}
|
|
guest, err := th.App.CreateGuest(guest)
|
|
require.Nil(t, err)
|
|
th.LinkUserToTeam(guest, th.BasicTeam)
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(guest, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: guest.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test123123 @group1 @group2 blah blah blah",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
err = th.App.FillInPostProps(post1, channel)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, post1.Props, model.StringInterface{})
|
|
})
|
|
|
|
t.Run("should add disable group highlight to post props for guest user", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
id := model.NewId()
|
|
guest := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
Password: "Password1",
|
|
EmailVerified: true,
|
|
}
|
|
guest, err := th.App.CreateGuest(guest)
|
|
require.Nil(t, err)
|
|
th.LinkUserToTeam(guest, th.BasicTeam)
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(guest, channel)
|
|
|
|
post1, err := th.App.CreatePost(&model.Post{
|
|
UserId: guest.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "test123123 @group1 @group2 blah blah blah",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
err = th.App.FillInPostProps(post1, channel)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, post1.Props, model.StringInterface{"disable_group_highlight": true})
|
|
})
|
|
}
|
|
|
|
func TestThreadMembership(t *testing.T) {
|
|
t.Run("should update memberships for conversation participants", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
|
|
postRoot, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "root post",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: postRoot.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// first user should now be part of the thread since they replied to a post
|
|
memberships, err2 := th.App.GetThreadMembershipsForUser(user1.Id, th.BasicTeam.Id)
|
|
require.NoError(t, err2)
|
|
require.Len(t, memberships, 1)
|
|
// second user should also be part of a thread since they were mentioned
|
|
memberships, err2 = th.App.GetThreadMembershipsForUser(user2.Id, th.BasicTeam.Id)
|
|
require.NoError(t, err2)
|
|
require.Len(t, memberships, 1)
|
|
|
|
post2, err := th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "second post",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user2.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: post2.Id,
|
|
Message: fmt.Sprintf("@%s", user1.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
// first user should now be part of two threads
|
|
memberships, err2 = th.App.GetThreadMembershipsForUser(user1.Id, th.BasicTeam.Id)
|
|
require.NoError(t, err2)
|
|
require.Len(t, memberships, 2)
|
|
})
|
|
}
|
|
|
|
func TestCollapsedThreadFetch(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.ThreadAutoFollow = true
|
|
*cfg.ServiceSettings.CollapsedThreads = model.COLLAPSED_THREADS_DEFAULT_ON
|
|
})
|
|
user1 := th.BasicUser
|
|
user2 := th.BasicUser2
|
|
|
|
t.Run("should only return root posts, enriched", func(t *testing.T) {
|
|
channel := th.CreateChannel(th.BasicTeam)
|
|
th.AddUserToChannel(user2, channel)
|
|
defer th.App.DeleteChannel(channel, user1.Id)
|
|
|
|
postRoot, err := th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
Message: "root post",
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
|
|
_, err = th.App.CreatePost(&model.Post{
|
|
UserId: user1.Id,
|
|
ChannelId: channel.Id,
|
|
RootId: postRoot.Id,
|
|
Message: fmt.Sprintf("@%s", user2.Username),
|
|
}, channel, false, true)
|
|
require.Nil(t, err)
|
|
thread, nErr := th.App.Srv().Store.Thread().Get(postRoot.Id)
|
|
require.NoError(t, nErr)
|
|
require.Len(t, thread.Participants, 2)
|
|
th.App.MarkChannelAsUnreadFromPost(postRoot.Id, user1.Id)
|
|
l, err := th.App.GetPostsForChannelAroundLastUnread(channel.Id, user1.Id, 10, 10, true, true, false)
|
|
require.Nil(t, err)
|
|
require.Len(t, l.Order, 1)
|
|
require.EqualValues(t, 1, l.Posts[postRoot.Id].ReplyCount)
|
|
require.EqualValues(t, []string{user1.Id, user2.Id}, []string{l.Posts[postRoot.Id].Participants[0].Id, l.Posts[postRoot.Id].Participants[1].Id})
|
|
require.Empty(t, l.Posts[postRoot.Id].Participants[0].Email)
|
|
require.NotZero(t, l.Posts[postRoot.Id].LastReplyAt)
|
|
|
|
// try extended fetch
|
|
l, err = th.App.GetPostsForChannelAroundLastUnread(channel.Id, user1.Id, 10, 10, true, true, true)
|
|
require.Nil(t, err)
|
|
require.Len(t, l.Order, 1)
|
|
require.NotEmpty(t, l.Posts[postRoot.Id].Participants[0].Email)
|
|
})
|
|
}
|