diff options
Diffstat (limited to 'api4')
-rw-r--r-- | api4/api.go | 6 | ||||
-rw-r--r-- | api4/api_test.go | 48 | ||||
-rw-r--r-- | api4/apitestlib.go | 102 | ||||
-rw-r--r-- | api4/channel.go | 5 | ||||
-rw-r--r-- | api4/command_test.go | 7 | ||||
-rw-r--r-- | api4/user.go | 20 | ||||
-rw-r--r-- | api4/user_test.go | 45 |
7 files changed, 191 insertions, 42 deletions
diff --git a/api4/api.go b/api4/api.go index c712b67f2..3c1d68384 100644 --- a/api4/api.go +++ b/api4/api.go @@ -109,12 +109,6 @@ type API struct { BaseRoutes *Routes } -func NewRouter() *mux.Router { - ret := mux.NewRouter() - ret.NotFoundHandler = http.HandlerFunc(Handle404) - return ret -} - func Init(a *app.App, root *mux.Router, full bool) *API { api := &API{ App: a, diff --git a/api4/api_test.go b/api4/api_test.go new file mode 100644 index 000000000..8a8753a4f --- /dev/null +++ b/api4/api_test.go @@ -0,0 +1,48 @@ +// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +package api4 + +import ( + "flag" + "os" + "testing" + + l4g "github.com/alecthomas/log4go" + + "github.com/mattermost/mattermost-server/store/storetest" + "github.com/mattermost/mattermost-server/utils" +) + +func TestMain(m *testing.M) { + flag.Parse() + + // In the case where a dev just wants to run a single test, it's faster to just use the default + // store. + if filter := flag.Lookup("test.run").Value.String(); filter != "" && filter != "." { + utils.TranslationsPreInit() + utils.LoadConfig("config.json") + l4g.Info("-test.run used, not creating temporary containers") + os.Exit(m.Run()) + } + + utils.TranslationsPreInit() + utils.LoadConfig("config.json") + utils.InitTranslations(utils.Cfg.LocalizationSettings) + + status := 0 + + container, settings, err := storetest.NewMySQLContainer() + if err != nil { + panic(err) + } + + UseTestStore(container, settings) + + defer func() { + StopTestStore() + os.Exit(status) + }() + + status = m.Run() +} diff --git a/api4/apitestlib.go b/api4/apitestlib.go index f50095f79..640f38fe6 100644 --- a/api4/apitestlib.go +++ b/api4/apitestlib.go @@ -22,6 +22,8 @@ import ( "github.com/mattermost/mattermost-server/app" "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/store" + "github.com/mattermost/mattermost-server/store/sqlstore" + "github.com/mattermost/mattermost-server/store/storetest" "github.com/mattermost/mattermost-server/utils" "github.com/mattermost/mattermost-server/wsapi" @@ -46,39 +48,66 @@ type TestHelper struct { SystemAdminUser *model.User } -func setupTestHelper(enterprise bool) *TestHelper { - th := &TestHelper{ - App: app.New(), +type persistentTestStore struct { + store.Store +} + +func (*persistentTestStore) Close() {} + +var testStoreContainer *storetest.RunningContainer +var testStore *persistentTestStore + +// UseTestStore sets the container and corresponding settings to use for tests. Once the tests are +// complete (e.g. at the end of your TestMain implementation), you should call StopTestStore. +func UseTestStore(container *storetest.RunningContainer, settings *model.SqlSettings) { + testStoreContainer = container + testStore = &persistentTestStore{store.NewLayeredStore(sqlstore.NewSqlSupplier(*settings, nil), nil, nil)} +} + +func StopTestStore() { + if testStoreContainer != nil { + testStoreContainer.Stop() + testStoreContainer = nil } +} - if th.App.Srv == nil { +func setupTestHelper(enterprise bool) *TestHelper { + if utils.T == nil { utils.TranslationsPreInit() - utils.LoadConfig("config.json") - utils.InitTranslations(utils.Cfg.LocalizationSettings) - *utils.Cfg.TeamSettings.MaxUsersPerTeam = 50 - *utils.Cfg.RateLimitSettings.Enable = false - utils.Cfg.EmailSettings.SendEmailNotifications = true - utils.DisableDebugLogForTest() - th.App.NewServer() - th.App.InitStores() - th.App.Srv.Router = NewRouter() - th.App.Srv.WebSocketRouter = th.App.NewWebSocketRouter() - th.App.StartServer() - Init(th.App, th.App.Srv.Router, true) - wsapi.Init(th.App, th.App.Srv.WebSocketRouter) - utils.EnableDebugLogForTest() - th.App.Srv.Store.MarkSystemRanUnitTests() + } + utils.LoadConfig("config.json") + utils.InitTranslations(utils.Cfg.LocalizationSettings) - *utils.Cfg.TeamSettings.EnableOpenServer = true + var options []app.Option + if testStore != nil { + options = append(options, app.StoreOverride(testStore)) + options = append(options, app.ConfigOverride(func(cfg *model.Config) { + cfg.ServiceSettings.ListenAddress = new(string) + *cfg.ServiceSettings.ListenAddress = ":0" + })) + } + + th := &TestHelper{ + App: app.New(options...), } + *utils.Cfg.TeamSettings.MaxUsersPerTeam = 50 + *utils.Cfg.RateLimitSettings.Enable = false + utils.Cfg.EmailSettings.SendEmailNotifications = true + utils.DisableDebugLogForTest() + th.App.StartServer() + Init(th.App, th.App.Srv.Router, true) + wsapi.Init(th.App, th.App.Srv.WebSocketRouter) + utils.EnableDebugLogForTest() + th.App.Srv.Store.MarkSystemRanUnitTests() + + *utils.Cfg.TeamSettings.EnableOpenServer = true + utils.SetIsLicensed(enterprise) if enterprise { utils.License().Features.SetDefaults() } - th.App.Jobs.Store = th.App.Srv.Store - th.Client = th.CreateClient() th.SystemAdminClient = th.CreateClient() return th @@ -150,23 +179,18 @@ func (me *TestHelper) TearDown() { me.App.Shutdown() utils.EnableDebugLogForTest() -} -func (me *TestHelper) waitForConnectivity() { - for i := 0; i < 1000; i++ { - _, err := net.Dial("tcp", "localhost"+*utils.Cfg.ServiceSettings.ListenAddress) - if err == nil { - return - } - time.Sleep(time.Millisecond * 20) + if err := recover(); err != nil { + StopTestStore() + panic(err) } - panic("unable to connect") } func (me *TestHelper) InitBasic() *TestHelper { me.waitForConnectivity() me.TeamAdminUser = me.CreateUser() + me.App.UpdateUserRoles(me.TeamAdminUser.Id, model.ROLE_SYSTEM_USER.Id) me.LoginTeamAdmin() me.BasicTeam = me.CreateTeam() me.BasicChannel = me.CreatePublicChannel() @@ -199,12 +223,24 @@ func (me *TestHelper) InitSystemAdmin() *TestHelper { return me } +func (me *TestHelper) waitForConnectivity() { + for i := 0; i < 1000; i++ { + conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", me.App.Srv.ListenAddr.Port)) + if err == nil { + conn.Close() + return + } + time.Sleep(time.Millisecond * 20) + } + panic("unable to connect") +} + func (me *TestHelper) CreateClient() *model.Client4 { - return model.NewAPIv4Client("http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress) + return model.NewAPIv4Client(fmt.Sprintf("http://localhost:%v", me.App.Srv.ListenAddr.Port)) } func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) { - return model.NewWebSocketClient4("ws://localhost"+*utils.Cfg.ServiceSettings.ListenAddress, me.Client.AuthToken) + return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", me.App.Srv.ListenAddr.Port), me.Client.AuthToken) } func (me *TestHelper) CreateUser() *model.User { diff --git a/api4/channel.go b/api4/channel.go index 7a1324883..07e48b46f 100644 --- a/api4/channel.go +++ b/api4/channel.go @@ -826,6 +826,11 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) { return } + if channel.Type == model.CHANNEL_DIRECT || channel.Type == model.CHANNEL_GROUP { + c.Err = model.NewAppError("addUserToChannel", "api.channel.add_user_to_channel.type.app_error", nil, "", http.StatusBadRequest) + return + } + if cm, err := c.App.AddChannelMember(member.UserId, channel, c.Session.UserId); err != nil { c.Err = err return diff --git a/api4/command_test.go b/api4/command_test.go index 9a6c9dc78..52ef0f841 100644 --- a/api4/command_test.go +++ b/api4/command_test.go @@ -4,6 +4,7 @@ package api4 import ( + "fmt" "strings" "testing" @@ -399,7 +400,7 @@ func TestExecuteCommand(t *testing.T) { postCmd := &model.Command{ CreatorId: th.BasicUser.Id, TeamId: th.BasicTeam.Id, - URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test", + URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test", Method: model.COMMAND_METHOD_POST, Trigger: "postcommand", } @@ -443,7 +444,7 @@ func TestExecuteCommand(t *testing.T) { getCmd := &model.Command{ CreatorId: th.BasicUser.Id, TeamId: th.BasicTeam.Id, - URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test", + URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test", Method: model.COMMAND_METHOD_GET, Trigger: "getcommand", } @@ -511,7 +512,7 @@ func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) { postCmd := &model.Command{ CreatorId: th.BasicUser.Id, TeamId: team2.Id, - URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test", + URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test", Method: model.COMMAND_METHOD_POST, Trigger: "postcommand", } diff --git a/api4/user.go b/api4/user.go index ae1b2418c..07f223bd6 100644 --- a/api4/user.go +++ b/api4/user.go @@ -53,6 +53,7 @@ func (api *API) InitUser() { api.BaseRoutes.User.Handle("/sessions", api.ApiSessionRequired(getSessions)).Methods("GET") api.BaseRoutes.User.Handle("/sessions/revoke", api.ApiSessionRequired(revokeSession)).Methods("POST") + api.BaseRoutes.User.Handle("/sessions/revoke/all", api.ApiSessionRequired(revokeAllSessionsForUser)).Methods("POST") api.BaseRoutes.Users.Handle("/sessions/device", api.ApiSessionRequired(attachDeviceId)).Methods("PUT") api.BaseRoutes.User.Handle("/audits", api.ApiSessionRequired(getUserAudits)).Methods("GET") @@ -986,6 +987,25 @@ func revokeSession(c *Context, w http.ResponseWriter, r *http.Request) { ReturnStatusOK(w) } +func revokeAllSessionsForUser(c *Context, w http.ResponseWriter, r *http.Request) { + c.RequireUserId() + if c.Err != nil { + return + } + + if !app.SessionHasPermissionToUser(c.Session, c.Params.UserId) { + c.SetPermissionError(model.PERMISSION_EDIT_OTHER_USERS) + return + } + + if err := c.App.RevokeAllSessions(c.Params.UserId); err != nil { + c.Err = err + return + } + + ReturnStatusOK(w) +} + func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { props := model.MapFromJson(r.Body) diff --git a/api4/user_test.go b/api4/user_test.go index 0913819cc..3a1579e14 100644 --- a/api4/user_test.go +++ b/api4/user_test.go @@ -1971,6 +1971,51 @@ func TestRevokeSessions(t *testing.T) { CheckNoError(t, resp) } +func TestRevokeAllSessions(t *testing.T) { + th := Setup().InitBasic() + defer th.TearDown() + Client := th.Client + + user := th.BasicUser + Client.Login(user.Email, user.Password) + + _, resp := Client.RevokeAllSessions(th.BasicUser2.Id) + CheckForbiddenStatus(t, resp) + + th.InitSystemAdmin() + + _, resp = Client.RevokeAllSessions("junk" + user.Id) + CheckBadRequestStatus(t, resp) + + status, resp := Client.RevokeAllSessions(user.Id) + if status == false { + t.Fatal("user all sessions revoke unsuccessful") + } + CheckNoError(t, resp) + + Client.Logout() + _, resp = Client.RevokeAllSessions(user.Id) + CheckUnauthorizedStatus(t, resp) + + Client.Login(user.Email, user.Password) + + sessions, _ := Client.GetSessions(user.Id, "") + if len(sessions) < 1 { + t.Fatal("session should exist") + } + + _, resp = Client.RevokeAllSessions(user.Id) + CheckNoError(t, resp) + + sessions, _ = th.SystemAdminClient.GetSessions(user.Id, "") + if len(sessions) != 0 { + t.Fatal("no sessions should exist for user") + } + + _, resp = Client.RevokeAllSessions(user.Id) + CheckUnauthorizedStatus(t, resp) +} + func TestAttachDeviceId(t *testing.T) { th := Setup().InitBasic() defer th.TearDown() |