* MM-36589: provide previous values for unreads To successfully figure out the new counts of mentions or unread replies for CRT we need to provide previous values alongside with the new. This is needed so we'll know how many to subtract from the total. This commit provides those numbers upon publishing websocket ThreadUpdated and ThreadReadChanged events. * Fixes errors * Removes unneeded lines * Adds GetThreadUnreadReplyCount store method Uses the new store method to get unread replies instead of GetThreadForUser. * Tests, and some changes - Adds api4 tests to test ws events - Uses sqlx instead of gorp for new store method - Fixes case where previous_unread_replies could be a negative value * Refactors tests and adds more cases * Fixes previous and current unread counts for commenter When a user posts a reply to a thread the unread counts had a couple of issues. UnreadMentions where not zeroed out, and previous unread counts where not set correctly. This commit tries to fix that by marking the thread as read for the current poster after we set previous unread counts to the websocket event data. Also MaintainMembership should zero out UnreadMentions when we are setting the thread as read. * Oops * Fixes tests by updating when maintaining membership OK, so some tests broke because we zero UnreadMentions in the membership when we UpdateViewedTimestamp, since the new timestamp is always now. Some tests broke because MaintainMembership for the commenter so that the thread is read each time commenter posts moved further down in the SendNotification method. BOTH those test cases are fixed with this commit. To be sincere though I don't understand why the second one is fixed by this. * SystemAdminUser was not part of the channel Some tests are failing because SystemAdminUser is not part of the team and channels. This commit adds user to team and channels, in an effort to fix api4/user_tests * Fixes tests * Fixes tests * Addresses review comments * Fix if clause Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
1254 строки
36 KiB
Go
1254 строки
36 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package api4
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/rand"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/websocket"
|
|
s3 "github.com/minio/minio-go/v7"
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost-server/v6/app"
|
|
"github.com/mattermost/mattermost-server/v6/app/request"
|
|
"github.com/mattermost/mattermost-server/v6/config"
|
|
"github.com/mattermost/mattermost-server/v6/model"
|
|
"github.com/mattermost/mattermost-server/v6/plugin/plugintest/mock"
|
|
"github.com/mattermost/mattermost-server/v6/services/searchengine"
|
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
|
"github.com/mattermost/mattermost-server/v6/store"
|
|
"github.com/mattermost/mattermost-server/v6/store/localcachelayer"
|
|
"github.com/mattermost/mattermost-server/v6/store/storetest/mocks"
|
|
"github.com/mattermost/mattermost-server/v6/testlib"
|
|
"github.com/mattermost/mattermost-server/v6/web"
|
|
"github.com/mattermost/mattermost-server/v6/wsapi"
|
|
)
|
|
|
|
type TestHelper struct {
|
|
App *app.App
|
|
Server *app.Server
|
|
ConfigStore *config.Store
|
|
|
|
Context *request.Context
|
|
Client *model.Client4
|
|
BasicUser *model.User
|
|
BasicUser2 *model.User
|
|
TeamAdminUser *model.User
|
|
BasicTeam *model.Team
|
|
BasicChannel *model.Channel
|
|
BasicPrivateChannel *model.Channel
|
|
BasicPrivateChannel2 *model.Channel
|
|
BasicDeletedChannel *model.Channel
|
|
BasicChannel2 *model.Channel
|
|
BasicPost *model.Post
|
|
Group *model.Group
|
|
|
|
SystemAdminClient *model.Client4
|
|
SystemAdminUser *model.User
|
|
tempWorkspace string
|
|
|
|
SystemManagerClient *model.Client4
|
|
SystemManagerUser *model.User
|
|
|
|
LocalClient *model.Client4
|
|
|
|
IncludeCacheLayer bool
|
|
|
|
TestLogger *mlog.Logger
|
|
}
|
|
|
|
var mainHelper *testlib.MainHelper
|
|
|
|
func SetMainHelper(mh *testlib.MainHelper) {
|
|
mainHelper = mh
|
|
}
|
|
|
|
func setupTestHelper(dbStore store.Store, searchEngine *searchengine.Broker, enterprise bool, includeCache bool,
|
|
updateConfig func(*model.Config), options []app.Option) *TestHelper {
|
|
tempWorkspace, err := ioutil.TempDir("", "apptest")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
memoryStore, err := config.NewMemoryStoreWithOptions(&config.MemoryStoreOptions{IgnoreEnvironmentOverrides: true})
|
|
if err != nil {
|
|
panic("failed to initialize memory store: " + err.Error())
|
|
}
|
|
|
|
memoryConfig := &model.Config{}
|
|
memoryConfig.SetDefaults()
|
|
*memoryConfig.PluginSettings.Directory = filepath.Join(tempWorkspace, "plugins")
|
|
*memoryConfig.PluginSettings.ClientDirectory = filepath.Join(tempWorkspace, "webapp")
|
|
memoryConfig.ServiceSettings.EnableLocalMode = model.NewBool(true)
|
|
*memoryConfig.ServiceSettings.LocalModeSocketLocation = filepath.Join(tempWorkspace, "mattermost_local.sock")
|
|
*memoryConfig.AnnouncementSettings.AdminNoticesEnabled = false
|
|
*memoryConfig.AnnouncementSettings.UserNoticesEnabled = false
|
|
*memoryConfig.PluginSettings.AutomaticPrepackagedPlugins = false
|
|
if updateConfig != nil {
|
|
updateConfig(memoryConfig)
|
|
}
|
|
memoryStore.Set(memoryConfig)
|
|
|
|
configStore, err := config.NewStoreFromBacking(memoryStore, nil, false)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
options = append(options, app.ConfigStore(configStore))
|
|
if includeCache {
|
|
// Adds the cache layer to the test store
|
|
options = append(options, app.StoreOverride(func(s *app.Server) store.Store {
|
|
lcl, err2 := localcachelayer.NewLocalCacheLayer(dbStore, s.Metrics, s.Cluster, s.CacheProvider)
|
|
if err2 != nil {
|
|
panic(err2)
|
|
}
|
|
return lcl
|
|
}))
|
|
} else {
|
|
options = append(options, app.StoreOverride(dbStore))
|
|
}
|
|
|
|
testLogger, _ := mlog.NewLogger()
|
|
logCfg, _ := config.MloggerConfigFromLoggerConfig(&memoryConfig.LogSettings, nil, config.GetLogFileLocation)
|
|
if errCfg := testLogger.ConfigureTargets(logCfg, nil); errCfg != nil {
|
|
panic("failed to configure test logger: " + errCfg.Error())
|
|
}
|
|
// lock logger config so server init cannot override it during testing.
|
|
testLogger.LockConfiguration()
|
|
options = append(options, app.SetLogger(testLogger))
|
|
|
|
s, err := app.NewServer(options...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
th := &TestHelper{
|
|
App: app.New(app.ServerConnector(s.Channels())),
|
|
Server: s,
|
|
ConfigStore: configStore,
|
|
IncludeCacheLayer: includeCache,
|
|
Context: &request.Context{},
|
|
TestLogger: testLogger,
|
|
}
|
|
|
|
if s.SearchEngine != nil && s.SearchEngine.BleveEngine != nil && searchEngine != nil {
|
|
searchEngine.BleveEngine = s.SearchEngine.BleveEngine
|
|
}
|
|
|
|
if searchEngine != nil {
|
|
th.App.SetSearchEngine(searchEngine)
|
|
}
|
|
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.TeamSettings.MaxUsersPerTeam = 50
|
|
*cfg.RateLimitSettings.Enable = false
|
|
*cfg.EmailSettings.SendEmailNotifications = true
|
|
*cfg.ServiceSettings.SiteURL = ""
|
|
|
|
// Disable sniffing, otherwise elastic client fails to connect to docker node
|
|
// More details: https://github.com/olivere/elastic/wiki/Sniffing
|
|
*cfg.ElasticsearchSettings.Sniff = false
|
|
|
|
*cfg.TeamSettings.EnableOpenServer = true
|
|
|
|
// Disable strict password requirements for test
|
|
*cfg.PasswordSettings.MinimumLength = 5
|
|
*cfg.PasswordSettings.Lowercase = false
|
|
*cfg.PasswordSettings.Uppercase = false
|
|
*cfg.PasswordSettings.Symbol = false
|
|
*cfg.PasswordSettings.Number = false
|
|
|
|
*cfg.ServiceSettings.ListenAddress = ":0"
|
|
})
|
|
if err := th.Server.Start(); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
Init(th.App.Srv())
|
|
web.New(th.App.Srv())
|
|
wsapi.Init(th.App.Srv())
|
|
|
|
if enterprise {
|
|
th.App.Srv().SetLicense(model.NewTestLicense())
|
|
th.App.Srv().Jobs.InitWorkers()
|
|
th.App.Srv().Jobs.InitSchedulers()
|
|
} else {
|
|
th.App.Srv().SetLicense(nil)
|
|
}
|
|
|
|
th.Client = th.CreateClient()
|
|
th.SystemAdminClient = th.CreateClient()
|
|
th.SystemManagerClient = th.CreateClient()
|
|
|
|
// Verify handling of the supported true/false values by randomizing on each run.
|
|
rand.Seed(time.Now().UTC().UnixNano())
|
|
trueValues := []string{"1", "t", "T", "TRUE", "true", "True"}
|
|
falseValues := []string{"0", "f", "F", "FALSE", "false", "False"}
|
|
trueString := trueValues[rand.Intn(len(trueValues))]
|
|
falseString := falseValues[rand.Intn(len(falseValues))]
|
|
mlog.Debug("Configured Client4 bool string values", mlog.String("true", trueString), mlog.String("false", falseString))
|
|
th.Client.SetBoolString(true, trueString)
|
|
th.Client.SetBoolString(false, falseString)
|
|
|
|
th.LocalClient = th.CreateLocalClient(*memoryConfig.ServiceSettings.LocalModeSocketLocation)
|
|
|
|
if th.tempWorkspace == "" {
|
|
th.tempWorkspace = tempWorkspace
|
|
}
|
|
|
|
return th
|
|
}
|
|
|
|
func SetupEnterprise(tb testing.TB) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
if mainHelper == nil {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
mainHelper.PreloadMigrations()
|
|
searchEngine := mainHelper.GetSearchEngine()
|
|
th := setupTestHelper(dbStore, searchEngine, true, true, nil, nil)
|
|
th.InitLogin()
|
|
return th
|
|
}
|
|
|
|
func Setup(tb testing.TB) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
if mainHelper == nil {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
mainHelper.PreloadMigrations()
|
|
searchEngine := mainHelper.GetSearchEngine()
|
|
th := setupTestHelper(dbStore, searchEngine, false, true, nil, nil)
|
|
th.InitLogin()
|
|
return th
|
|
}
|
|
|
|
func SetupAndApplyConfigBeforeLogin(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
if mainHelper == nil {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
mainHelper.PreloadMigrations()
|
|
searchEngine := mainHelper.GetSearchEngine()
|
|
th := setupTestHelper(dbStore, searchEngine, false, true, nil, nil)
|
|
th.App.UpdateConfig(updateConfig)
|
|
th.InitLogin()
|
|
return th
|
|
}
|
|
|
|
func SetupConfig(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
if mainHelper == nil {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
searchEngine := mainHelper.GetSearchEngine()
|
|
th := setupTestHelper(dbStore, searchEngine, false, true, updateConfig, nil)
|
|
th.InitLogin()
|
|
return th
|
|
}
|
|
|
|
func SetupConfigWithStoreMock(tb testing.TB, updateConfig func(cfg *model.Config)) *TestHelper {
|
|
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, false, false, updateConfig, nil)
|
|
statusMock := mocks.StatusStore{}
|
|
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
|
|
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
|
|
statusMock.On("UpdateLastActivityAt", "user1", mock.Anything).Return(nil)
|
|
statusMock.On("SaveOrUpdate", mock.AnythingOfType("*model.Status")).Return(nil)
|
|
emptyMockStore := mocks.Store{}
|
|
emptyMockStore.On("Close").Return(nil)
|
|
emptyMockStore.On("Status").Return(&statusMock)
|
|
th.App.Srv().Store = &emptyMockStore
|
|
return th
|
|
}
|
|
|
|
func SetupWithStoreMock(tb testing.TB) *TestHelper {
|
|
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, false, false, nil, nil)
|
|
statusMock := mocks.StatusStore{}
|
|
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
|
|
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
|
|
statusMock.On("UpdateLastActivityAt", "user1", mock.Anything).Return(nil)
|
|
statusMock.On("SaveOrUpdate", mock.AnythingOfType("*model.Status")).Return(nil)
|
|
emptyMockStore := mocks.Store{}
|
|
emptyMockStore.On("Close").Return(nil)
|
|
emptyMockStore.On("Status").Return(&statusMock)
|
|
th.App.Srv().Store = &emptyMockStore
|
|
return th
|
|
}
|
|
|
|
func SetupEnterpriseWithStoreMock(tb testing.TB) *TestHelper {
|
|
th := setupTestHelper(testlib.GetMockStoreForSetupFunctions(), nil, true, false, nil, nil)
|
|
statusMock := mocks.StatusStore{}
|
|
statusMock.On("UpdateExpiredDNDStatuses").Return([]*model.Status{}, nil)
|
|
statusMock.On("Get", "user1").Return(&model.Status{UserId: "user1", Status: model.StatusOnline}, nil)
|
|
statusMock.On("UpdateLastActivityAt", "user1", mock.Anything).Return(nil)
|
|
statusMock.On("SaveOrUpdate", mock.AnythingOfType("*model.Status")).Return(nil)
|
|
emptyMockStore := mocks.Store{}
|
|
emptyMockStore.On("Close").Return(nil)
|
|
emptyMockStore.On("Status").Return(&statusMock)
|
|
th.App.Srv().Store = &emptyMockStore
|
|
return th
|
|
}
|
|
|
|
func SetupWithServerOptions(tb testing.TB, options []app.Option) *TestHelper {
|
|
if testing.Short() {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
if mainHelper == nil {
|
|
tb.SkipNow()
|
|
}
|
|
|
|
dbStore := mainHelper.GetStore()
|
|
dbStore.DropAllTables()
|
|
dbStore.MarkSystemRanUnitTests()
|
|
mainHelper.PreloadMigrations()
|
|
searchEngine := mainHelper.GetSearchEngine()
|
|
th := setupTestHelper(dbStore, searchEngine, false, true, nil, options)
|
|
th.InitLogin()
|
|
return th
|
|
}
|
|
|
|
func (th *TestHelper) ShutdownApp() {
|
|
done := make(chan bool)
|
|
go func() {
|
|
th.Server.Shutdown()
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(30 * time.Second):
|
|
// panic instead of fatal to terminate all tests in this package, otherwise the
|
|
// still running App could spuriously fail subsequent tests.
|
|
panic("failed to shutdown App within 30 seconds")
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) TearDown() {
|
|
if th.IncludeCacheLayer {
|
|
// Clean all the caches
|
|
th.App.Srv().InvalidateAllCaches()
|
|
}
|
|
th.ShutdownApp()
|
|
}
|
|
|
|
var initBasicOnce sync.Once
|
|
var userCache struct {
|
|
SystemAdminUser *model.User
|
|
SystemManagerUser *model.User
|
|
TeamAdminUser *model.User
|
|
BasicUser *model.User
|
|
BasicUser2 *model.User
|
|
}
|
|
|
|
func (th *TestHelper) InitLogin() *TestHelper {
|
|
th.waitForConnectivity()
|
|
|
|
// create users once and cache them because password hashing is slow
|
|
initBasicOnce.Do(func() {
|
|
th.SystemAdminUser = th.CreateUser()
|
|
th.App.UpdateUserRoles(th.SystemAdminUser.Id, model.SystemUserRoleId+" "+model.SystemAdminRoleId, false)
|
|
th.SystemAdminUser, _ = th.App.GetUser(th.SystemAdminUser.Id)
|
|
userCache.SystemAdminUser = th.SystemAdminUser.DeepCopy()
|
|
|
|
th.SystemManagerUser = th.CreateUser()
|
|
th.App.UpdateUserRoles(th.SystemManagerUser.Id, model.SystemUserRoleId+" "+model.SystemManagerRoleId, false)
|
|
th.SystemManagerUser, _ = th.App.GetUser(th.SystemManagerUser.Id)
|
|
userCache.SystemManagerUser = th.SystemManagerUser.DeepCopy()
|
|
|
|
th.TeamAdminUser = th.CreateUser()
|
|
th.App.UpdateUserRoles(th.TeamAdminUser.Id, model.SystemUserRoleId, false)
|
|
th.TeamAdminUser, _ = th.App.GetUser(th.TeamAdminUser.Id)
|
|
userCache.TeamAdminUser = th.TeamAdminUser.DeepCopy()
|
|
|
|
th.BasicUser = th.CreateUser()
|
|
th.BasicUser, _ = th.App.GetUser(th.BasicUser.Id)
|
|
userCache.BasicUser = th.BasicUser.DeepCopy()
|
|
|
|
th.BasicUser2 = th.CreateUser()
|
|
th.BasicUser2, _ = th.App.GetUser(th.BasicUser2.Id)
|
|
userCache.BasicUser2 = th.BasicUser2.DeepCopy()
|
|
})
|
|
// restore cached users
|
|
th.SystemAdminUser = userCache.SystemAdminUser.DeepCopy()
|
|
th.SystemManagerUser = userCache.SystemManagerUser.DeepCopy()
|
|
th.TeamAdminUser = userCache.TeamAdminUser.DeepCopy()
|
|
th.BasicUser = userCache.BasicUser.DeepCopy()
|
|
th.BasicUser2 = userCache.BasicUser2.DeepCopy()
|
|
|
|
users := []*model.User{th.SystemAdminUser, th.TeamAdminUser, th.BasicUser, th.BasicUser2, th.SystemManagerUser}
|
|
mainHelper.GetSQLStore().User().InsertUsers(users)
|
|
|
|
// restore non hashed password for login
|
|
th.SystemAdminUser.Password = "Pa$$word11"
|
|
th.TeamAdminUser.Password = "Pa$$word11"
|
|
th.BasicUser.Password = "Pa$$word11"
|
|
th.BasicUser2.Password = "Pa$$word11"
|
|
th.SystemManagerUser.Password = "Pa$$word11"
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(3)
|
|
go func() {
|
|
th.LoginSystemAdmin()
|
|
wg.Done()
|
|
}()
|
|
go func() {
|
|
th.LoginSystemManager()
|
|
wg.Done()
|
|
}()
|
|
go func() {
|
|
th.LoginTeamAdmin()
|
|
wg.Done()
|
|
}()
|
|
wg.Wait()
|
|
return th
|
|
}
|
|
|
|
func (th *TestHelper) InitBasic() *TestHelper {
|
|
th.BasicTeam = th.CreateTeam()
|
|
th.BasicChannel = th.CreatePublicChannel()
|
|
th.BasicPrivateChannel = th.CreatePrivateChannel()
|
|
th.BasicPrivateChannel2 = th.CreatePrivateChannel()
|
|
th.BasicDeletedChannel = th.CreatePublicChannel()
|
|
th.BasicChannel2 = th.CreatePublicChannel()
|
|
th.BasicPost = th.CreatePost()
|
|
th.LinkUserToTeam(th.BasicUser, th.BasicTeam)
|
|
th.LinkUserToTeam(th.BasicUser2, th.BasicTeam)
|
|
th.App.AddUserToChannel(th.BasicUser, th.BasicChannel, false)
|
|
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel, false)
|
|
th.App.AddUserToChannel(th.BasicUser, th.BasicChannel2, false)
|
|
th.App.AddUserToChannel(th.BasicUser2, th.BasicChannel2, false)
|
|
th.App.AddUserToChannel(th.BasicUser, th.BasicPrivateChannel, false)
|
|
th.App.AddUserToChannel(th.BasicUser2, th.BasicPrivateChannel, false)
|
|
th.App.AddUserToChannel(th.BasicUser, th.BasicDeletedChannel, false)
|
|
th.App.AddUserToChannel(th.BasicUser2, th.BasicDeletedChannel, false)
|
|
th.App.UpdateUserRoles(th.BasicUser.Id, model.SystemUserRoleId, false)
|
|
th.Client.DeleteChannel(th.BasicDeletedChannel.Id)
|
|
th.LoginBasic()
|
|
th.Group = th.CreateGroup()
|
|
|
|
return th
|
|
}
|
|
|
|
func (th *TestHelper) waitForConnectivity() {
|
|
for i := 0; i < 1000; i++ {
|
|
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", th.App.Srv().ListenAddr.Port))
|
|
if err == nil {
|
|
conn.Close()
|
|
return
|
|
}
|
|
time.Sleep(time.Millisecond * 20)
|
|
}
|
|
panic("unable to connect")
|
|
}
|
|
|
|
func (th *TestHelper) CreateClient() *model.Client4 {
|
|
return model.NewAPIv4Client(fmt.Sprintf("http://localhost:%v", th.App.Srv().ListenAddr.Port))
|
|
}
|
|
|
|
// ToDo: maybe move this to NewAPIv4SocketClient and reuse it in mmctl
|
|
func (th *TestHelper) CreateLocalClient(socketPath string) *model.Client4 {
|
|
httpClient := &http.Client{
|
|
Transport: &http.Transport{
|
|
Dial: func(network, addr string) (net.Conn, error) {
|
|
return net.Dial("unix", socketPath)
|
|
},
|
|
},
|
|
}
|
|
|
|
return &model.Client4{
|
|
APIURL: "http://_" + model.APIURLSuffix,
|
|
HTTPClient: httpClient,
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, error) {
|
|
return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", th.App.Srv().ListenAddr.Port), th.Client.AuthToken)
|
|
}
|
|
|
|
func (th *TestHelper) CreateReliableWebSocketClient(connID string, seqNo int) (*model.WebSocketClient, error) {
|
|
return model.NewReliableWebSocketClientWithDialer(websocket.DefaultDialer, fmt.Sprintf("ws://localhost:%v", th.App.Srv().ListenAddr.Port), th.Client.AuthToken, connID, seqNo, true)
|
|
}
|
|
|
|
func (th *TestHelper) CreateWebSocketSystemAdminClient() (*model.WebSocketClient, error) {
|
|
return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", th.App.Srv().ListenAddr.Port), th.SystemAdminClient.AuthToken)
|
|
}
|
|
|
|
func (th *TestHelper) CreateWebSocketSystemManagerClient() (*model.WebSocketClient, error) {
|
|
return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", th.App.Srv().ListenAddr.Port), th.SystemManagerClient.AuthToken)
|
|
}
|
|
|
|
func (th *TestHelper) CreateWebSocketClientWithClient(client *model.Client4) (*model.WebSocketClient, error) {
|
|
return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", th.App.Srv().ListenAddr.Port), client.AuthToken)
|
|
}
|
|
|
|
func (th *TestHelper) CreateBotWithSystemAdminClient() *model.Bot {
|
|
return th.CreateBotWithClient((th.SystemAdminClient))
|
|
}
|
|
|
|
func (th *TestHelper) CreateBotWithClient(client *model.Client4) *model.Bot {
|
|
bot := &model.Bot{
|
|
Username: GenerateTestUsername(),
|
|
DisplayName: "a bot",
|
|
Description: "bot",
|
|
}
|
|
|
|
rbot, _, err := client.CreateBot(bot)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rbot
|
|
}
|
|
|
|
func (th *TestHelper) CreateUser() *model.User {
|
|
return th.CreateUserWithClient(th.Client)
|
|
}
|
|
|
|
func (th *TestHelper) CreateTeam() *model.Team {
|
|
return th.CreateTeamWithClient(th.Client)
|
|
}
|
|
|
|
func (th *TestHelper) CreateTeamWithClient(client *model.Client4) *model.Team {
|
|
id := model.NewId()
|
|
team := &model.Team{
|
|
DisplayName: "dn_" + id,
|
|
Name: GenerateTestTeamName(),
|
|
Email: th.GenerateTestEmail(),
|
|
Type: model.TeamOpen,
|
|
}
|
|
|
|
rteam, _, err := client.CreateTeam(team)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rteam
|
|
}
|
|
|
|
func (th *TestHelper) CreateUserWithClient(client *model.Client4) *model.User {
|
|
id := model.NewId()
|
|
|
|
user := &model.User{
|
|
Email: th.GenerateTestEmail(),
|
|
Username: GenerateTestUsername(),
|
|
Nickname: "nn_" + id,
|
|
FirstName: "f_" + id,
|
|
LastName: "l_" + id,
|
|
Password: "Pa$$word11",
|
|
}
|
|
|
|
ruser, _, err := client.CreateUser(user)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ruser.Password = "Pa$$word11"
|
|
_, err = th.App.Srv().Store.User().VerifyEmail(ruser.Id, ruser.Email)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return ruser
|
|
}
|
|
|
|
func (th *TestHelper) CreateUserWithAuth(authService string) *model.User {
|
|
id := model.NewId()
|
|
user := &model.User{
|
|
Email: "success+" + id + "@simulator.amazonses.com",
|
|
Username: "un_" + id,
|
|
Nickname: "nn_" + id,
|
|
EmailVerified: true,
|
|
AuthService: authService,
|
|
}
|
|
user, err := th.App.CreateUser(th.Context, user)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return user
|
|
}
|
|
|
|
func (th *TestHelper) SetupLdapConfig() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableMultifactorAuthentication = true
|
|
*cfg.LdapSettings.Enable = true
|
|
*cfg.LdapSettings.EnableSync = true
|
|
*cfg.LdapSettings.LdapServer = "dockerhost"
|
|
*cfg.LdapSettings.BaseDN = "dc=mm,dc=test,dc=com"
|
|
*cfg.LdapSettings.BindUsername = "cn=admin,dc=mm,dc=test,dc=com"
|
|
*cfg.LdapSettings.BindPassword = "mostest"
|
|
*cfg.LdapSettings.FirstNameAttribute = "cn"
|
|
*cfg.LdapSettings.LastNameAttribute = "sn"
|
|
*cfg.LdapSettings.NicknameAttribute = "cn"
|
|
*cfg.LdapSettings.EmailAttribute = "mail"
|
|
*cfg.LdapSettings.UsernameAttribute = "uid"
|
|
*cfg.LdapSettings.IdAttribute = "cn"
|
|
*cfg.LdapSettings.LoginIdAttribute = "uid"
|
|
*cfg.LdapSettings.SkipCertificateVerification = true
|
|
*cfg.LdapSettings.GroupFilter = ""
|
|
*cfg.LdapSettings.GroupDisplayNameAttribute = "cN"
|
|
*cfg.LdapSettings.GroupIdAttribute = "entRyUuId"
|
|
*cfg.LdapSettings.MaxPageSize = 0
|
|
})
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
}
|
|
|
|
func (th *TestHelper) SetupSamlConfig() {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.SamlSettings.Enable = true
|
|
*cfg.SamlSettings.Verify = false
|
|
*cfg.SamlSettings.Encrypt = false
|
|
*cfg.SamlSettings.IdpURL = "https://does.notmatter.com"
|
|
*cfg.SamlSettings.IdpDescriptorURL = "https://localhost/adfs/services/trust"
|
|
*cfg.SamlSettings.AssertionConsumerServiceURL = "https://localhost/login/sso/saml"
|
|
*cfg.SamlSettings.ServiceProviderIdentifier = "https://localhost/login/sso/saml"
|
|
*cfg.SamlSettings.IdpCertificateFile = app.SamlIdpCertificateName
|
|
*cfg.SamlSettings.PrivateKeyFile = app.SamlPrivateKeyName
|
|
*cfg.SamlSettings.PublicCertificateFile = app.SamlPublicCertificateName
|
|
*cfg.SamlSettings.EmailAttribute = "Email"
|
|
*cfg.SamlSettings.UsernameAttribute = "Username"
|
|
*cfg.SamlSettings.FirstNameAttribute = "FirstName"
|
|
*cfg.SamlSettings.LastNameAttribute = "LastName"
|
|
*cfg.SamlSettings.NicknameAttribute = ""
|
|
*cfg.SamlSettings.PositionAttribute = ""
|
|
*cfg.SamlSettings.LocaleAttribute = ""
|
|
*cfg.SamlSettings.SignatureAlgorithm = model.SamlSettingsSignatureAlgorithmSha256
|
|
*cfg.SamlSettings.CanonicalAlgorithm = model.SamlSettingsCanonicalAlgorithmC14n11
|
|
})
|
|
th.App.Srv().SetLicense(model.NewTestLicense("saml"))
|
|
}
|
|
|
|
func (th *TestHelper) CreatePublicChannel() *model.Channel {
|
|
return th.CreateChannelWithClient(th.Client, model.ChannelTypeOpen)
|
|
}
|
|
|
|
func (th *TestHelper) CreatePrivateChannel() *model.Channel {
|
|
return th.CreateChannelWithClient(th.Client, model.ChannelTypePrivate)
|
|
}
|
|
|
|
func (th *TestHelper) CreateChannelWithClient(client *model.Client4, channelType model.ChannelType) *model.Channel {
|
|
return th.CreateChannelWithClientAndTeam(client, channelType, th.BasicTeam.Id)
|
|
}
|
|
|
|
func (th *TestHelper) CreateChannelWithClientAndTeam(client *model.Client4, channelType model.ChannelType, teamId string) *model.Channel {
|
|
id := model.NewId()
|
|
|
|
channel := &model.Channel{
|
|
DisplayName: "dn_" + id,
|
|
Name: GenerateTestChannelName(),
|
|
Type: channelType,
|
|
TeamId: teamId,
|
|
}
|
|
|
|
rchannel, _, err := client.CreateChannel(channel)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rchannel
|
|
}
|
|
|
|
func (th *TestHelper) CreatePost() *model.Post {
|
|
return th.CreatePostWithClient(th.Client, th.BasicChannel)
|
|
}
|
|
|
|
func (th *TestHelper) CreatePinnedPost() *model.Post {
|
|
return th.CreatePinnedPostWithClient(th.Client, th.BasicChannel)
|
|
}
|
|
|
|
func (th *TestHelper) CreateMessagePost(message string) *model.Post {
|
|
return th.CreateMessagePostWithClient(th.Client, th.BasicChannel, message)
|
|
}
|
|
|
|
func (th *TestHelper) CreatePostWithClient(client *model.Client4, channel *model.Channel) *model.Post {
|
|
id := model.NewId()
|
|
|
|
post := &model.Post{
|
|
ChannelId: channel.Id,
|
|
Message: "message_" + id,
|
|
}
|
|
|
|
rpost, _, err := client.CreatePost(post)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rpost
|
|
}
|
|
|
|
func (th *TestHelper) CreatePinnedPostWithClient(client *model.Client4, channel *model.Channel) *model.Post {
|
|
id := model.NewId()
|
|
|
|
post := &model.Post{
|
|
ChannelId: channel.Id,
|
|
Message: "message_" + id,
|
|
IsPinned: true,
|
|
}
|
|
|
|
rpost, _, err := client.CreatePost(post)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rpost
|
|
}
|
|
|
|
func (th *TestHelper) CreateMessagePostWithClient(client *model.Client4, channel *model.Channel, message string) *model.Post {
|
|
post := &model.Post{
|
|
ChannelId: channel.Id,
|
|
Message: message,
|
|
}
|
|
|
|
rpost, _, err := client.CreatePost(post)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return rpost
|
|
}
|
|
|
|
func (th *TestHelper) CreateMessagePostNoClient(channel *model.Channel, message string, createAtTime int64) *model.Post {
|
|
post, err := th.App.Srv().Store.Post().Save(&model.Post{
|
|
UserId: th.BasicUser.Id,
|
|
ChannelId: channel.Id,
|
|
Message: message,
|
|
CreateAt: createAtTime,
|
|
})
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return post
|
|
}
|
|
|
|
func (th *TestHelper) CreateDmChannel(user *model.User) *model.Channel {
|
|
var err *model.AppError
|
|
var channel *model.Channel
|
|
if channel, err = th.App.GetOrCreateDirectChannel(th.Context, th.BasicUser.Id, user.Id); err != nil {
|
|
panic(err)
|
|
}
|
|
return channel
|
|
}
|
|
|
|
func (th *TestHelper) LoginBasic() {
|
|
th.LoginBasicWithClient(th.Client)
|
|
}
|
|
|
|
func (th *TestHelper) LoginBasic2() {
|
|
th.LoginBasic2WithClient(th.Client)
|
|
}
|
|
|
|
func (th *TestHelper) LoginTeamAdmin() {
|
|
th.LoginTeamAdminWithClient(th.Client)
|
|
}
|
|
|
|
func (th *TestHelper) LoginSystemAdmin() {
|
|
th.LoginSystemAdminWithClient(th.SystemAdminClient)
|
|
}
|
|
|
|
func (th *TestHelper) LoginSystemManager() {
|
|
th.LoginSystemManagerWithClient(th.SystemManagerClient)
|
|
}
|
|
|
|
func (th *TestHelper) LoginBasicWithClient(client *model.Client4) {
|
|
_, _, err := client.Login(th.BasicUser.Email, th.BasicUser.Password)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) LoginBasic2WithClient(client *model.Client4) {
|
|
_, _, err := client.Login(th.BasicUser2.Email, th.BasicUser2.Password)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) LoginTeamAdminWithClient(client *model.Client4) {
|
|
_, _, err := client.Login(th.TeamAdminUser.Email, th.TeamAdminUser.Password)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) LoginSystemManagerWithClient(client *model.Client4) {
|
|
_, _, err := client.Login(th.SystemManagerUser.Email, th.SystemManagerUser.Password)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) LoginSystemAdminWithClient(client *model.Client4) {
|
|
_, _, err := client.Login(th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) UpdateActiveUser(user *model.User, active bool) {
|
|
_, err := th.App.UpdateActive(th.Context, user, active)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) LinkUserToTeam(user *model.User, team *model.Team) {
|
|
_, err := th.App.JoinUserToTeam(th.Context, team, user, "")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) UnlinkUserFromTeam(user *model.User, team *model.Team) {
|
|
err := th.App.RemoveUserFromTeam(th.Context, team.Id, user.Id, "")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) AddUserToChannel(user *model.User, channel *model.Channel) *model.ChannelMember {
|
|
member, err := th.App.AddUserToChannel(user, channel, false)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return member
|
|
}
|
|
|
|
func (th *TestHelper) RemoveUserFromChannel(user *model.User, channel *model.Channel) {
|
|
err := th.App.RemoveUserFromChannel(th.Context, user.Id, "", channel)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) GenerateTestEmail() string {
|
|
if *th.App.Config().EmailSettings.SMTPServer != "localhost" && os.Getenv("CI_INBUCKET_PORT") == "" {
|
|
return strings.ToLower("success+" + model.NewId() + "@simulator.amazonses.com")
|
|
}
|
|
return strings.ToLower(model.NewId() + "@localhost")
|
|
}
|
|
|
|
func (th *TestHelper) CreateGroup() *model.Group {
|
|
id := model.NewId()
|
|
group := &model.Group{
|
|
Name: model.NewString("n-" + id),
|
|
DisplayName: "dn_" + id,
|
|
Source: model.GroupSourceLdap,
|
|
RemoteId: "ri_" + id,
|
|
}
|
|
|
|
group, err := th.App.CreateGroup(group)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return group
|
|
}
|
|
|
|
// TestForSystemAdminAndLocal runs a test function for both
|
|
// SystemAdmin and Local clients. Several endpoints work in the same
|
|
// way when used by a fully privileged user and through the local
|
|
// mode, so this helper facilitates checking both
|
|
func (th *TestHelper) TestForSystemAdminAndLocal(t *testing.T, f func(*testing.T, *model.Client4), name ...string) {
|
|
var testName string
|
|
if len(name) > 0 {
|
|
testName = name[0] + "/"
|
|
}
|
|
|
|
t.Run(testName+"SystemAdminClient", func(t *testing.T) {
|
|
f(t, th.SystemAdminClient)
|
|
})
|
|
|
|
t.Run(testName+"LocalClient", func(t *testing.T) {
|
|
f(t, th.LocalClient)
|
|
})
|
|
}
|
|
|
|
// TestForAllClients runs a test function for all the clients
|
|
// registered in the TestHelper
|
|
func (th *TestHelper) TestForAllClients(t *testing.T, f func(*testing.T, *model.Client4), name ...string) {
|
|
var testName string
|
|
if len(name) > 0 {
|
|
testName = name[0] + "/"
|
|
}
|
|
|
|
t.Run(testName+"Client", func(t *testing.T) {
|
|
f(t, th.Client)
|
|
})
|
|
|
|
t.Run(testName+"SystemAdminClient", func(t *testing.T) {
|
|
f(t, th.SystemAdminClient)
|
|
})
|
|
|
|
t.Run(testName+"LocalClient", func(t *testing.T) {
|
|
f(t, th.LocalClient)
|
|
})
|
|
}
|
|
|
|
func GenerateTestUsername() string {
|
|
return "fakeuser" + model.NewRandomString(10)
|
|
}
|
|
|
|
func GenerateTestTeamName() string {
|
|
return "faketeam" + model.NewRandomString(6)
|
|
}
|
|
|
|
func GenerateTestChannelName() string {
|
|
return "fakechannel" + model.NewRandomString(10)
|
|
}
|
|
|
|
func GenerateTestAppName() string {
|
|
return "fakeoauthapp" + model.NewRandomString(10)
|
|
}
|
|
|
|
func GenerateTestId() string {
|
|
return model.NewId()
|
|
}
|
|
|
|
func CheckUserSanitization(tb testing.TB, user *model.User) {
|
|
tb.Helper()
|
|
|
|
require.Equal(tb, "", user.Password, "password wasn't blank")
|
|
require.Empty(tb, user.AuthData, "auth data wasn't blank")
|
|
require.Equal(tb, "", user.MfaSecret, "mfa secret wasn't blank")
|
|
}
|
|
|
|
func CheckEtag(tb testing.TB, data interface{}, resp *model.Response) {
|
|
tb.Helper()
|
|
|
|
require.Empty(tb, data)
|
|
require.Equal(tb, http.StatusNotModified, resp.StatusCode, "wrong status code for etag")
|
|
}
|
|
|
|
func checkHTTPStatus(tb testing.TB, resp *model.Response, expectedStatus int) {
|
|
tb.Helper()
|
|
|
|
require.NotNilf(tb, resp, "Unexpected nil response, expected http status:%v", expectedStatus)
|
|
require.Equalf(tb, expectedStatus, resp.StatusCode, "Expected http status:%v, got %v", expectedStatus, resp.StatusCode)
|
|
}
|
|
|
|
func CheckOKStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusOK)
|
|
}
|
|
|
|
func CheckCreatedStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusCreated)
|
|
}
|
|
|
|
func CheckForbiddenStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusForbidden)
|
|
}
|
|
|
|
func CheckUnauthorizedStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusUnauthorized)
|
|
}
|
|
|
|
func CheckNotFoundStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusNotFound)
|
|
}
|
|
|
|
func CheckBadRequestStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusBadRequest)
|
|
}
|
|
|
|
func CheckNotImplementedStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusNotImplemented)
|
|
}
|
|
|
|
func CheckRequestEntityTooLargeStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusRequestEntityTooLarge)
|
|
}
|
|
|
|
func CheckInternalErrorStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusInternalServerError)
|
|
}
|
|
|
|
func CheckServiceUnavailableStatus(tb testing.TB, resp *model.Response) {
|
|
tb.Helper()
|
|
checkHTTPStatus(tb, resp, http.StatusServiceUnavailable)
|
|
}
|
|
|
|
func CheckErrorID(tb testing.TB, err error, errorId string) {
|
|
tb.Helper()
|
|
|
|
require.Error(tb, err, "should have errored with id: %s", errorId)
|
|
|
|
var appError *model.AppError
|
|
ok := errors.As(err, &appError)
|
|
require.True(tb, ok, "should have been a model.AppError")
|
|
|
|
require.Equalf(tb, errorId, appError.Id, "incorrect error id, actual: %s, expected: %s", appError.Id, errorId)
|
|
}
|
|
|
|
func CheckErrorMessage(tb testing.TB, err error, message string) {
|
|
tb.Helper()
|
|
|
|
require.Error(tb, err, "should have errored with message: %s", message)
|
|
|
|
var appError *model.AppError
|
|
ok := errors.As(err, &appError)
|
|
require.True(tb, ok, "should have been a model.AppError")
|
|
|
|
require.Equalf(tb, message, appError.Message, "incorrect error message, actual: %s, expected: %s", appError.Id, message)
|
|
}
|
|
|
|
func CheckStartsWith(tb testing.TB, value, prefix, message string) {
|
|
tb.Helper()
|
|
|
|
require.True(tb, strings.HasPrefix(value, prefix), message, value)
|
|
}
|
|
|
|
// Similar to s3.New() but allows initialization of signature v2 or signature v4 client.
|
|
// If signV2 input is false, function always returns signature v4.
|
|
//
|
|
// Additionally this function also takes a user defined region, if set
|
|
// disables automatic region lookup.
|
|
func s3New(endpoint, accessKey, secretKey string, secure bool, signV2 bool, region string) (*s3.Client, error) {
|
|
var creds *credentials.Credentials
|
|
if signV2 {
|
|
creds = credentials.NewStatic(accessKey, secretKey, "", credentials.SignatureV2)
|
|
} else {
|
|
creds = credentials.NewStatic(accessKey, secretKey, "", credentials.SignatureV4)
|
|
}
|
|
|
|
opts := s3.Options{
|
|
Creds: creds,
|
|
Secure: secure,
|
|
Region: region,
|
|
}
|
|
return s3.New(endpoint, &opts)
|
|
}
|
|
|
|
func (th *TestHelper) cleanupTestFile(info *model.FileInfo) error {
|
|
cfg := th.App.Config()
|
|
if *cfg.FileSettings.DriverName == model.ImageDriverS3 {
|
|
endpoint := *cfg.FileSettings.AmazonS3Endpoint
|
|
accessKey := *cfg.FileSettings.AmazonS3AccessKeyId
|
|
secretKey := *cfg.FileSettings.AmazonS3SecretAccessKey
|
|
secure := *cfg.FileSettings.AmazonS3SSL
|
|
signV2 := *cfg.FileSettings.AmazonS3SignV2
|
|
region := *cfg.FileSettings.AmazonS3Region
|
|
s3Clnt, err := s3New(endpoint, accessKey, secretKey, secure, signV2, region)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bucket := *cfg.FileSettings.AmazonS3Bucket
|
|
if err := s3Clnt.RemoveObject(context.Background(), bucket, info.Path, s3.RemoveObjectOptions{}); err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.ThumbnailPath != "" {
|
|
if err := s3Clnt.RemoveObject(context.Background(), bucket, info.ThumbnailPath, s3.RemoveObjectOptions{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if info.PreviewPath != "" {
|
|
if err := s3Clnt.RemoveObject(context.Background(), bucket, info.PreviewPath, s3.RemoveObjectOptions{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
} else if *cfg.FileSettings.DriverName == model.ImageDriverLocal {
|
|
if err := os.Remove(*cfg.FileSettings.Directory + info.Path); err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.ThumbnailPath != "" {
|
|
if err := os.Remove(*cfg.FileSettings.Directory + info.ThumbnailPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if info.PreviewPath != "" {
|
|
if err := os.Remove(*cfg.FileSettings.Directory + info.PreviewPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (th *TestHelper) MakeUserChannelAdmin(user *model.User, channel *model.Channel) {
|
|
if cm, err := th.App.Srv().Store.Channel().GetMember(context.Background(), channel.Id, user.Id); err == nil {
|
|
cm.SchemeAdmin = true
|
|
if _, err = th.App.Srv().Store.Channel().UpdateMember(cm); err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) UpdateUserToTeamAdmin(user *model.User, team *model.Team) {
|
|
if tm, err := th.App.Srv().Store.Team().GetMember(context.Background(), team.Id, user.Id); err == nil {
|
|
tm.SchemeAdmin = true
|
|
if _, err = th.App.Srv().Store.Team().UpdateMember(tm); err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) UpdateUserToNonTeamAdmin(user *model.User, team *model.Team) {
|
|
if tm, err := th.App.Srv().Store.Team().GetMember(context.Background(), team.Id, user.Id); err == nil {
|
|
tm.SchemeAdmin = false
|
|
if _, err = th.App.Srv().Store.Team().UpdateMember(tm); err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) SaveDefaultRolePermissions() map[string][]string {
|
|
results := make(map[string][]string)
|
|
|
|
for _, roleName := range []string{
|
|
"system_user",
|
|
"system_admin",
|
|
"team_user",
|
|
"team_admin",
|
|
"channel_user",
|
|
"channel_admin",
|
|
} {
|
|
role, err1 := th.App.GetRoleByName(context.Background(), roleName)
|
|
if err1 != nil {
|
|
panic(err1)
|
|
}
|
|
|
|
results[roleName] = role.Permissions
|
|
}
|
|
return results
|
|
}
|
|
|
|
func (th *TestHelper) RestoreDefaultRolePermissions(data map[string][]string) {
|
|
for roleName, permissions := range data {
|
|
role, err1 := th.App.GetRoleByName(context.Background(), roleName)
|
|
if err1 != nil {
|
|
panic(err1)
|
|
}
|
|
|
|
if strings.Join(role.Permissions, " ") == strings.Join(permissions, " ") {
|
|
continue
|
|
}
|
|
|
|
role.Permissions = permissions
|
|
|
|
_, err2 := th.App.UpdateRole(role)
|
|
if err2 != nil {
|
|
panic(err2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) RemovePermissionFromRole(permission string, roleName string) {
|
|
role, err1 := th.App.GetRoleByName(context.Background(), roleName)
|
|
if err1 != nil {
|
|
panic(err1)
|
|
}
|
|
|
|
var newPermissions []string
|
|
for _, p := range role.Permissions {
|
|
if p != permission {
|
|
newPermissions = append(newPermissions, p)
|
|
}
|
|
}
|
|
|
|
if strings.Join(role.Permissions, " ") == strings.Join(newPermissions, " ") {
|
|
return
|
|
}
|
|
|
|
role.Permissions = newPermissions
|
|
|
|
_, err2 := th.App.UpdateRole(role)
|
|
if err2 != nil {
|
|
panic(err2)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) AddPermissionToRole(permission string, roleName string) {
|
|
role, err1 := th.App.GetRoleByName(context.Background(), roleName)
|
|
if err1 != nil {
|
|
panic(err1)
|
|
}
|
|
|
|
for _, existingPermission := range role.Permissions {
|
|
if existingPermission == permission {
|
|
return
|
|
}
|
|
}
|
|
|
|
role.Permissions = append(role.Permissions, permission)
|
|
|
|
_, err2 := th.App.UpdateRole(role)
|
|
if err2 != nil {
|
|
panic(err2)
|
|
}
|
|
}
|
|
|
|
func (th *TestHelper) SetupTeamScheme() *model.Scheme {
|
|
return th.SetupScheme(model.SchemeScopeTeam)
|
|
}
|
|
|
|
func (th *TestHelper) SetupChannelScheme() *model.Scheme {
|
|
return th.SetupScheme(model.SchemeScopeChannel)
|
|
}
|
|
|
|
func (th *TestHelper) SetupScheme(scope string) *model.Scheme {
|
|
scheme, err := th.App.CreateScheme(&model.Scheme{
|
|
Name: model.NewId(),
|
|
DisplayName: model.NewId(),
|
|
Scope: scope,
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return scheme
|
|
}
|