github.com/nhannv/mattermost-server@v5.11.1+incompatible/app/plugin_hooks_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 "bytes" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "net/http/httptest" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "strings" 16 "testing" 17 "time" 18 19 "github.com/pkg/errors" 20 21 "github.com/mattermost/mattermost-server/model" 22 "github.com/mattermost/mattermost-server/plugin" 23 "github.com/mattermost/mattermost-server/plugin/plugintest" 24 "github.com/mattermost/mattermost-server/plugin/plugintest/mock" 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func compileGo(t *testing.T, sourceCode, outputPath string) { 30 dir, err := ioutil.TempDir(".", "") 31 require.NoError(t, err) 32 defer os.RemoveAll(dir) 33 require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(sourceCode), 0600)) 34 cmd := exec.Command("go", "build", "-o", outputPath, "main.go") 35 cmd.Dir = dir 36 cmd.Stdout = os.Stdout 37 cmd.Stderr = os.Stderr 38 require.NoError(t, cmd.Run(), "failed to compile go") 39 } 40 41 func SetAppEnvironmentWithPlugins(t *testing.T, pluginCode []string, app *App, apiFunc func(*model.Manifest) plugin.API) (func(), []string, []error) { 42 pluginDir, err := ioutil.TempDir("", "") 43 require.NoError(t, err) 44 webappPluginDir, err := ioutil.TempDir("", "") 45 require.NoError(t, err) 46 47 env, err := plugin.NewEnvironment(apiFunc, pluginDir, webappPluginDir, app.Log) 48 require.NoError(t, err) 49 50 app.SetPluginsEnvironment(env) 51 pluginIds := []string{} 52 activationErrors := []error{} 53 for _, code := range pluginCode { 54 pluginId := model.NewId() 55 backend := filepath.Join(pluginDir, pluginId, "backend.exe") 56 compileGo(t, code, backend) 57 58 ioutil.WriteFile(filepath.Join(pluginDir, pluginId, "plugin.json"), []byte(`{"id": "`+pluginId+`", "backend": {"executable": "backend.exe"}}`), 0600) 59 _, _, activationErr := env.Activate(pluginId) 60 pluginIds = append(pluginIds, pluginId) 61 activationErrors = append(activationErrors, activationErr) 62 } 63 64 return func() { 65 os.RemoveAll(pluginDir) 66 os.RemoveAll(webappPluginDir) 67 }, pluginIds, activationErrors 68 } 69 70 func TestHookMessageWillBePosted(t *testing.T) { 71 t.Run("rejected", func(t *testing.T) { 72 th := Setup(t).InitBasic() 73 defer th.TearDown() 74 75 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 76 ` 77 package main 78 79 import ( 80 "github.com/mattermost/mattermost-server/plugin" 81 "github.com/mattermost/mattermost-server/model" 82 ) 83 84 type MyPlugin struct { 85 plugin.MattermostPlugin 86 } 87 88 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 89 return nil, "rejected" 90 } 91 92 func main() { 93 plugin.ClientMain(&MyPlugin{}) 94 } 95 `, 96 }, th.App, th.App.NewPluginAPI) 97 defer tearDown() 98 99 post := &model.Post{ 100 UserId: th.BasicUser.Id, 101 ChannelId: th.BasicChannel.Id, 102 Message: "message_", 103 CreateAt: model.GetMillis() - 10000, 104 } 105 _, err := th.App.CreatePost(post, th.BasicChannel, false) 106 if assert.NotNil(t, err) { 107 assert.Equal(t, "Post rejected by plugin. rejected", err.Message) 108 } 109 }) 110 111 t.Run("rejected, returned post ignored", func(t *testing.T) { 112 th := Setup(t).InitBasic() 113 defer th.TearDown() 114 115 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 116 ` 117 package main 118 119 import ( 120 "github.com/mattermost/mattermost-server/plugin" 121 "github.com/mattermost/mattermost-server/model" 122 ) 123 124 type MyPlugin struct { 125 plugin.MattermostPlugin 126 } 127 128 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 129 post.Message = "ignored" 130 return post, "rejected" 131 } 132 133 func main() { 134 plugin.ClientMain(&MyPlugin{}) 135 } 136 `, 137 }, th.App, th.App.NewPluginAPI) 138 defer tearDown() 139 140 post := &model.Post{ 141 UserId: th.BasicUser.Id, 142 ChannelId: th.BasicChannel.Id, 143 Message: "message_", 144 CreateAt: model.GetMillis() - 10000, 145 } 146 _, err := th.App.CreatePost(post, th.BasicChannel, false) 147 if assert.NotNil(t, err) { 148 assert.Equal(t, "Post rejected by plugin. rejected", err.Message) 149 } 150 }) 151 152 t.Run("allowed", func(t *testing.T) { 153 th := Setup(t).InitBasic() 154 defer th.TearDown() 155 156 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 157 ` 158 package main 159 160 import ( 161 "github.com/mattermost/mattermost-server/plugin" 162 "github.com/mattermost/mattermost-server/model" 163 ) 164 165 type MyPlugin struct { 166 plugin.MattermostPlugin 167 } 168 169 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 170 return nil, "" 171 } 172 173 func main() { 174 plugin.ClientMain(&MyPlugin{}) 175 } 176 `, 177 }, th.App, th.App.NewPluginAPI) 178 defer tearDown() 179 180 post := &model.Post{ 181 UserId: th.BasicUser.Id, 182 ChannelId: th.BasicChannel.Id, 183 Message: "message", 184 CreateAt: model.GetMillis() - 10000, 185 } 186 post, err := th.App.CreatePost(post, th.BasicChannel, false) 187 if err != nil { 188 t.Fatal(err) 189 } 190 assert.Equal(t, "message", post.Message) 191 if result := <-th.App.Srv.Store.Post().GetSingle(post.Id); result.Err != nil { 192 t.Fatal(err) 193 } else { 194 assert.Equal(t, "message", result.Data.(*model.Post).Message) 195 } 196 }) 197 198 t.Run("updated", func(t *testing.T) { 199 th := Setup(t).InitBasic() 200 defer th.TearDown() 201 202 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 203 ` 204 package main 205 206 import ( 207 "github.com/mattermost/mattermost-server/plugin" 208 "github.com/mattermost/mattermost-server/model" 209 ) 210 211 type MyPlugin struct { 212 plugin.MattermostPlugin 213 } 214 215 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 216 post.Message = post.Message + "_fromplugin" 217 return post, "" 218 } 219 220 func main() { 221 plugin.ClientMain(&MyPlugin{}) 222 } 223 `, 224 }, th.App, th.App.NewPluginAPI) 225 defer tearDown() 226 227 post := &model.Post{ 228 UserId: th.BasicUser.Id, 229 ChannelId: th.BasicChannel.Id, 230 Message: "message", 231 CreateAt: model.GetMillis() - 10000, 232 } 233 post, err := th.App.CreatePost(post, th.BasicChannel, false) 234 if err != nil { 235 t.Fatal(err) 236 } 237 assert.Equal(t, "message_fromplugin", post.Message) 238 if result := <-th.App.Srv.Store.Post().GetSingle(post.Id); result.Err != nil { 239 t.Fatal(err) 240 } else { 241 assert.Equal(t, "message_fromplugin", result.Data.(*model.Post).Message) 242 } 243 }) 244 245 t.Run("multiple updated", func(t *testing.T) { 246 th := Setup(t).InitBasic() 247 defer th.TearDown() 248 249 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 250 ` 251 package main 252 253 import ( 254 "github.com/mattermost/mattermost-server/plugin" 255 "github.com/mattermost/mattermost-server/model" 256 ) 257 258 type MyPlugin struct { 259 plugin.MattermostPlugin 260 } 261 262 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 263 264 post.Message = "prefix_" + post.Message 265 return post, "" 266 } 267 268 func main() { 269 plugin.ClientMain(&MyPlugin{}) 270 } 271 `, 272 ` 273 package main 274 275 import ( 276 "github.com/mattermost/mattermost-server/plugin" 277 "github.com/mattermost/mattermost-server/model" 278 ) 279 280 type MyPlugin struct { 281 plugin.MattermostPlugin 282 } 283 284 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 285 post.Message = post.Message + "_suffix" 286 return post, "" 287 } 288 289 func main() { 290 plugin.ClientMain(&MyPlugin{}) 291 } 292 `, 293 }, th.App, th.App.NewPluginAPI) 294 defer tearDown() 295 296 post := &model.Post{ 297 UserId: th.BasicUser.Id, 298 ChannelId: th.BasicChannel.Id, 299 Message: "message", 300 CreateAt: model.GetMillis() - 10000, 301 } 302 post, err := th.App.CreatePost(post, th.BasicChannel, false) 303 if err != nil { 304 t.Fatal(err) 305 } 306 assert.Equal(t, "prefix_message_suffix", post.Message) 307 }) 308 } 309 310 func TestHookMessageHasBeenPosted(t *testing.T) { 311 th := Setup(t).InitBasic() 312 defer th.TearDown() 313 314 var mockAPI plugintest.API 315 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 316 mockAPI.On("LogDebug", "message").Return(nil) 317 318 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 319 []string{ 320 ` 321 package main 322 323 import ( 324 "github.com/mattermost/mattermost-server/plugin" 325 "github.com/mattermost/mattermost-server/model" 326 ) 327 328 type MyPlugin struct { 329 plugin.MattermostPlugin 330 } 331 332 func (p *MyPlugin) MessageHasBeenPosted(c *plugin.Context, post *model.Post) { 333 p.API.LogDebug(post.Message) 334 } 335 336 func main() { 337 plugin.ClientMain(&MyPlugin{}) 338 } 339 `}, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 340 defer tearDown() 341 342 post := &model.Post{ 343 UserId: th.BasicUser.Id, 344 ChannelId: th.BasicChannel.Id, 345 Message: "message", 346 CreateAt: model.GetMillis() - 10000, 347 } 348 _, err := th.App.CreatePost(post, th.BasicChannel, false) 349 if err != nil { 350 t.Fatal(err) 351 } 352 } 353 354 func TestHookMessageWillBeUpdated(t *testing.T) { 355 th := Setup(t).InitBasic() 356 defer th.TearDown() 357 358 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 359 []string{ 360 ` 361 package main 362 363 import ( 364 "github.com/mattermost/mattermost-server/plugin" 365 "github.com/mattermost/mattermost-server/model" 366 ) 367 368 type MyPlugin struct { 369 plugin.MattermostPlugin 370 } 371 372 func (p *MyPlugin) MessageWillBeUpdated(c *plugin.Context, newPost, oldPost *model.Post) (*model.Post, string) { 373 newPost.Message = newPost.Message + "fromplugin" 374 return newPost, "" 375 } 376 377 func main() { 378 plugin.ClientMain(&MyPlugin{}) 379 } 380 `}, th.App, th.App.NewPluginAPI) 381 defer tearDown() 382 383 post := &model.Post{ 384 UserId: th.BasicUser.Id, 385 ChannelId: th.BasicChannel.Id, 386 Message: "message_", 387 CreateAt: model.GetMillis() - 10000, 388 } 389 post, err := th.App.CreatePost(post, th.BasicChannel, false) 390 if err != nil { 391 t.Fatal(err) 392 } 393 assert.Equal(t, "message_", post.Message) 394 post.Message = post.Message + "edited_" 395 post, err = th.App.UpdatePost(post, true) 396 if err != nil { 397 t.Fatal(err) 398 } 399 assert.Equal(t, "message_edited_fromplugin", post.Message) 400 } 401 402 func TestHookMessageHasBeenUpdated(t *testing.T) { 403 th := Setup(t).InitBasic() 404 defer th.TearDown() 405 406 var mockAPI plugintest.API 407 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 408 mockAPI.On("LogDebug", "message_edited").Return(nil) 409 mockAPI.On("LogDebug", "message_").Return(nil) 410 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 411 []string{ 412 ` 413 package main 414 415 import ( 416 "github.com/mattermost/mattermost-server/plugin" 417 "github.com/mattermost/mattermost-server/model" 418 ) 419 420 type MyPlugin struct { 421 plugin.MattermostPlugin 422 } 423 424 func (p *MyPlugin) MessageHasBeenUpdated(c *plugin.Context, newPost, oldPost *model.Post) { 425 p.API.LogDebug(newPost.Message) 426 p.API.LogDebug(oldPost.Message) 427 } 428 429 func main() { 430 plugin.ClientMain(&MyPlugin{}) 431 } 432 `}, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 433 defer tearDown() 434 435 post := &model.Post{ 436 UserId: th.BasicUser.Id, 437 ChannelId: th.BasicChannel.Id, 438 Message: "message_", 439 CreateAt: model.GetMillis() - 10000, 440 } 441 post, err := th.App.CreatePost(post, th.BasicChannel, false) 442 if err != nil { 443 t.Fatal(err) 444 } 445 assert.Equal(t, "message_", post.Message) 446 post.Message = post.Message + "edited" 447 _, err = th.App.UpdatePost(post, true) 448 if err != nil { 449 t.Fatal(err) 450 } 451 } 452 453 func TestHookFileWillBeUploaded(t *testing.T) { 454 t.Run("rejected", func(t *testing.T) { 455 th := Setup(t).InitBasic() 456 defer th.TearDown() 457 458 var mockAPI plugintest.API 459 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 460 mockAPI.On("LogDebug", "testhook.txt").Return(nil) 461 mockAPI.On("LogDebug", "inputfile").Return(nil) 462 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 463 ` 464 package main 465 466 import ( 467 "io" 468 "github.com/mattermost/mattermost-server/plugin" 469 "github.com/mattermost/mattermost-server/model" 470 ) 471 472 type MyPlugin struct { 473 plugin.MattermostPlugin 474 } 475 476 func (p *MyPlugin) FileWillBeUploaded(c *plugin.Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) { 477 return nil, "rejected" 478 } 479 480 func main() { 481 plugin.ClientMain(&MyPlugin{}) 482 } 483 `, 484 }, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 485 defer tearDown() 486 487 _, err := th.App.UploadFiles( 488 "noteam", 489 th.BasicChannel.Id, 490 th.BasicUser.Id, 491 []io.ReadCloser{ioutil.NopCloser(bytes.NewBufferString("inputfile"))}, 492 []string{"testhook.txt"}, 493 []string{}, 494 time.Now(), 495 ) 496 if assert.NotNil(t, err) { 497 assert.Equal(t, "File rejected by plugin. rejected", err.Message) 498 } 499 }) 500 501 t.Run("rejected, returned file ignored", func(t *testing.T) { 502 th := Setup(t).InitBasic() 503 defer th.TearDown() 504 505 var mockAPI plugintest.API 506 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 507 mockAPI.On("LogDebug", "testhook.txt").Return(nil) 508 mockAPI.On("LogDebug", "inputfile").Return(nil) 509 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 510 ` 511 package main 512 513 import ( 514 "io" 515 "github.com/mattermost/mattermost-server/plugin" 516 "github.com/mattermost/mattermost-server/model" 517 ) 518 519 type MyPlugin struct { 520 plugin.MattermostPlugin 521 } 522 523 func (p *MyPlugin) FileWillBeUploaded(c *plugin.Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) { 524 output.Write([]byte("ignored")) 525 info.Name = "ignored" 526 return info, "rejected" 527 } 528 529 func main() { 530 plugin.ClientMain(&MyPlugin{}) 531 } 532 `, 533 }, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 534 defer tearDown() 535 536 _, err := th.App.UploadFiles( 537 "noteam", 538 th.BasicChannel.Id, 539 th.BasicUser.Id, 540 []io.ReadCloser{ioutil.NopCloser(bytes.NewBufferString("inputfile"))}, 541 []string{"testhook.txt"}, 542 []string{}, 543 time.Now(), 544 ) 545 if assert.NotNil(t, err) { 546 assert.Equal(t, "File rejected by plugin. rejected", err.Message) 547 } 548 }) 549 550 t.Run("allowed", func(t *testing.T) { 551 th := Setup(t).InitBasic() 552 defer th.TearDown() 553 554 var mockAPI plugintest.API 555 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 556 mockAPI.On("LogDebug", "testhook.txt").Return(nil) 557 mockAPI.On("LogDebug", "inputfile").Return(nil) 558 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 559 ` 560 package main 561 562 import ( 563 "io" 564 "github.com/mattermost/mattermost-server/plugin" 565 "github.com/mattermost/mattermost-server/model" 566 ) 567 568 type MyPlugin struct { 569 plugin.MattermostPlugin 570 } 571 572 func (p *MyPlugin) FileWillBeUploaded(c *plugin.Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) { 573 return nil, "" 574 } 575 576 func main() { 577 plugin.ClientMain(&MyPlugin{}) 578 } 579 `, 580 }, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 581 defer tearDown() 582 583 response, err := th.App.UploadFiles( 584 "noteam", 585 th.BasicChannel.Id, 586 th.BasicUser.Id, 587 []io.ReadCloser{ioutil.NopCloser(bytes.NewBufferString("inputfile"))}, 588 []string{"testhook.txt"}, 589 []string{}, 590 time.Now(), 591 ) 592 assert.Nil(t, err) 593 assert.NotNil(t, response) 594 assert.Equal(t, 1, len(response.FileInfos)) 595 fileId := response.FileInfos[0].Id 596 597 fileInfo, err := th.App.GetFileInfo(fileId) 598 assert.Nil(t, err) 599 assert.NotNil(t, fileInfo) 600 assert.Equal(t, "testhook.txt", fileInfo.Name) 601 602 fileReader, err := th.App.FileReader(fileInfo.Path) 603 assert.Nil(t, err) 604 var resultBuf bytes.Buffer 605 io.Copy(&resultBuf, fileReader) 606 assert.Equal(t, "inputfile", resultBuf.String()) 607 }) 608 609 t.Run("updated", func(t *testing.T) { 610 th := Setup(t).InitBasic() 611 defer th.TearDown() 612 613 var mockAPI plugintest.API 614 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 615 mockAPI.On("LogDebug", "testhook.txt").Return(nil) 616 mockAPI.On("LogDebug", "inputfile").Return(nil) 617 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, []string{ 618 ` 619 package main 620 621 import ( 622 "io" 623 "bytes" 624 "github.com/mattermost/mattermost-server/plugin" 625 "github.com/mattermost/mattermost-server/model" 626 ) 627 628 type MyPlugin struct { 629 plugin.MattermostPlugin 630 } 631 632 func (p *MyPlugin) FileWillBeUploaded(c *plugin.Context, info *model.FileInfo, file io.Reader, output io.Writer) (*model.FileInfo, string) { 633 p.API.LogDebug(info.Name) 634 var buf bytes.Buffer 635 buf.ReadFrom(file) 636 p.API.LogDebug(buf.String()) 637 638 outbuf := bytes.NewBufferString("changedtext") 639 io.Copy(output, outbuf) 640 info.Name = "modifiedinfo" 641 return info, "" 642 } 643 644 func main() { 645 plugin.ClientMain(&MyPlugin{}) 646 } 647 `, 648 }, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 649 defer tearDown() 650 651 response, err := th.App.UploadFiles( 652 "noteam", 653 th.BasicChannel.Id, 654 th.BasicUser.Id, 655 []io.ReadCloser{ioutil.NopCloser(bytes.NewBufferString("inputfile"))}, 656 []string{"testhook.txt"}, 657 []string{}, 658 time.Now(), 659 ) 660 assert.Nil(t, err) 661 assert.NotNil(t, response) 662 assert.Equal(t, 1, len(response.FileInfos)) 663 fileId := response.FileInfos[0].Id 664 665 fileInfo, err := th.App.GetFileInfo(fileId) 666 assert.Nil(t, err) 667 assert.NotNil(t, fileInfo) 668 assert.Equal(t, "modifiedinfo", fileInfo.Name) 669 670 fileReader, err := th.App.FileReader(fileInfo.Path) 671 assert.Nil(t, err) 672 var resultBuf bytes.Buffer 673 io.Copy(&resultBuf, fileReader) 674 assert.Equal(t, "changedtext", resultBuf.String()) 675 }) 676 } 677 678 func TestUserWillLogIn_Blocked(t *testing.T) { 679 th := Setup(t).InitBasic() 680 defer th.TearDown() 681 682 err := th.App.UpdatePassword(th.BasicUser, "hunter2") 683 684 if err != nil { 685 t.Errorf("Error updating user password: %s", err) 686 } 687 688 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 689 []string{ 690 ` 691 package main 692 693 import ( 694 "github.com/mattermost/mattermost-server/plugin" 695 "github.com/mattermost/mattermost-server/model" 696 ) 697 698 type MyPlugin struct { 699 plugin.MattermostPlugin 700 } 701 702 func (p *MyPlugin) UserWillLogIn(c *plugin.Context, user *model.User) string { 703 return "Blocked By Plugin" 704 } 705 706 func main() { 707 plugin.ClientMain(&MyPlugin{}) 708 } 709 `}, th.App, th.App.NewPluginAPI) 710 defer tearDown() 711 712 r := &http.Request{} 713 w := httptest.NewRecorder() 714 _, err = th.App.DoLogin(w, r, th.BasicUser, "") 715 716 if !strings.HasPrefix(err.Id, "Login rejected by plugin") { 717 t.Errorf("Expected Login rejected by plugin, got %s", err.Id) 718 } 719 } 720 721 func TestUserWillLogInIn_Passed(t *testing.T) { 722 th := Setup(t).InitBasic() 723 defer th.TearDown() 724 725 err := th.App.UpdatePassword(th.BasicUser, "hunter2") 726 727 if err != nil { 728 t.Errorf("Error updating user password: %s", err) 729 } 730 731 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 732 []string{ 733 ` 734 package main 735 736 import ( 737 "github.com/mattermost/mattermost-server/plugin" 738 "github.com/mattermost/mattermost-server/model" 739 ) 740 741 type MyPlugin struct { 742 plugin.MattermostPlugin 743 } 744 745 func (p *MyPlugin) UserWillLogIn(c *plugin.Context, user *model.User) string { 746 return "" 747 } 748 749 func main() { 750 plugin.ClientMain(&MyPlugin{}) 751 } 752 `}, th.App, th.App.NewPluginAPI) 753 defer tearDown() 754 755 r := &http.Request{} 756 w := httptest.NewRecorder() 757 session, err := th.App.DoLogin(w, r, th.BasicUser, "") 758 759 if err != nil { 760 t.Errorf("Expected nil, got %s", err) 761 } 762 763 if session.UserId != th.BasicUser.Id { 764 t.Errorf("Expected %s, got %s", th.BasicUser.Id, session.UserId) 765 } 766 } 767 768 func TestUserHasLoggedIn(t *testing.T) { 769 th := Setup(t).InitBasic() 770 defer th.TearDown() 771 772 err := th.App.UpdatePassword(th.BasicUser, "hunter2") 773 774 if err != nil { 775 t.Errorf("Error updating user password: %s", err) 776 } 777 778 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 779 []string{ 780 ` 781 package main 782 783 import ( 784 "github.com/mattermost/mattermost-server/plugin" 785 "github.com/mattermost/mattermost-server/model" 786 ) 787 788 type MyPlugin struct { 789 plugin.MattermostPlugin 790 } 791 792 func (p *MyPlugin) UserHasLoggedIn(c *plugin.Context, user *model.User) { 793 user.FirstName = "plugin-callback-success" 794 p.API.UpdateUser(user) 795 } 796 797 func main() { 798 plugin.ClientMain(&MyPlugin{}) 799 } 800 `}, th.App, th.App.NewPluginAPI) 801 defer tearDown() 802 803 r := &http.Request{} 804 w := httptest.NewRecorder() 805 _, err = th.App.DoLogin(w, r, th.BasicUser, "") 806 807 if err != nil { 808 t.Errorf("Expected nil, got %s", err) 809 } 810 811 time.Sleep(2 * time.Second) 812 813 user, _ := th.App.GetUser(th.BasicUser.Id) 814 815 if user.FirstName != "plugin-callback-success" { 816 t.Errorf("Expected firstname overwrite, got default") 817 } 818 } 819 820 func TestUserHasBeenCreated(t *testing.T) { 821 th := Setup(t).InitBasic() 822 defer th.TearDown() 823 824 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 825 []string{ 826 ` 827 package main 828 829 import ( 830 "github.com/mattermost/mattermost-server/plugin" 831 "github.com/mattermost/mattermost-server/model" 832 ) 833 834 type MyPlugin struct { 835 plugin.MattermostPlugin 836 } 837 838 func (p *MyPlugin) UserHasBeenCreated(c *plugin.Context, user *model.User) { 839 user.Nickname = "plugin-callback-success" 840 p.API.UpdateUser(user) 841 } 842 843 func main() { 844 plugin.ClientMain(&MyPlugin{}) 845 } 846 `}, th.App, th.App.NewPluginAPI) 847 defer tearDown() 848 849 user := &model.User{ 850 Email: model.NewId() + "success+test@example.com", 851 Nickname: "Darth Vader", 852 Username: "vader" + model.NewId(), 853 Password: "passwd1", 854 AuthService: "", 855 } 856 _, err := th.App.CreateUser(user) 857 require.Nil(t, err) 858 859 time.Sleep(1 * time.Second) 860 861 user, err = th.App.GetUser(user.Id) 862 require.Nil(t, err) 863 864 require.Equal(t, "plugin-callback-success", user.Nickname) 865 } 866 867 func TestErrorString(t *testing.T) { 868 th := Setup(t).InitBasic() 869 defer th.TearDown() 870 871 t.Run("errors.New", func(t *testing.T) { 872 tearDown, _, activationErrors := SetAppEnvironmentWithPlugins(t, 873 []string{ 874 ` 875 package main 876 877 import ( 878 "errors" 879 880 "github.com/mattermost/mattermost-server/plugin" 881 ) 882 883 type MyPlugin struct { 884 plugin.MattermostPlugin 885 } 886 887 func (p *MyPlugin) OnActivate() error { 888 return errors.New("simulate failure") 889 } 890 891 func main() { 892 plugin.ClientMain(&MyPlugin{}) 893 } 894 `}, th.App, th.App.NewPluginAPI) 895 defer tearDown() 896 897 require.Len(t, activationErrors, 1) 898 require.NotNil(t, activationErrors[0]) 899 require.Contains(t, activationErrors[0].Error(), "simulate failure") 900 }) 901 902 t.Run("AppError", func(t *testing.T) { 903 tearDown, _, activationErrors := SetAppEnvironmentWithPlugins(t, 904 []string{ 905 ` 906 package main 907 908 import ( 909 "github.com/mattermost/mattermost-server/plugin" 910 "github.com/mattermost/mattermost-server/model" 911 ) 912 913 type MyPlugin struct { 914 plugin.MattermostPlugin 915 } 916 917 func (p *MyPlugin) OnActivate() error { 918 return model.NewAppError("where", "id", map[string]interface{}{"param": 1}, "details", 42) 919 } 920 921 func main() { 922 plugin.ClientMain(&MyPlugin{}) 923 } 924 `}, th.App, th.App.NewPluginAPI) 925 defer tearDown() 926 927 require.Len(t, activationErrors, 1) 928 require.NotNil(t, activationErrors[0]) 929 930 cause := errors.Cause(activationErrors[0]) 931 require.IsType(t, &model.AppError{}, cause) 932 933 // params not expected, since not exported 934 expectedErr := model.NewAppError("where", "id", nil, "details", 42) 935 require.Equal(t, expectedErr, cause) 936 }) 937 } 938 939 func TestHookContext(t *testing.T) { 940 th := Setup(t).InitBasic() 941 defer th.TearDown() 942 943 // We don't actually have a session, we are faking it so just set something arbitrarily 944 th.App.Session.Id = model.NewId() 945 th.App.RequestId = model.NewId() 946 th.App.IpAddress = model.NewId() 947 th.App.AcceptLanguage = model.NewId() 948 th.App.UserAgent = model.NewId() 949 950 var mockAPI plugintest.API 951 mockAPI.On("LoadPluginConfiguration", mock.Anything).Return(nil) 952 mockAPI.On("LogDebug", th.App.Session.Id).Return(nil) 953 mockAPI.On("LogInfo", th.App.RequestId).Return(nil) 954 mockAPI.On("LogError", th.App.IpAddress).Return(nil) 955 mockAPI.On("LogWarn", th.App.AcceptLanguage).Return(nil) 956 mockAPI.On("DeleteTeam", th.App.UserAgent).Return(nil) 957 958 tearDown, _, _ := SetAppEnvironmentWithPlugins(t, 959 []string{ 960 ` 961 package main 962 963 import ( 964 "github.com/mattermost/mattermost-server/plugin" 965 "github.com/mattermost/mattermost-server/model" 966 ) 967 968 type MyPlugin struct { 969 plugin.MattermostPlugin 970 } 971 972 func (p *MyPlugin) MessageHasBeenPosted(c *plugin.Context, post *model.Post) { 973 p.API.LogDebug(c.SessionId) 974 p.API.LogInfo(c.RequestId) 975 p.API.LogError(c.IpAddress) 976 p.API.LogWarn(c.AcceptLanguage) 977 p.API.DeleteTeam(c.UserAgent) 978 } 979 980 func main() { 981 plugin.ClientMain(&MyPlugin{}) 982 } 983 `}, th.App, func(*model.Manifest) plugin.API { return &mockAPI }) 984 defer tearDown() 985 986 post := &model.Post{ 987 UserId: th.BasicUser.Id, 988 ChannelId: th.BasicChannel.Id, 989 Message: "not this", 990 CreateAt: model.GetMillis() - 10000, 991 } 992 _, err := th.App.CreatePost(post, th.BasicChannel, false) 993 if err != nil { 994 t.Fatal(err) 995 } 996 }