github.com/nhannv/mattermost-server@v5.11.1+incompatible/app/plugin_deadlock_test.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "os" 8 "strings" 9 "testing" 10 "text/template" 11 "time" 12 13 "github.com/mattermost/mattermost-server/model" 14 ) 15 16 func TestPluginDeadlock(t *testing.T) { 17 t.Run("Single Plugin", func(t *testing.T) { 18 th := Setup(t).InitBasic() 19 defer th.TearDown() 20 21 pluginPostOnActivate := template.Must(template.New("pluginPostOnActivate").Parse(` 22 package main 23 24 import ( 25 "github.com/mattermost/mattermost-server/plugin" 26 "github.com/mattermost/mattermost-server/model" 27 ) 28 29 type MyPlugin struct { 30 plugin.MattermostPlugin 31 } 32 33 func (p *MyPlugin) OnActivate() error { 34 _, err := p.API.CreatePost(&model.Post{ 35 UserId: "{{.User.Id}}", 36 ChannelId: "{{.Channel.Id}}", 37 Message: "message", 38 }) 39 if err != nil { 40 panic(err.Error()) 41 } 42 43 return nil 44 } 45 46 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 47 if _, from_plugin := post.Props["from_plugin"]; from_plugin { 48 return nil, "" 49 } 50 51 p.API.CreatePost(&model.Post{ 52 UserId: "{{.User.Id}}", 53 ChannelId: "{{.Channel.Id}}", 54 Message: "message", 55 Props: map[string]interface{}{ 56 "from_plugin": true, 57 }, 58 }) 59 60 return nil, "" 61 } 62 63 func main() { 64 plugin.ClientMain(&MyPlugin{}) 65 } 66 `, 67 )) 68 69 templateData := struct { 70 User *model.User 71 Channel *model.Channel 72 }{ 73 th.BasicUser, 74 th.BasicChannel, 75 } 76 77 plugins := []string{} 78 pluginTemplates := []*template.Template{ 79 pluginPostOnActivate, 80 } 81 for _, pluginTemplate := range pluginTemplates { 82 b := &strings.Builder{} 83 pluginTemplate.Execute(b, templateData) 84 85 plugins = append(plugins, b.String()) 86 } 87 88 done := make(chan bool) 89 go func() { 90 SetAppEnvironmentWithPlugins(t, plugins, th.App, th.App.NewPluginAPI) 91 close(done) 92 }() 93 94 select { 95 case <-done: 96 case <-time.After(30 * time.Second): 97 t.Fatal("plugin failed to activate: likely deadlocked") 98 go func() { 99 time.Sleep(5 * time.Second) 100 os.Exit(1) 101 }() 102 } 103 }) 104 105 t.Run("Multiple Plugins", func(t *testing.T) { 106 th := Setup(t).InitBasic() 107 defer th.TearDown() 108 109 pluginPostOnHasBeenPosted := template.Must(template.New("pluginPostOnHasBeenPosted").Parse(` 110 package main 111 112 import ( 113 "github.com/mattermost/mattermost-server/plugin" 114 "github.com/mattermost/mattermost-server/model" 115 ) 116 117 type MyPlugin struct { 118 plugin.MattermostPlugin 119 } 120 121 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 122 if _, from_plugin := post.Props["from_plugin"]; from_plugin { 123 return nil, "" 124 } 125 126 p.API.CreatePost(&model.Post{ 127 UserId: "{{.User.Id}}", 128 ChannelId: "{{.Channel.Id}}", 129 Message: "message", 130 Props: map[string]interface{}{ 131 "from_plugin": true, 132 }, 133 }) 134 135 return nil, "" 136 } 137 138 func main() { 139 plugin.ClientMain(&MyPlugin{}) 140 } 141 `, 142 )) 143 144 pluginPostOnActivate := template.Must(template.New("pluginPostOnActivate").Parse(` 145 package main 146 147 import ( 148 "github.com/mattermost/mattermost-server/plugin" 149 "github.com/mattermost/mattermost-server/model" 150 ) 151 152 type MyPlugin struct { 153 plugin.MattermostPlugin 154 } 155 156 func (p *MyPlugin) OnActivate() error { 157 _, err := p.API.CreatePost(&model.Post{ 158 UserId: "{{.User.Id}}", 159 ChannelId: "{{.Channel.Id}}", 160 Message: "message", 161 }) 162 if err != nil { 163 panic(err.Error()) 164 } 165 166 return nil 167 } 168 169 func main() { 170 plugin.ClientMain(&MyPlugin{}) 171 } 172 `, 173 )) 174 175 templateData := struct { 176 User *model.User 177 Channel *model.Channel 178 }{ 179 th.BasicUser, 180 th.BasicChannel, 181 } 182 183 plugins := []string{} 184 pluginTemplates := []*template.Template{ 185 pluginPostOnHasBeenPosted, 186 pluginPostOnActivate, 187 } 188 for _, pluginTemplate := range pluginTemplates { 189 b := &strings.Builder{} 190 pluginTemplate.Execute(b, templateData) 191 192 plugins = append(plugins, b.String()) 193 } 194 195 done := make(chan bool) 196 go func() { 197 SetAppEnvironmentWithPlugins(t, plugins, th.App, th.App.NewPluginAPI) 198 close(done) 199 }() 200 201 select { 202 case <-done: 203 case <-time.After(30 * time.Second): 204 t.Fatal("plugin failed to activate: likely deadlocked") 205 go func() { 206 time.Sleep(5 * time.Second) 207 os.Exit(1) 208 }() 209 } 210 }) 211 }