mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-03 20:40:00 -05:00
* Add mutex to model.Post to guard against race conditions on Post.Props * Rename mutex * Add GetProp() method to Post * Fix more tests * Fix flaky test Benchmarks: BenchmarkPostPropsGet_indirect BenchmarkPostPropsGet_indirect-2 85026746 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-4 90273747 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-8 88324293 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-16 91427720 13.1 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct BenchmarkPostPropsGet_direct-2 1000000000 0.242 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-4 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-8 1000000000 0.240 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-16 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_indirect BenchmarkPostPropsAdd_indirect-2 5602224 203 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-4 5959496 206 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-8 5833999 205 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-16 5802493 225 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_direct BenchmarkPostPropsAdd_direct-2 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-4 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-8 100000000 11.6 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-16 99840794 11.4 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_indirect BenchmarkPostPropsDel_indirect-2 18824002 61.9 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-4 19470736 63.8 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-8 17640460 65.3 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-16 18692962 65.4 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_direct BenchmarkPostPropsDel_direct-2 516257440 2.34 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-4 514865216 2.43 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-8 511330477 2.37 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-16 499504010 2.38 ns/op 0 B/op 0 allocs/op
321 lines
6.9 KiB
Go
321 lines
6.9 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
func TestPluginDeadlock(t *testing.T) {
|
|
t.Run("Single Plugin", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
pluginPostOnActivate := template.Must(template.New("pluginPostOnActivate").Parse(`
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func (p *MyPlugin) OnActivate() error {
|
|
_, err := p.API.CreatePost(&model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "message",
|
|
})
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
|
if _, from_plugin := post.GetProps()["from_plugin"]; from_plugin {
|
|
return nil, ""
|
|
}
|
|
|
|
p.API.CreatePost(&model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "message",
|
|
Props: map[string]interface{}{
|
|
"from_plugin": true,
|
|
},
|
|
})
|
|
|
|
return nil, ""
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`,
|
|
))
|
|
|
|
templateData := struct {
|
|
User *model.User
|
|
Channel *model.Channel
|
|
}{
|
|
th.BasicUser,
|
|
th.BasicChannel,
|
|
}
|
|
|
|
plugins := []string{}
|
|
pluginTemplates := []*template.Template{
|
|
pluginPostOnActivate,
|
|
}
|
|
for _, pluginTemplate := range pluginTemplates {
|
|
b := &strings.Builder{}
|
|
pluginTemplate.Execute(b, templateData)
|
|
|
|
plugins = append(plugins, b.String())
|
|
}
|
|
|
|
done := make(chan bool)
|
|
go func() {
|
|
SetAppEnvironmentWithPlugins(t, plugins, th.App, th.App.NewPluginAPI)
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(30 * time.Second):
|
|
require.Fail(t, "plugin failed to activate: likely deadlocked")
|
|
go func() {
|
|
time.Sleep(5 * time.Second)
|
|
os.Exit(1)
|
|
}()
|
|
}
|
|
})
|
|
|
|
t.Run("Multiple Plugins", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
defer th.TearDown()
|
|
|
|
pluginPostOnHasBeenPosted := template.Must(template.New("pluginPostOnHasBeenPosted").Parse(`
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
|
if _, from_plugin := post.GetProps()["from_plugin"]; from_plugin {
|
|
return nil, ""
|
|
}
|
|
|
|
p.API.CreatePost(&model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "message",
|
|
Props: map[string]interface{}{
|
|
"from_plugin": true,
|
|
},
|
|
})
|
|
|
|
return nil, ""
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`,
|
|
))
|
|
|
|
pluginPostOnActivate := template.Must(template.New("pluginPostOnActivate").Parse(`
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func (p *MyPlugin) OnActivate() error {
|
|
_, err := p.API.CreatePost(&model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "message",
|
|
})
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`,
|
|
))
|
|
|
|
templateData := struct {
|
|
User *model.User
|
|
Channel *model.Channel
|
|
}{
|
|
th.BasicUser,
|
|
th.BasicChannel,
|
|
}
|
|
|
|
plugins := []string{}
|
|
pluginTemplates := []*template.Template{
|
|
pluginPostOnHasBeenPosted,
|
|
pluginPostOnActivate,
|
|
}
|
|
for _, pluginTemplate := range pluginTemplates {
|
|
b := &strings.Builder{}
|
|
pluginTemplate.Execute(b, templateData)
|
|
|
|
plugins = append(plugins, b.String())
|
|
}
|
|
|
|
done := make(chan bool)
|
|
go func() {
|
|
SetAppEnvironmentWithPlugins(t, plugins, th.App, th.App.NewPluginAPI)
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(30 * time.Second):
|
|
require.Fail(t, "plugin failed to activate: likely deadlocked")
|
|
go func() {
|
|
time.Sleep(5 * time.Second)
|
|
os.Exit(1)
|
|
}()
|
|
}
|
|
})
|
|
|
|
t.Run("CreatePost on OnDeactivate Plugin", func(t *testing.T) {
|
|
th := Setup(t).InitBasic()
|
|
|
|
pluginPostOnActivate := template.Must(template.New("pluginPostOnActivate").Parse(`
|
|
package main
|
|
|
|
import (
|
|
"github.com/mattermost/mattermost-server/v5/plugin"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
)
|
|
|
|
type MyPlugin struct {
|
|
plugin.MattermostPlugin
|
|
}
|
|
|
|
func (p *MyPlugin) OnDeactivate() error {
|
|
_, err := p.API.CreatePost(&model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "OnDeactivate",
|
|
})
|
|
if err != nil {
|
|
panic(err.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
|
updatedPost := &model.Post{
|
|
UserId: "{{.User.Id}}",
|
|
ChannelId: "{{.Channel.Id}}",
|
|
Message: "messageUpdated",
|
|
Props: map[string]interface{}{
|
|
"from_plugin": true,
|
|
},
|
|
}
|
|
|
|
return updatedPost, ""
|
|
}
|
|
|
|
func main() {
|
|
plugin.ClientMain(&MyPlugin{})
|
|
}
|
|
`,
|
|
))
|
|
|
|
templateData := struct {
|
|
User *model.User
|
|
Channel *model.Channel
|
|
}{
|
|
th.BasicUser,
|
|
th.BasicChannel,
|
|
}
|
|
|
|
plugins := []string{}
|
|
pluginTemplates := []*template.Template{
|
|
pluginPostOnActivate,
|
|
}
|
|
for _, pluginTemplate := range pluginTemplates {
|
|
b := &strings.Builder{}
|
|
pluginTemplate.Execute(b, templateData)
|
|
|
|
plugins = append(plugins, b.String())
|
|
}
|
|
|
|
done := make(chan bool)
|
|
go func() {
|
|
posts, appErr := th.App.GetPosts(th.BasicChannel.Id, 0, 2)
|
|
require.Nil(t, appErr)
|
|
require.NotNil(t, posts)
|
|
|
|
messageWillBePostedCalled := false
|
|
for _, p := range posts.Posts {
|
|
if p.Message == "messageUpdated" {
|
|
messageWillBePostedCalled = true
|
|
}
|
|
}
|
|
require.False(t, messageWillBePostedCalled, "MessageWillBePosted should not have been called")
|
|
|
|
SetAppEnvironmentWithPlugins(t, plugins, th.App, th.App.NewPluginAPI)
|
|
th.TearDown()
|
|
|
|
posts, appErr = th.App.GetPosts(th.BasicChannel.Id, 0, 2)
|
|
require.Nil(t, appErr)
|
|
require.NotNil(t, posts)
|
|
|
|
messageWillBePostedCalled = false
|
|
for _, p := range posts.Posts {
|
|
if p.Message == "messageUpdated" {
|
|
messageWillBePostedCalled = true
|
|
}
|
|
}
|
|
require.True(t, messageWillBePostedCalled, "MessageWillBePosted was not called on deactivate")
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(30 * time.Second):
|
|
require.Fail(t, "plugin failed to activate: likely deadlocked")
|
|
go func() {
|
|
time.Sleep(5 * time.Second)
|
|
os.Exit(1)
|
|
}()
|
|
}
|
|
})
|
|
}
|