From dc54e640c296d50c51858fa50256b3aed9e0a46c Mon Sep 17 00:00:00 2001 From: Carlos Tadeu Panato Junior Date: Tue, 17 Jan 2017 15:01:41 +0100 Subject: Add inbucket docker image to allow local and automated testing of emails (#4901) * add docker container for inbucket * Add way to get the emails using inbucket and add a test for reset password * add config setting to send emails * update TestEmailTest update * add another test and fix wrong assert * update per review fix lint change senders email * Revert config.json to default values for EmailSettings section * update test * add setup to make the test run --- Makefile | 25 +++++++++++ api/admin_test.go | 16 +++++++ api/apitestlib.go | 4 ++ api/post_test.go | 38 +++++++++++++++- api/user_test.go | 16 +++++++ app/apptestlib.go | 1 + app/notification_test.go | 1 + config/config.json | 8 ++-- utils/inbucket.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 218 insertions(+), 6 deletions(-) create mode 100644 utils/inbucket.go diff --git a/Makefile b/Makefile index b4d243fdf..980a9b89d 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,14 @@ start-docker: docker start mattermost-webrtc > /dev/null; \ fi + @if [ $(shell docker ps -a | grep -ci mattermost-inbucket) -eq 0 ]; then \ + echo starting mattermost-inbucket; \ + docker run --name mattermost-inbucket -p 9000:10080 -p 2500:10025 -d jhillyerd/inbucket:latest > /dev/null; \ + elif [ $(shell docker ps | grep -ci mattermost-inbucket) -eq 0 ]; then \ + echo restarting mattermost-inbucket; \ + docker start mattermost-inbucket > /dev/null; \ + fi + ifeq ($(BUILD_ENTERPRISE_READY),true) @echo Ldap test user test.one @if [ $(shell docker ps -a | grep -ci mattermost-openldap) -eq 0 ]; then \ @@ -132,6 +140,11 @@ stop-docker: docker stop mattermost-webrtc > /dev/null; \ fi + @if [ $(shell docker ps -a | grep -ci mattermost-inbucket) -eq 1 ]; then \ + echo stopping mattermost-inbucket; \ + docker stop mattermost-inbucket > /dev/null; \ + fi + clean-docker: @echo Removing docker containers @@ -159,6 +172,12 @@ clean-docker: docker rm -v mattermost-webrtc > /dev/null; \ fi + @if [ $(shell docker ps -a | grep -ci mattermost-inbucket) -eq 1 ]; then \ + echo removing mattermost-inbucket; \ + docker stop mattermost-inbucket > /dev/null; \ + docker rm -v mattermost-inbucket > /dev/null; \ + fi + check-client-style: @echo Checking client style @@ -303,6 +322,12 @@ package: build build-client @# Disable developer settings sed -i'' -e 's|"ConsoleLevel": "DEBUG"|"ConsoleLevel": "INFO"|g' $(DIST_PATH)/config/config.json + @# Reset email sending to original configuration + sed -i'' -e 's|"SendEmailNotifications": true,|"SendEmailNotifications": false,|g' $(DIST_PATH)/config/config.json + sed -i'' -e 's|"FeedbackEmail": "test@example.com",|"FeedbackEmail": "",|g' $(DIST_PATH)/config/config.json + sed -i'' -e 's|"SMTPServer": "dockerhost",|"SMTPServer": "",|g' $(DIST_PATH)/config/config.json + sed -i'' -e 's|"SMTPPort": "2500",|"SMTPPort": "",|g' $(DIST_PATH)/config/config.json + @# Package webapp mkdir -p $(DIST_PATH)/webapp/dist cp -RL $(BUILD_WEBAPP_DIR)/dist $(DIST_PATH)/webapp diff --git a/api/admin_test.go b/api/admin_test.go index f97d76855..801ad8f21 100644 --- a/api/admin_test.go +++ b/api/admin_test.go @@ -160,6 +160,22 @@ func TestRecycleDatabaseConnection(t *testing.T) { func TestEmailTest(t *testing.T) { th := Setup().InitBasic().InitSystemAdmin() + SendEmailNotifications := utils.Cfg.EmailSettings.SendEmailNotifications + SMTPServer := utils.Cfg.EmailSettings.SMTPServer + SMTPPort := utils.Cfg.EmailSettings.SMTPPort + FeedbackEmail := utils.Cfg.EmailSettings.FeedbackEmail + defer func() { + utils.Cfg.EmailSettings.SendEmailNotifications = SendEmailNotifications + utils.Cfg.EmailSettings.SMTPServer = SMTPServer + utils.Cfg.EmailSettings.SMTPPort = SMTPPort + utils.Cfg.EmailSettings.FeedbackEmail = FeedbackEmail + }() + + utils.Cfg.EmailSettings.SendEmailNotifications = false + utils.Cfg.EmailSettings.SMTPServer = "" + utils.Cfg.EmailSettings.SMTPPort = "" + utils.Cfg.EmailSettings.FeedbackEmail = "" + if _, err := th.BasicClient.TestEmail(utils.Cfg); err == nil { t.Fatal("Shouldn't have permissions") } diff --git a/api/apitestlib.go b/api/apitestlib.go index cd54c8e2a..abd4767b7 100644 --- a/api/apitestlib.go +++ b/api/apitestlib.go @@ -59,6 +59,10 @@ func Setup() *TestHelper { utils.InitTranslations(utils.Cfg.LocalizationSettings) utils.Cfg.TeamSettings.MaxUsersPerTeam = 50 *utils.Cfg.RateLimitSettings.Enable = false + utils.Cfg.EmailSettings.SendEmailNotifications = true + utils.Cfg.EmailSettings.SMTPServer = "dockerhost" + utils.Cfg.EmailSettings.SMTPPort = "2500" + utils.Cfg.EmailSettings.FeedbackEmail = "test@example.com" utils.DisableDebugLogForTest() app.NewServer() app.InitStores() diff --git a/api/post_test.go b/api/post_test.go index 95f753da7..151387953 100644 --- a/api/post_test.go +++ b/api/post_test.go @@ -857,11 +857,45 @@ func TestEmailMention(t *testing.T) { th := Setup().InitBasic() Client := th.BasicClient channel1 := th.BasicChannel + Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id)) - post1 := &model.Post{ChannelId: channel1.Id, Message: th.BasicUser.Username} + th.LoginBasic2() + //Set the notification properties + data := make(map[string]string) + data["user_id"] = th.BasicUser2.Id + data["email"] = "true" + data["desktop"] = "all" + data["desktop_sound"] = "false" + data["comments"] = "any" + Client.Must(Client.UpdateUserNotify(data)) + + store.Must(app.Srv.Store.Preference().Save(&model.Preferences{{ + UserId: th.BasicUser2.Id, + Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS, + Name: model.PREFERENCE_NAME_EMAIL_INTERVAL, + Value: "0", + }})) + + //Delete all the messages before create a mention post + utils.DeleteMailBox(th.BasicUser2.Email) + + //Send a mention message from user1 to user2 + th.LoginBasic() + time.Sleep(10 * time.Millisecond) + post1 := &model.Post{ChannelId: channel1.Id, Message: "@" + th.BasicUser2.Username + " this is a test"} post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post) - // No easy way to verify the email was sent, but this will at least cause the server to throw errors if the code is broken + //Check if the email was send to the rigth email address and the mention + if resultsMailbox, err := utils.GetMailBox(th.BasicUser2.Email); err != nil && !strings.ContainsAny(resultsMailbox[0].To[0], th.BasicUser2.Email) { + t.Fatal("Wrong To recipient") + } else { + if resultsEmail, err := utils.GetMessageFromMailbox(th.BasicUser2.Email, resultsMailbox[0].ID); err == nil { + if !strings.Contains(resultsEmail.Body.Text, post1.Message) { + t.Log(resultsEmail.Body.Text) + t.Fatal("Received wrong Message") + } + } + } } diff --git a/api/user_test.go b/api/user_test.go index 3163de078..56064232b 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -1284,6 +1284,9 @@ func TestResetPassword(t *testing.T) { LinkUserToTeam(user, team) store.Must(app.Srv.Store.User().VerifyEmail(user.Id)) + //Delete all the messages before check the reset password + utils.DeleteMailBox(user.Email) + Client.Must(Client.SendPasswordReset(user.Email)) var recovery *model.PasswordRecovery @@ -1293,6 +1296,19 @@ func TestResetPassword(t *testing.T) { recovery = result.Data.(*model.PasswordRecovery) } + //Check if the email was send to the rigth email address and the recovery key match + if resultsMailbox, err := utils.GetMailBox(user.Email); err != nil && !strings.ContainsAny(resultsMailbox[0].To[0], user.Email) { + t.Fatal("Wrong To recipient") + } else { + if resultsEmail, err := utils.GetMessageFromMailbox(user.Email, resultsMailbox[0].ID); err == nil { + if !strings.Contains(resultsEmail.Body.Text, recovery.Code) { + t.Log(resultsEmail.Body.Text) + t.Log(recovery.Code) + t.Fatal("Received wrong recovery code") + } + } + } + if _, err := Client.ResetPassword(recovery.Code, ""); err == nil { t.Fatal("Should have errored - no password") } diff --git a/app/apptestlib.go b/app/apptestlib.go index dee6f0fd9..41e234130 100644 --- a/app/apptestlib.go +++ b/app/apptestlib.go @@ -53,6 +53,7 @@ func Setup() *TestHelper { NewServer() InitStores() StartServer() + utils.InitHTML() utils.EnableDebugLogForTest() Srv.Store.MarkSystemRanUnitTests() diff --git a/app/notification_test.go b/app/notification_test.go index d3aea214c..8554d0af6 100644 --- a/app/notification_test.go +++ b/app/notification_test.go @@ -178,6 +178,7 @@ func TestGetExplicitMentionsAtHere(t *testing.T) { } func TestGetMentionKeywords(t *testing.T) { + Setup() // user with username or custom mentions enabled user1 := &model.User{ Id: model.NewId(), diff --git a/config/config.json b/config/config.json index c979c778b..971e77837 100644 --- a/config/config.json +++ b/config/config.json @@ -109,15 +109,15 @@ "EnableSignUpWithEmail": true, "EnableSignInWithEmail": true, "EnableSignInWithUsername": true, - "SendEmailNotifications": false, + "SendEmailNotifications": true, "RequireEmailVerification": false, "FeedbackName": "", - "FeedbackEmail": "", + "FeedbackEmail": "test@example.com", "FeedbackOrganization": "", "SMTPUsername": "", "SMTPPassword": "", - "SMTPServer": "", - "SMTPPort": "", + "SMTPServer": "dockerhost", + "SMTPPort": "2500", "ConnectionSecurity": "", "InviteSalt": "", "PasswordResetSalt": "", diff --git a/utils/inbucket.go b/utils/inbucket.go new file mode 100644 index 000000000..1c747cee8 --- /dev/null +++ b/utils/inbucket.go @@ -0,0 +1,115 @@ +package utils + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" +) + +const ( + INBUCKET_HOST = "http://dockerhost:9000" + INBUCKET_API = "/api/v1/mailbox/" +) + +// OutputJSONHeader holds the received Header to test sending emails (inbucket) +type JSONMessageHeaderInbucket []struct { + Mailbox string + ID string `json:"Id"` + From, Subject, Date string + To []string + Size int +} + +// OutputJSONMessage holds the received Message fto test sending emails (inbucket) +type JSONMessageInbucket struct { + Mailbox string + ID string `json:"Id"` + From, Subject, Date string + Size int + Header map[string][]string + Body struct { + Text string + HTML string `json:"Html"` + } +} + +func ParseEmail(email string) string { + pos := strings.Index(email, "@") + parsedEmail := email[0:pos] + return parsedEmail +} + +func GetMailBox(email string) (results JSONMessageHeaderInbucket, err error) { + + parsedEmail := ParseEmail(email) + + url := fmt.Sprintf("%s%s%s", INBUCKET_HOST, INBUCKET_API, parsedEmail) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + client := &http.Client{} + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var record JSONMessageHeaderInbucket + if err := json.NewDecoder(resp.Body).Decode(&record); err != nil { + fmt.Println(err) + return nil, err + } + return record, nil +} + +func GetMessageFromMailbox(email, id string) (results JSONMessageInbucket, err error) { + + parsedEmail := ParseEmail(email) + + var record JSONMessageInbucket + + url := fmt.Sprintf("%s%s%s/%s", INBUCKET_HOST, INBUCKET_API, parsedEmail, id) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return record, err + } + + client := &http.Client{} + + resp, err := client.Do(req) + if err != nil { + return record, err + } + defer resp.Body.Close() + + if err := json.NewDecoder(resp.Body).Decode(&record); err != nil { + fmt.Println(err) + return record, err + } + return record, nil +} + +func DeleteMailBox(email string) (err error) { + + parsedEmail := ParseEmail(email) + + url := fmt.Sprintf("%s%s%s", INBUCKET_HOST, INBUCKET_API, parsedEmail) + req, err := http.NewRequest("DELETE", url, nil) + if err != nil { + return err + } + + client := &http.Client{} + + resp, err := client.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + return nil +} -- cgit v1.2.3-1-g7c22