github.com/teloshs/mattermost-server@v5.11.1+incompatible/app/plugin_api_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 "encoding/json" 9 "fmt" 10 "image" 11 "image/color" 12 "image/png" 13 "io/ioutil" 14 "os" 15 "path/filepath" 16 "strings" 17 "testing" 18 "time" 19 20 "github.com/mattermost/mattermost-server/model" 21 "github.com/mattermost/mattermost-server/plugin" 22 "github.com/mattermost/mattermost-server/services/mailservice" 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string, pluginId string, app *App) { 28 pluginDir, err := ioutil.TempDir("", "") 29 require.NoError(t, err) 30 webappPluginDir, err := ioutil.TempDir("", "") 31 require.NoError(t, err) 32 defer os.RemoveAll(pluginDir) 33 defer os.RemoveAll(webappPluginDir) 34 35 env, err := plugin.NewEnvironment(app.NewPluginAPI, pluginDir, webappPluginDir, app.Log) 36 require.NoError(t, err) 37 38 backend := filepath.Join(pluginDir, pluginId, "backend.exe") 39 compileGo(t, pluginCode, backend) 40 41 ioutil.WriteFile(filepath.Join(pluginDir, pluginId, "plugin.json"), []byte(pluginManifest), 0600) 42 manifest, activated, reterr := env.Activate(pluginId) 43 require.Nil(t, reterr) 44 require.NotNil(t, manifest) 45 require.True(t, activated) 46 47 app.SetPluginsEnvironment(env) 48 } 49 50 func TestPluginAPIGetUsers(t *testing.T) { 51 th := Setup(t) 52 defer th.TearDown() 53 api := th.SetupPluginAPI() 54 55 user1, err := th.App.CreateUser(&model.User{ 56 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 57 Password: "password", 58 Username: "user1" + model.NewId(), 59 }) 60 require.Nil(t, err) 61 defer th.App.PermanentDeleteUser(user1) 62 63 user2, err := th.App.CreateUser(&model.User{ 64 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 65 Password: "password", 66 Username: "user2" + model.NewId(), 67 }) 68 require.Nil(t, err) 69 defer th.App.PermanentDeleteUser(user2) 70 71 user3, err := th.App.CreateUser(&model.User{ 72 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 73 Password: "password", 74 Username: "user3" + model.NewId(), 75 }) 76 require.Nil(t, err) 77 defer th.App.PermanentDeleteUser(user3) 78 79 user4, err := th.App.CreateUser(&model.User{ 80 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 81 Password: "password", 82 Username: "user4" + model.NewId(), 83 }) 84 require.Nil(t, err) 85 defer th.App.PermanentDeleteUser(user4) 86 87 testCases := []struct { 88 Description string 89 Page int 90 PerPage int 91 ExpectedUsers []*model.User 92 }{ 93 { 94 "page 0, perPage 0", 95 0, 96 0, 97 []*model.User{}, 98 }, 99 { 100 "page 0, perPage 10", 101 0, 102 10, 103 []*model.User{user1, user2, user3, user4}, 104 }, 105 { 106 "page 0, perPage 2", 107 0, 108 2, 109 []*model.User{user1, user2}, 110 }, 111 { 112 "page 1, perPage 2", 113 1, 114 2, 115 []*model.User{user3, user4}, 116 }, 117 { 118 "page 10, perPage 10", 119 10, 120 10, 121 []*model.User{}, 122 }, 123 } 124 125 for _, testCase := range testCases { 126 t.Run(testCase.Description, func(t *testing.T) { 127 users, err := api.GetUsers(&model.UserGetOptions{ 128 Page: testCase.Page, 129 PerPage: testCase.PerPage, 130 }) 131 assert.Nil(t, err) 132 assert.Equal(t, testCase.ExpectedUsers, users) 133 }) 134 } 135 } 136 137 func TestPluginAPIGetUsersInTeam(t *testing.T) { 138 th := Setup(t).InitBasic() 139 defer th.TearDown() 140 api := th.SetupPluginAPI() 141 142 team1 := th.CreateTeam() 143 team2 := th.CreateTeam() 144 145 user1, err := th.App.CreateUser(&model.User{ 146 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 147 Password: "password", 148 Username: "user1" + model.NewId(), 149 }) 150 require.Nil(t, err) 151 defer th.App.PermanentDeleteUser(user1) 152 153 user2, err := th.App.CreateUser(&model.User{ 154 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 155 Password: "password", 156 Username: "user2" + model.NewId(), 157 }) 158 require.Nil(t, err) 159 defer th.App.PermanentDeleteUser(user2) 160 161 user3, err := th.App.CreateUser(&model.User{ 162 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 163 Password: "password", 164 Username: "user3" + model.NewId(), 165 }) 166 require.Nil(t, err) 167 defer th.App.PermanentDeleteUser(user3) 168 169 user4, err := th.App.CreateUser(&model.User{ 170 Email: strings.ToLower(model.NewId()) + "success+test@example.com", 171 Password: "password", 172 Username: "user4" + model.NewId(), 173 }) 174 require.Nil(t, err) 175 defer th.App.PermanentDeleteUser(user4) 176 177 // Add all users to team 1 178 _, _, err = th.App.joinUserToTeam(team1, user1) 179 require.Nil(t, err) 180 _, _, err = th.App.joinUserToTeam(team1, user2) 181 require.Nil(t, err) 182 _, _, err = th.App.joinUserToTeam(team1, user3) 183 require.Nil(t, err) 184 _, _, err = th.App.joinUserToTeam(team1, user4) 185 require.Nil(t, err) 186 187 // Add only user3 and user4 to team 2 188 _, _, err = th.App.joinUserToTeam(team2, user3) 189 require.Nil(t, err) 190 _, _, err = th.App.joinUserToTeam(team2, user4) 191 require.Nil(t, err) 192 193 testCases := []struct { 194 Description string 195 TeamId string 196 Page int 197 PerPage int 198 ExpectedUsers []*model.User 199 }{ 200 { 201 "unknown team", 202 model.NewId(), 203 0, 204 0, 205 []*model.User{}, 206 }, 207 { 208 "team 1, page 0, perPage 10", 209 team1.Id, 210 0, 211 10, 212 []*model.User{user1, user2, user3, user4}, 213 }, 214 { 215 "team 1, page 0, perPage 2", 216 team1.Id, 217 0, 218 2, 219 []*model.User{user1, user2}, 220 }, 221 { 222 "team 1, page 1, perPage 2", 223 team1.Id, 224 1, 225 2, 226 []*model.User{user3, user4}, 227 }, 228 { 229 "team 2, page 0, perPage 10", 230 team2.Id, 231 0, 232 10, 233 []*model.User{user3, user4}, 234 }, 235 } 236 237 for _, testCase := range testCases { 238 t.Run(testCase.Description, func(t *testing.T) { 239 users, err := api.GetUsersInTeam(testCase.TeamId, testCase.Page, testCase.PerPage) 240 assert.Nil(t, err) 241 assert.Equal(t, testCase.ExpectedUsers, users) 242 }) 243 } 244 } 245 246 func TestPluginAPIUpdateUserStatus(t *testing.T) { 247 th := Setup(t).InitBasic() 248 defer th.TearDown() 249 api := th.SetupPluginAPI() 250 251 statuses := []string{model.STATUS_ONLINE, model.STATUS_AWAY, model.STATUS_DND, model.STATUS_OFFLINE} 252 253 for _, s := range statuses { 254 status, err := api.UpdateUserStatus(th.BasicUser.Id, s) 255 require.Nil(t, err) 256 require.NotNil(t, status) 257 assert.Equal(t, s, status.Status) 258 } 259 260 status, err := api.UpdateUserStatus(th.BasicUser.Id, "notrealstatus") 261 assert.NotNil(t, err) 262 assert.Nil(t, status) 263 } 264 265 func TestPluginAPIGetFile(t *testing.T) { 266 th := Setup(t).InitBasic() 267 defer th.TearDown() 268 api := th.SetupPluginAPI() 269 270 // check a valid file first 271 uploadTime := time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local) 272 filename := "testGetFile" 273 fileData := []byte("Hello World") 274 info, err := th.App.DoUploadFile(uploadTime, th.BasicTeam.Id, th.BasicChannel.Id, th.BasicUser.Id, filename, fileData) 275 require.Nil(t, err) 276 defer func() { 277 <-th.App.Srv.Store.FileInfo().PermanentDelete(info.Id) 278 th.App.RemoveFile(info.Path) 279 }() 280 281 data, err1 := api.GetFile(info.Id) 282 require.Nil(t, err1) 283 assert.Equal(t, data, fileData) 284 285 // then checking invalid file 286 data, err = api.GetFile("../fake/testingApi") 287 require.NotNil(t, err) 288 require.Nil(t, data) 289 } 290 func TestPluginAPISavePluginConfig(t *testing.T) { 291 th := Setup(t).InitBasic() 292 defer th.TearDown() 293 294 manifest := &model.Manifest{ 295 Id: "pluginid", 296 SettingsSchema: &model.PluginSettingsSchema{ 297 Settings: []*model.PluginSetting{ 298 {Key: "MyStringSetting", Type: "text"}, 299 {Key: "MyIntSetting", Type: "text"}, 300 {Key: "MyBoolSetting", Type: "bool"}, 301 }, 302 }, 303 } 304 305 api := NewPluginAPI(th.App, manifest) 306 307 pluginConfigJsonString := `{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}` 308 309 var pluginConfig map[string]interface{} 310 if err := json.Unmarshal([]byte(pluginConfigJsonString), &pluginConfig); err != nil { 311 t.Fatal(err) 312 } 313 314 if err := api.SavePluginConfig(pluginConfig); err != nil { 315 t.Fatal(err) 316 } 317 318 type Configuration struct { 319 MyStringSetting string 320 MyIntSetting int 321 MyBoolSetting bool 322 } 323 324 savedConfiguration := new(Configuration) 325 if err := api.LoadPluginConfiguration(savedConfiguration); err != nil { 326 t.Fatal(err) 327 } 328 329 expectedConfiguration := new(Configuration) 330 if err := json.Unmarshal([]byte(pluginConfigJsonString), &expectedConfiguration); err != nil { 331 t.Fatal(err) 332 } 333 334 assert.Equal(t, expectedConfiguration, savedConfiguration) 335 } 336 337 func TestPluginAPIGetPluginConfig(t *testing.T) { 338 th := Setup(t).InitBasic() 339 defer th.TearDown() 340 341 manifest := &model.Manifest{ 342 Id: "pluginid", 343 SettingsSchema: &model.PluginSettingsSchema{ 344 Settings: []*model.PluginSetting{ 345 {Key: "MyStringSetting", Type: "text"}, 346 {Key: "MyIntSetting", Type: "text"}, 347 {Key: "MyBoolSetting", Type: "bool"}, 348 }, 349 }, 350 } 351 352 api := NewPluginAPI(th.App, manifest) 353 354 pluginConfigJsonString := `{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}` 355 var pluginConfig map[string]interface{} 356 357 if err := json.Unmarshal([]byte(pluginConfigJsonString), &pluginConfig); err != nil { 358 t.Fatal(err) 359 } 360 th.App.UpdateConfig(func(cfg *model.Config) { 361 cfg.PluginSettings.Plugins["pluginid"] = pluginConfig 362 }) 363 364 savedPluginConfig := api.GetPluginConfig() 365 assert.Equal(t, pluginConfig, savedPluginConfig) 366 } 367 368 func TestPluginAPILoadPluginConfiguration(t *testing.T) { 369 th := Setup(t).InitBasic() 370 defer th.TearDown() 371 372 var pluginJson map[string]interface{} 373 if err := json.Unmarshal([]byte(`{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}`), &pluginJson); err != nil { 374 t.Fatal(err) 375 } 376 th.App.UpdateConfig(func(cfg *model.Config) { 377 cfg.PluginSettings.Plugins["testloadpluginconfig"] = pluginJson 378 }) 379 setupPluginApiTest(t, 380 ` 381 package main 382 383 import ( 384 "github.com/mattermost/mattermost-server/plugin" 385 "github.com/mattermost/mattermost-server/model" 386 "fmt" 387 ) 388 389 type configuration struct { 390 MyStringSetting string 391 MyIntSetting int 392 MyBoolSetting bool 393 } 394 395 type MyPlugin struct { 396 plugin.MattermostPlugin 397 398 configuration configuration 399 } 400 401 func (p *MyPlugin) OnConfigurationChange() error { 402 if err := p.API.LoadPluginConfiguration(&p.configuration); err != nil { 403 return err 404 } 405 406 return nil 407 } 408 409 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 410 return nil, fmt.Sprintf("%v%v%v", p.configuration.MyStringSetting, p.configuration.MyIntSetting, p.configuration.MyBoolSetting) 411 } 412 413 func main() { 414 plugin.ClientMain(&MyPlugin{}) 415 } 416 `, 417 `{"id": "testloadpluginconfig", "backend": {"executable": "backend.exe"}, "settings_schema": { 418 "settings": [ 419 { 420 "key": "MyStringSetting", 421 "type": "text" 422 }, 423 { 424 "key": "MyIntSetting", 425 "type": "text" 426 }, 427 { 428 "key": "MyBoolSetting", 429 "type": "bool" 430 } 431 ] 432 }}`, "testloadpluginconfig", th.App) 433 hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testloadpluginconfig") 434 assert.NoError(t, err) 435 _, ret := hooks.MessageWillBePosted(nil, nil) 436 assert.Equal(t, "str32true", ret) 437 } 438 439 func TestPluginAPILoadPluginConfigurationDefaults(t *testing.T) { 440 th := Setup(t).InitBasic() 441 defer th.TearDown() 442 443 var pluginJson map[string]interface{} 444 if err := json.Unmarshal([]byte(`{"mystringsetting": "override"}`), &pluginJson); err != nil { 445 t.Fatal(err) 446 } 447 th.App.UpdateConfig(func(cfg *model.Config) { 448 cfg.PluginSettings.Plugins["testloadpluginconfig"] = pluginJson 449 }) 450 setupPluginApiTest(t, 451 ` 452 package main 453 454 import ( 455 "github.com/mattermost/mattermost-server/plugin" 456 "github.com/mattermost/mattermost-server/model" 457 "fmt" 458 ) 459 460 type configuration struct { 461 MyStringSetting string 462 MyIntSetting int 463 MyBoolSetting bool 464 } 465 466 type MyPlugin struct { 467 plugin.MattermostPlugin 468 469 configuration configuration 470 } 471 472 func (p *MyPlugin) OnConfigurationChange() error { 473 if err := p.API.LoadPluginConfiguration(&p.configuration); err != nil { 474 return err 475 } 476 477 return nil 478 } 479 480 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 481 return nil, fmt.Sprintf("%v%v%v", p.configuration.MyStringSetting, p.configuration.MyIntSetting, p.configuration.MyBoolSetting) 482 } 483 484 func main() { 485 plugin.ClientMain(&MyPlugin{}) 486 } 487 `, 488 `{"id": "testloadpluginconfig", "backend": {"executable": "backend.exe"}, "settings_schema": { 489 "settings": [ 490 { 491 "key": "MyStringSetting", 492 "type": "text", 493 "default": "notthis" 494 }, 495 { 496 "key": "MyIntSetting", 497 "type": "text", 498 "default": 35 499 }, 500 { 501 "key": "MyBoolSetting", 502 "type": "bool", 503 "default": true 504 } 505 ] 506 }}`, "testloadpluginconfig", th.App) 507 hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testloadpluginconfig") 508 assert.NoError(t, err) 509 _, ret := hooks.MessageWillBePosted(nil, nil) 510 assert.Equal(t, "override35true", ret) 511 } 512 513 func TestPluginAPIGetBundlePath(t *testing.T) { 514 th := Setup(t).InitBasic() 515 defer th.TearDown() 516 517 setupPluginApiTest(t, 518 ` 519 package main 520 521 import ( 522 "github.com/mattermost/mattermost-server/plugin" 523 "github.com/mattermost/mattermost-server/model" 524 ) 525 526 type MyPlugin struct { 527 plugin.MattermostPlugin 528 } 529 530 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 531 bundlePath, err := p.API.GetBundlePath() 532 if err != nil { 533 return nil, err.Error() + "failed get bundle path" 534 } 535 536 return nil, bundlePath 537 } 538 539 func main() { 540 plugin.ClientMain(&MyPlugin{}) 541 } 542 `, `{"id": "testplugin", "backend": {"executable": "backend.exe"}}`, "testplugin", th.App) 543 544 hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testplugin") 545 require.Nil(t, err) 546 require.NotNil(t, hooks) 547 bundlePath, err := filepath.Abs(filepath.Join(*th.App.Config().PluginSettings.Directory, "testplugin")) 548 require.Nil(t, err) 549 550 _, errString := hooks.MessageWillBePosted(nil, nil) 551 assert.Equal(t, bundlePath, errString) 552 } 553 554 func TestPluginAPIGetProfileImage(t *testing.T) { 555 th := Setup(t).InitBasic() 556 defer th.TearDown() 557 api := th.SetupPluginAPI() 558 559 // check existing user first 560 data, err := api.GetProfileImage(th.BasicUser.Id) 561 require.Nil(t, err) 562 require.NotEmpty(t, data) 563 564 // then unknown user 565 data, err = api.GetProfileImage(model.NewId()) 566 require.NotNil(t, err) 567 require.Nil(t, data) 568 } 569 570 func TestPluginAPISetProfileImage(t *testing.T) { 571 th := Setup(t).InitBasic() 572 defer th.TearDown() 573 api := th.SetupPluginAPI() 574 575 // Create an 128 x 128 image 576 img := image.NewRGBA(image.Rect(0, 0, 128, 128)) 577 // Draw a red dot at (2, 3) 578 img.Set(2, 3, color.RGBA{255, 0, 0, 255}) 579 buf := new(bytes.Buffer) 580 err := png.Encode(buf, img) 581 require.Nil(t, err) 582 dataBytes := buf.Bytes() 583 584 // Set the user profile image 585 err = api.SetProfileImage(th.BasicUser.Id, dataBytes) 586 require.Nil(t, err) 587 588 // Get the user profile image to check 589 imageProfile, err := api.GetProfileImage(th.BasicUser.Id) 590 require.Nil(t, err) 591 require.NotEmpty(t, imageProfile) 592 593 colorful := color.NRGBA{255, 0, 0, 255} 594 byteReader := bytes.NewReader(imageProfile) 595 img2, _, err2 := image.Decode(byteReader) 596 require.Nil(t, err2) 597 require.Equal(t, img2.At(2, 3), colorful) 598 } 599 600 func TestPluginAPIGetPlugins(t *testing.T) { 601 th := Setup(t).InitBasic() 602 defer th.TearDown() 603 api := th.SetupPluginAPI() 604 605 pluginCode := ` 606 package main 607 608 import ( 609 "github.com/mattermost/mattermost-server/plugin" 610 ) 611 612 type MyPlugin struct { 613 plugin.MattermostPlugin 614 } 615 616 func main() { 617 plugin.ClientMain(&MyPlugin{}) 618 } 619 ` 620 621 pluginDir, err := ioutil.TempDir("", "") 622 require.NoError(t, err) 623 webappPluginDir, err := ioutil.TempDir("", "") 624 require.NoError(t, err) 625 defer os.RemoveAll(pluginDir) 626 defer os.RemoveAll(webappPluginDir) 627 628 env, err := plugin.NewEnvironment(th.App.NewPluginAPI, pluginDir, webappPluginDir, th.App.Log) 629 require.NoError(t, err) 630 631 pluginIDs := []string{"pluginid1", "pluginid2", "pluginid3"} 632 var pluginManifests []*model.Manifest 633 for _, pluginID := range pluginIDs { 634 backend := filepath.Join(pluginDir, pluginID, "backend.exe") 635 compileGo(t, pluginCode, backend) 636 637 ioutil.WriteFile(filepath.Join(pluginDir, pluginID, "plugin.json"), []byte(fmt.Sprintf(`{"id": "%s", "server": {"executable": "backend.exe"}}`, pluginID)), 0600) 638 manifest, activated, reterr := env.Activate(pluginID) 639 640 require.Nil(t, reterr) 641 require.NotNil(t, manifest) 642 require.True(t, activated) 643 pluginManifests = append(pluginManifests, manifest) 644 } 645 th.App.SetPluginsEnvironment(env) 646 647 // Decativate the last one for testing 648 sucess := env.Deactivate(pluginIDs[len(pluginIDs)-1]) 649 require.True(t, sucess) 650 651 // check existing user first 652 plugins, err := api.GetPlugins() 653 assert.Nil(t, err) 654 assert.NotEmpty(t, plugins) 655 assert.Equal(t, pluginManifests, plugins) 656 } 657 658 func TestPluginAPIGetTeamIcon(t *testing.T) { 659 th := Setup(t).InitBasic() 660 defer th.TearDown() 661 api := th.SetupPluginAPI() 662 663 // Create an 128 x 128 image 664 img := image.NewRGBA(image.Rect(0, 0, 128, 128)) 665 // Draw a red dot at (2, 3) 666 img.Set(2, 3, color.RGBA{255, 0, 0, 255}) 667 buf := new(bytes.Buffer) 668 err := png.Encode(buf, img) 669 require.Nil(t, err) 670 dataBytes := buf.Bytes() 671 fileReader := bytes.NewReader(dataBytes) 672 673 // Set the Team Icon 674 err = th.App.SetTeamIconFromFile(th.BasicTeam, fileReader) 675 require.Nil(t, err) 676 677 // Get the team icon to check 678 teamIcon, err := api.GetTeamIcon(th.BasicTeam.Id) 679 require.Nil(t, err) 680 require.NotEmpty(t, teamIcon) 681 682 colorful := color.NRGBA{255, 0, 0, 255} 683 byteReader := bytes.NewReader(teamIcon) 684 img2, _, err2 := image.Decode(byteReader) 685 require.Nil(t, err2) 686 require.Equal(t, img2.At(2, 3), colorful) 687 } 688 689 func TestPluginAPISetTeamIcon(t *testing.T) { 690 th := Setup(t).InitBasic() 691 defer th.TearDown() 692 api := th.SetupPluginAPI() 693 694 // Create an 128 x 128 image 695 img := image.NewRGBA(image.Rect(0, 0, 128, 128)) 696 // Draw a red dot at (2, 3) 697 img.Set(2, 3, color.RGBA{255, 0, 0, 255}) 698 buf := new(bytes.Buffer) 699 err := png.Encode(buf, img) 700 require.Nil(t, err) 701 dataBytes := buf.Bytes() 702 703 // Set the user profile image 704 err = api.SetTeamIcon(th.BasicTeam.Id, dataBytes) 705 require.Nil(t, err) 706 707 // Get the user profile image to check 708 teamIcon, err := api.GetTeamIcon(th.BasicTeam.Id) 709 require.Nil(t, err) 710 require.NotEmpty(t, teamIcon) 711 712 colorful := color.NRGBA{255, 0, 0, 255} 713 byteReader := bytes.NewReader(teamIcon) 714 img2, _, err2 := image.Decode(byteReader) 715 require.Nil(t, err2) 716 require.Equal(t, img2.At(2, 3), colorful) 717 } 718 719 func TestPluginAPISearchChannels(t *testing.T) { 720 th := Setup(t).InitBasic() 721 defer th.TearDown() 722 api := th.SetupPluginAPI() 723 724 t.Run("all fine", func(t *testing.T) { 725 channels, err := api.SearchChannels(th.BasicTeam.Id, th.BasicChannel.Name) 726 assert.Nil(t, err) 727 assert.Len(t, channels, 1) 728 }) 729 730 t.Run("invalid team id", func(t *testing.T) { 731 channels, err := api.SearchChannels("invalidid", th.BasicChannel.Name) 732 assert.Nil(t, err) 733 assert.Empty(t, channels) 734 }) 735 } 736 737 func TestPluginAPISearchPostsInTeam(t *testing.T) { 738 th := Setup(t).InitBasic() 739 defer th.TearDown() 740 api := th.SetupPluginAPI() 741 742 testCases := []struct { 743 description string 744 teamId string 745 params []*model.SearchParams 746 expectedPostsLen int 747 }{ 748 { 749 "nil params", 750 th.BasicTeam.Id, 751 nil, 752 0, 753 }, 754 { 755 "empty params", 756 th.BasicTeam.Id, 757 []*model.SearchParams{}, 758 0, 759 }, 760 { 761 "doesn't match any posts", 762 th.BasicTeam.Id, 763 model.ParseSearchParams("bad message", 0), 764 0, 765 }, 766 { 767 "matched posts", 768 th.BasicTeam.Id, 769 model.ParseSearchParams(th.BasicPost.Message, 0), 770 1, 771 }, 772 } 773 774 for _, testCase := range testCases { 775 t.Run(testCase.description, func(t *testing.T) { 776 posts, err := api.SearchPostsInTeam(testCase.teamId, testCase.params) 777 assert.Nil(t, err) 778 assert.Equal(t, testCase.expectedPostsLen, len(posts)) 779 }) 780 } 781 } 782 783 func TestPluginAPIGetChannelsForTeamForUser(t *testing.T) { 784 th := Setup(t).InitBasic() 785 defer th.TearDown() 786 api := th.SetupPluginAPI() 787 788 t.Run("all fine", func(t *testing.T) { 789 channels, err := api.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false) 790 assert.Nil(t, err) 791 assert.Len(t, channels, 3) 792 }) 793 794 t.Run("invalid team id", func(t *testing.T) { 795 channels, err := api.GetChannelsForTeamForUser("invalidid", th.BasicUser.Id, false) 796 assert.NotNil(t, err) 797 assert.Empty(t, channels) 798 }) 799 } 800 801 func TestPluginAPIRemoveTeamIcon(t *testing.T) { 802 th := Setup(t).InitBasic() 803 defer th.TearDown() 804 api := th.SetupPluginAPI() 805 806 // Create an 128 x 128 image 807 img := image.NewRGBA(image.Rect(0, 0, 128, 128)) 808 809 // Draw a red dot at (2, 3) 810 img.Set(2, 3, color.RGBA{255, 0, 0, 255}) 811 buf := new(bytes.Buffer) 812 err1 := png.Encode(buf, img) 813 require.Nil(t, err1) 814 dataBytes := buf.Bytes() 815 fileReader := bytes.NewReader(dataBytes) 816 817 // Set the Team Icon 818 err := th.App.SetTeamIconFromFile(th.BasicTeam, fileReader) 819 require.Nil(t, err) 820 err = api.RemoveTeamIcon(th.BasicTeam.Id) 821 require.Nil(t, err) 822 } 823 824 func TestPluginAPIUpdateUserActive(t *testing.T) { 825 th := Setup(t).InitBasic() 826 defer th.TearDown() 827 api := th.SetupPluginAPI() 828 829 err := api.UpdateUserActive(th.BasicUser.Id, true) 830 require.Nil(t, err) 831 user, err := api.GetUser(th.BasicUser.Id) 832 require.Nil(t, err) 833 require.Equal(t, int64(0), user.DeleteAt) 834 835 err = api.UpdateUserActive(th.BasicUser.Id, false) 836 require.Nil(t, err) 837 user, err = api.GetUser(th.BasicUser.Id) 838 require.Nil(t, err) 839 require.NotNil(t, user) 840 require.NotEqual(t, int64(0), user.DeleteAt) 841 842 err = api.UpdateUserActive(th.BasicUser.Id, true) 843 require.Nil(t, err) 844 err = api.UpdateUserActive(th.BasicUser.Id, true) 845 require.Nil(t, err) 846 user, err = api.GetUser(th.BasicUser.Id) 847 require.Nil(t, err) 848 require.Equal(t, int64(0), user.DeleteAt) 849 } 850 851 func TestPluginAPIGetDirectChannel(t *testing.T) { 852 th := Setup(t).InitBasic() 853 defer th.TearDown() 854 api := th.SetupPluginAPI() 855 856 dm1, err := api.GetDirectChannel(th.BasicUser.Id, th.BasicUser2.Id) 857 require.Nil(t, err) 858 require.NotEmpty(t, dm1) 859 860 dm2, err := api.GetDirectChannel(th.BasicUser.Id, th.BasicUser.Id) 861 require.Nil(t, err) 862 require.NotEmpty(t, dm2) 863 864 dm3, err := api.GetDirectChannel(th.BasicUser.Id, model.NewId()) 865 require.NotNil(t, err) 866 require.Empty(t, dm3) 867 } 868 869 func TestPluginAPISendMail(t *testing.T) { 870 th := Setup(t).InitBasic() 871 defer th.TearDown() 872 api := th.SetupPluginAPI() 873 874 to := th.BasicUser.Email 875 subject := "testing plugin api sending email" 876 body := "this is a test." 877 878 err := api.SendMail(to, subject, body) 879 require.Nil(t, err) 880 881 // Check if we received the email 882 var resultsMailbox mailservice.JSONMessageHeaderInbucket 883 errMail := mailservice.RetryInbucket(5, func() error { 884 var err error 885 resultsMailbox, err = mailservice.GetMailBox(to) 886 return err 887 }) 888 require.Nil(t, errMail) 889 require.NotZero(t, len(resultsMailbox)) 890 require.True(t, strings.ContainsAny(resultsMailbox[len(resultsMailbox)-1].To[0], to)) 891 892 resultsEmail, err1 := mailservice.GetMessageFromMailbox(to, resultsMailbox[len(resultsMailbox)-1].ID) 893 require.Nil(t, err1) 894 require.Equal(t, resultsEmail.Subject, subject) 895 require.Equal(t, resultsEmail.Body.Text, body) 896 897 } 898 899 func TestPluginAPI_SearchTeams(t *testing.T) { 900 th := Setup(t).InitBasic() 901 defer th.TearDown() 902 903 api := th.SetupPluginAPI() 904 905 t.Run("all fine", func(t *testing.T) { 906 teams, err := api.SearchTeams(th.BasicTeam.Name) 907 assert.Nil(t, err) 908 assert.Len(t, teams, 1) 909 910 teams, err = api.SearchTeams(th.BasicTeam.DisplayName) 911 assert.Nil(t, err) 912 assert.Len(t, teams, 1) 913 914 teams, err = api.SearchTeams(th.BasicTeam.Name[:3]) 915 assert.Nil(t, err) 916 assert.Len(t, teams, 1) 917 }) 918 919 t.Run("invalid team name", func(t *testing.T) { 920 teams, err := api.SearchTeams("not found") 921 assert.Nil(t, err) 922 assert.Empty(t, teams) 923 }) 924 } 925 926 func TestPluginBots(t *testing.T) { 927 th := Setup(t).InitBasic() 928 defer th.TearDown() 929 930 setupPluginApiTest(t, 931 ` 932 package main 933 934 import ( 935 "github.com/mattermost/mattermost-server/plugin" 936 "github.com/mattermost/mattermost-server/model" 937 ) 938 939 type MyPlugin struct { 940 plugin.MattermostPlugin 941 } 942 943 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 944 createdBot, err := p.API.CreateBot(&model.Bot{ 945 Username: "bot", 946 Description: "a plugin bot", 947 }) 948 if err != nil { 949 return nil, err.Error() + "failed to create bot" 950 } 951 952 fetchedBot, err := p.API.GetBot(createdBot.UserId, false) 953 if err != nil { 954 return nil, err.Error() + "failed to get bot" 955 } 956 if fetchedBot.Description != "a plugin bot" { 957 return nil, "GetBot did not return the expected bot Description" 958 } 959 if fetchedBot.OwnerId != "testpluginbots" { 960 return nil, "GetBot did not return the expected bot OwnerId" 961 } 962 963 updatedDescription := createdBot.Description + ", updated" 964 patchedBot, err := p.API.PatchBot(createdBot.UserId, &model.BotPatch{ 965 Description: &updatedDescription, 966 }) 967 if err != nil { 968 return nil, err.Error() + "failed to patch bot" 969 } 970 971 fetchedBot, err = p.API.GetBot(patchedBot.UserId, false) 972 if err != nil { 973 return nil, err.Error() + "failed to get bot" 974 } 975 976 if fetchedBot.UserId != patchedBot.UserId { 977 return nil, "GetBot did not return the expected bot" 978 } 979 if fetchedBot.Description != "a plugin bot, updated" { 980 return nil, "GetBot did not return the updated bot Description" 981 } 982 983 fetchedBots, err := p.API.GetBots(&model.BotGetOptions{ 984 Page: 0, 985 PerPage: 1, 986 OwnerId: "", 987 IncludeDeleted: false, 988 }) 989 if err != nil { 990 return nil, err.Error() + "failed to get bots" 991 } 992 993 if len(fetchedBots) != 1 { 994 return nil, "GetBots did not return a single bot" 995 } 996 if fetchedBot.UserId != fetchedBots[0].UserId { 997 return nil, "GetBots did not return the expected bot" 998 } 999 1000 _, err = p.API.UpdateBotActive(fetchedBot.UserId, false) 1001 if err != nil { 1002 return nil, err.Error() + "failed to disable bot" 1003 } 1004 1005 fetchedBot, err = p.API.GetBot(patchedBot.UserId, false) 1006 if err == nil { 1007 return nil, "expected not to find disabled bot" 1008 } 1009 1010 _, err = p.API.UpdateBotActive(fetchedBot.UserId, true) 1011 if err != nil { 1012 return nil, err.Error() + "failed to disable bot" 1013 } 1014 1015 fetchedBot, err = p.API.GetBot(patchedBot.UserId, false) 1016 if err != nil { 1017 return nil, err.Error() + "failed to get bot after enabling" 1018 } 1019 if fetchedBot.UserId != patchedBot.UserId { 1020 return nil, "GetBot did not return the expected bot after enabling" 1021 } 1022 1023 err = p.API.PermanentDeleteBot(patchedBot.UserId) 1024 if err != nil { 1025 return nil, err.Error() + "failed to delete bot" 1026 } 1027 1028 _, err = p.API.GetBot(patchedBot.UserId, false) 1029 if err == nil { 1030 return nil, err.Error() + "found bot after permanently deleting" 1031 } 1032 1033 createdBotWithOverriddenCreator, err := p.API.CreateBot(&model.Bot{ 1034 Username: "bot", 1035 Description: "a plugin bot", 1036 OwnerId: "abc123", 1037 }) 1038 if err != nil { 1039 return nil, err.Error() + "failed to create bot with overridden creator" 1040 } 1041 1042 fetchedBot, err = p.API.GetBot(createdBotWithOverriddenCreator.UserId, false) 1043 if err != nil { 1044 return nil, err.Error() + "failed to get bot" 1045 } 1046 if fetchedBot.Description != "a plugin bot" { 1047 return nil, "GetBot did not return the expected bot Description" 1048 } 1049 if fetchedBot.OwnerId != "abc123" { 1050 return nil, "GetBot did not return the expected bot OwnerId" 1051 } 1052 1053 return nil, "" 1054 } 1055 1056 func main() { 1057 plugin.ClientMain(&MyPlugin{}) 1058 } 1059 `, 1060 `{"id": "testpluginbots", "backend": {"executable": "backend.exe"}}`, 1061 "testpluginbots", 1062 th.App, 1063 ) 1064 1065 hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testpluginbots") 1066 assert.NoError(t, err) 1067 _, errString := hooks.MessageWillBePosted(nil, nil) 1068 assert.Empty(t, errString) 1069 } 1070 1071 func TestPluginAPI_GetTeamMembersForUser(t *testing.T) { 1072 th := Setup(t).InitBasic() 1073 defer th.TearDown() 1074 api := th.SetupPluginAPI() 1075 1076 userId := th.BasicUser.Id 1077 teamMembers, err := api.GetTeamMembersForUser(userId, 0, 10) 1078 assert.Nil(t, err) 1079 assert.Equal(t, len(teamMembers), 1) 1080 assert.Equal(t, teamMembers[0].TeamId, th.BasicTeam.Id) 1081 assert.Equal(t, teamMembers[0].UserId, th.BasicUser.Id) 1082 } 1083 1084 func TestPluginAPI_GetChannelMembersForUser(t *testing.T) { 1085 th := Setup(t).InitBasic() 1086 defer th.TearDown() 1087 api := th.SetupPluginAPI() 1088 1089 userId := th.BasicUser.Id 1090 teamId := th.BasicTeam.Id 1091 channelMembers, err := api.GetChannelMembersForUser(teamId, userId, 0, 10) 1092 1093 assert.Nil(t, err) 1094 assert.Equal(t, len(channelMembers), 3) 1095 assert.Equal(t, channelMembers[0].UserId, th.BasicUser.Id) 1096 }