MM-24847 MM-24484 MM-24850 MM-24849 - local mode for commands (#14571)

* add unix socket listener for mmctl local mode

* First working PoC

* Adds the channel list endpoint

* Add team list endpoint

* Add a LocalClient to the api test helper and start local mode

* Add helper to test with both SystemAdmin and Local clients

* Add some docs

* Adds TestForAllClients test helper

* Incorporating @ashishbhate's proposal for adding test names to the helpers

* [MM-24146] Add unix socket listener for mmctl local mode (#14296)

* add unix socket listener for mmctl local mode

* add a constant for local-mode socket path

* reflect review comments

* Fix init errors after merge

* Adds create channel tests

* Always init local mode to allow for enabling-disabling it via config

* Check the RemoteAddr of the request before marking session as local

* Mark the request as errored if it's local and the origin is remote

* Set the socket permissions to read/write when initialising

* Fix linter

* Replace RemoteAddr check to ditch connections with the IP:PORT shape

* added update/move/get/delete command in local mode

* merge fix

* .

Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
Этот коммит содержится в:
Eli Yukelzon
2020-05-31 17:57:04 +03:00
коммит произвёл GitHub
родитель d1788cab85
Коммит 2af00f73c0
4 изменённых файлов: 88 добавлений и 82 удалений

Просмотреть файл

@@ -283,6 +283,7 @@ func InitLocal(configservice configservice.ConfigService, globalOptionsFunc app.
api.BaseRoutes.Plugin = api.BaseRoutes.Plugins.PathPrefix("/{plugin_id:[A-Za-z0-9\\_\\-\\.]+}").Subrouter()
api.BaseRoutes.Commands = api.BaseRoutes.ApiRoot.PathPrefix("/commands").Subrouter()
api.BaseRoutes.Command = api.BaseRoutes.Commands.PathPrefix("/{command_id:[A-Za-z0-9]+}").Subrouter()
api.BaseRoutes.License = api.BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter()

Просмотреть файл

@@ -13,6 +13,11 @@ import (
func (api *API) InitCommandLocal() {
api.BaseRoutes.Commands.Handle("", api.ApiLocal(localCreateCommand)).Methods("POST")
api.BaseRoutes.Commands.Handle("", api.ApiLocal(listCommands)).Methods("GET")
api.BaseRoutes.Command.Handle("", api.ApiLocal(getCommand)).Methods("GET")
api.BaseRoutes.Command.Handle("", api.ApiLocal(updateCommand)).Methods("PUT")
api.BaseRoutes.Command.Handle("/move", api.ApiLocal(moveCommand)).Methods("PUT")
api.BaseRoutes.Command.Handle("", api.ApiLocal(deleteCommand)).Methods("DELETE")
}
func localCreateCommand(c *Context, w http.ResponseWriter, r *http.Request) {

Просмотреть файл

@@ -77,7 +77,6 @@ func TestCreateCommand(t *testing.T) {
func TestUpdateCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
@@ -107,51 +106,51 @@ func TestUpdateCommand(t *testing.T) {
Token: "tokenchange",
}
rcmd, resp := Client.UpdateCommand(cmd2)
CheckNoError(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
rcmd, resp := client.UpdateCommand(cmd2)
CheckNoError(t, resp)
require.Equal(t, cmd2.Trigger, rcmd.Trigger, "Trigger should have updated")
require.Equal(t, cmd2.Trigger, rcmd.Trigger, "Trigger should have updated")
require.Equal(t, cmd2.Method, rcmd.Method, "Method should have updated")
require.Equal(t, cmd2.Method, rcmd.Method, "Method should have updated")
require.Equal(t, cmd2.URL, rcmd.URL, "URL should have updated")
require.Equal(t, cmd2.URL, rcmd.URL, "URL should have updated")
require.Equal(t, cmd1.CreatorId, rcmd.CreatorId, "CreatorId should have not updated")
require.Equal(t, cmd1.CreatorId, rcmd.CreatorId, "CreatorId should have not updated")
require.Equal(t, cmd1.Token, rcmd.Token, "Token should have not updated")
require.Equal(t, cmd1.Token, rcmd.Token, "Token should have not updated")
cmd2.Id = GenerateTestId()
cmd2.Id = GenerateTestId()
rcmd, resp = Client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
rcmd, resp = client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
require.Nil(t, rcmd, "should be empty")
require.Nil(t, rcmd, "should be empty")
cmd2.Id = "junk"
cmd2.Id = "junk"
_, resp = Client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
_, resp = client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
cmd2.Id = cmd1.Id
cmd2.TeamId = GenerateTestId()
cmd2.Id = cmd1.Id
cmd2.TeamId = GenerateTestId()
_, resp = Client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
_, resp = client.UpdateCommand(cmd2)
CheckBadRequestStatus(t, resp)
cmd2.TeamId = team.Id
cmd2.TeamId = team.Id
_, resp = th.Client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.UpdateCommand(cmd2)
_, resp = th.Client.UpdateCommand(cmd2)
CheckNotFoundStatus(t, resp)
})
th.SystemAdminClient.Logout()
_, resp := th.SystemAdminClient.UpdateCommand(cmd2)
CheckUnauthorizedStatus(t, resp)
}
func TestMoveCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
newTeam := th.CreateTeam()
@@ -171,23 +170,24 @@ func TestMoveCommand(t *testing.T) {
}
rcmd1, _ := th.App.CreateCommand(cmd1)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
ok, resp := Client.MoveCommand(newTeam.Id, rcmd1.Id)
CheckNoError(t, resp)
require.True(t, ok)
ok, resp := client.MoveCommand(newTeam.Id, rcmd1.Id)
CheckNoError(t, resp)
require.True(t, ok)
rcmd1, _ = th.App.GetCommand(rcmd1.Id)
require.NotNil(t, rcmd1)
require.Equal(t, newTeam.Id, rcmd1.TeamId)
rcmd1, _ = th.App.GetCommand(rcmd1.Id)
require.NotNil(t, rcmd1)
require.Equal(t, newTeam.Id, rcmd1.TeamId)
ok, resp = Client.MoveCommand(newTeam.Id, "bogus")
CheckBadRequestStatus(t, resp)
require.False(t, ok)
ok, resp = Client.MoveCommand(GenerateTestId(), rcmd1.Id)
CheckNotFoundStatus(t, resp)
require.False(t, ok)
ok, resp = client.MoveCommand(newTeam.Id, "bogus")
CheckBadRequestStatus(t, resp)
require.False(t, ok)
ok, resp = client.MoveCommand(GenerateTestId(), rcmd1.Id)
CheckNotFoundStatus(t, resp)
require.False(t, ok)
})
cmd2 := &model.Command{
CreatorId: user.Id,
TeamId: team.Id,
@@ -198,18 +198,17 @@ func TestMoveCommand(t *testing.T) {
rcmd2, _ := th.App.CreateCommand(cmd2)
_, resp = th.Client.MoveCommand(newTeam.Id, rcmd2.Id)
_, resp := th.Client.MoveCommand(newTeam.Id, rcmd2.Id)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.MoveCommand(newTeam.Id, rcmd2.Id)
th.SystemAdminClient.Logout()
_, resp = th.SystemAdminClient.MoveCommand(newTeam.Id, rcmd2.Id)
CheckUnauthorizedStatus(t, resp)
}
func TestDeleteCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.BasicTeam
@@ -227,24 +226,26 @@ func TestDeleteCommand(t *testing.T) {
Trigger: "trigger1",
}
rcmd1, _ := th.App.CreateCommand(cmd1)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
cmd1.Id = ""
rcmd1, err := th.App.CreateCommand(cmd1)
require.Nil(t, err)
ok, resp := client.DeleteCommand(rcmd1.Id)
CheckNoError(t, resp)
ok, resp := Client.DeleteCommand(rcmd1.Id)
CheckNoError(t, resp)
require.True(t, ok)
require.True(t, ok)
rcmd1, _ = th.App.GetCommand(rcmd1.Id)
require.Nil(t, rcmd1)
rcmd1, _ = th.App.GetCommand(rcmd1.Id)
require.Nil(t, rcmd1)
ok, resp = client.DeleteCommand("junk")
CheckBadRequestStatus(t, resp)
ok, resp = Client.DeleteCommand("junk")
CheckBadRequestStatus(t, resp)
require.False(t, ok)
_, resp = Client.DeleteCommand(GenerateTestId())
CheckNotFoundStatus(t, resp)
require.False(t, ok)
_, resp = client.DeleteCommand(GenerateTestId())
CheckNotFoundStatus(t, resp)
})
cmd2 := &model.Command{
CreatorId: user.Id,
TeamId: team.Id,
@@ -255,11 +256,11 @@ func TestDeleteCommand(t *testing.T) {
rcmd2, _ := th.App.CreateCommand(cmd2)
_, resp = th.Client.DeleteCommand(rcmd2.Id)
_, resp := th.Client.DeleteCommand(rcmd2.Id)
CheckNotFoundStatus(t, resp)
Client.Logout()
_, resp = Client.DeleteCommand(rcmd2.Id)
th.SystemAdminClient.Logout()
_, resp = th.SystemAdminClient.DeleteCommand(rcmd2.Id)
CheckUnauthorizedStatus(t, resp)
}
@@ -513,7 +514,6 @@ func TestListCommandAutocompleteSuggestions(t *testing.T) {
func TestGetCommand(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
Client := th.Client
enableCommands := *th.App.Config().ServiceSettings.EnableCommands
defer func() {
@@ -530,41 +530,42 @@ func TestGetCommand(t *testing.T) {
newCmd, resp := th.SystemAdminClient.CreateCommand(newCmd)
CheckNoError(t, resp)
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
t.Run("ValidId", func(t *testing.T) {
cmd, resp := th.SystemAdminClient.GetCommandById(newCmd.Id)
CheckNoError(t, resp)
t.Run("ValidId", func(t *testing.T) {
cmd, resp := client.GetCommandById(newCmd.Id)
CheckNoError(t, resp)
require.Equal(t, newCmd.Id, cmd.Id)
require.Equal(t, newCmd.CreatorId, cmd.CreatorId)
require.Equal(t, newCmd.TeamId, cmd.TeamId)
require.Equal(t, newCmd.URL, cmd.URL)
require.Equal(t, newCmd.Method, cmd.Method)
require.Equal(t, newCmd.Trigger, cmd.Trigger)
require.Equal(t, newCmd.Id, cmd.Id)
require.Equal(t, newCmd.CreatorId, cmd.CreatorId)
require.Equal(t, newCmd.TeamId, cmd.TeamId)
require.Equal(t, newCmd.URL, cmd.URL)
require.Equal(t, newCmd.Method, cmd.Method)
require.Equal(t, newCmd.Trigger, cmd.Trigger)
})
t.Run("InvalidId", func(t *testing.T) {
_, resp := client.GetCommandById(strings.Repeat("z", len(newCmd.Id)))
require.Error(t, resp.Error)
})
})
t.Run("InvalidId", func(t *testing.T) {
_, resp := th.SystemAdminClient.GetCommandById(strings.Repeat("z", len(newCmd.Id)))
require.Error(t, resp.Error)
})
t.Run("UserWithNoPermissionForCustomCommands", func(t *testing.T) {
_, resp := Client.GetCommandById(newCmd.Id)
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckNotFoundStatus(t, resp)
})
t.Run("NoMember", func(t *testing.T) {
Client.Logout()
th.Client.Logout()
user := th.CreateUser()
th.SystemAdminClient.RemoveTeamMember(th.BasicTeam.Id, user.Id)
Client.Login(user.Email, user.Password)
_, resp := Client.GetCommandById(newCmd.Id)
th.Client.Login(user.Email, user.Password)
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckNotFoundStatus(t, resp)
})
t.Run("NotLoggedIn", func(t *testing.T) {
Client.Logout()
_, resp := Client.GetCommandById(newCmd.Id)
th.Client.Logout()
_, resp := th.Client.GetCommandById(newCmd.Id)
CheckUnauthorizedStatus(t, resp)
})
}