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