diff --git a/internal/handlers/send_email.go b/internal/handlers/send_email.go index 1a0d9de..aa1c0fa 100644 --- a/internal/handlers/send_email.go +++ b/internal/handlers/send_email.go @@ -11,23 +11,10 @@ import ( "github.com/redhatinsights/mbop/internal/service/mailer" ) +// SendEmails sends the incoming payload's emails through the configured mailer module. func SendEmails(w http.ResponseWriter, r *http.Request) { switch config.Get().MailerModule { case awsModule, printModule: - body, err := io.ReadAll(r.Body) - if err != nil { - do500(w, "failed to read request body: "+err.Error()) - return - } - defer r.Body.Close() - - var emails models.Emails - err = json.Unmarshal(body, &emails) - if err != nil { - do400(w, "failed to parse request body: "+err.Error()) - return - } - // create our mailer (using the correct interface) sender, err := mailer.NewMailer() if err != nil { @@ -36,50 +23,67 @@ func SendEmails(w http.ResponseWriter, r *http.Request) { return } - // The user might have wanted to override the sender that goes in the "from" field of the email. - var fromAddress string - if emails.EmailSender != "" { - fromAddress = emails.EmailSender - } else { - fromAddress = config.Get().FromEmail - } + sendEmails(w, r, sender) + default: + CatchAll(w, r) + } +} - for _, email := range emails.Emails { - // creating a copy in order to pass it down into sub-functions - email := email +// sendEmails reads the unmarshalls the incoming body, and it verifies that it is correct. It determines if the email +// sender was overridden and resolves the specified non-email users through the configured user module. Finally, it +// determines if the default recipient must be grabbed from the config or if, on the other hand, we must set it to what +// the user asked it to be set. +func sendEmails(w http.ResponseWriter, r *http.Request, sender mailer.Emailer) { + body, err := io.ReadAll(r.Body) + if err != nil { + do500(w, "failed to read request body: "+err.Error()) + return + } + defer r.Body.Close() - // Lookup the emails for the given usernames unless the client specified otherwise. - if !emails.SkipUsersResolution { - err := mailer.LookupEmailsForUsernames(r.Context(), &email) - if err != nil { - l.Log.Error(err, "error translating usernames") - continue - } + var emails models.Emails + err = json.Unmarshal(body, &emails) + if err != nil { + do400(w, "failed to parse request body: "+err.Error()) + return + } - if len(email.Recipients) == 0 { - email.Recipients = []string{config.Get().ToEmail} - } - } + // The user might have wanted to override the sender that goes in the "from" field of the email. + var fromAddress string + if emails.EmailSender != "" { + fromAddress = emails.EmailSender + } else { + fromAddress = config.Get().FromEmail + } - // Should the user not specify any recipients, we need to determine if we should use the "default - // recipient" the user might have specified, or the default one that we set up in the configuration. - if len(email.Recipients) == 0 { - if emails.DefaultRecipient != "" { - email.Recipients = []string{emails.DefaultRecipient} - } else { - email.Recipients = []string{config.Get().ToEmail} - } - } + for _, email := range emails.Emails { + // creating a copy in order to pass it down into sub-functions + email := email - err = sender.SendEmail(r.Context(), &email, fromAddress) + // Lookup the emails for the given usernames unless the client specified otherwise. + if !emails.SkipUsersResolution { + err := mailer.LookupEmailsForUsernames(r.Context(), &email) if err != nil { - l.Log.Error(err, "Error sending email", "email", email) + l.Log.Error(err, "error translating usernames") + continue } } - sendJSON(w, newResponse("success")) + // Should the user not specify any recipients, we need to determine if we should use the "default + // recipient" the user might have specified, or the default one that we set up in the configuration. + if len(email.Recipients) == 0 { + if emails.DefaultRecipient == "" { + email.Recipients = []string{config.Get().ToEmail} + } else { + email.Recipients = []string{emails.DefaultRecipient} + } + } - default: - CatchAll(w, r) + err = sender.SendEmail(r.Context(), &email, fromAddress) + if err != nil { + l.Log.Error(err, "Error sending email", "email", email) + } } + + sendJSON(w, newResponse("success")) } diff --git a/internal/handlers/send_email_test.go b/internal/handlers/send_email_test.go new file mode 100644 index 0000000..3ee154b --- /dev/null +++ b/internal/handlers/send_email_test.go @@ -0,0 +1,622 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "github.com/redhatinsights/mbop/internal/config" + "github.com/redhatinsights/mbop/internal/models" + "github.com/redhatinsights/mbop/internal/service/mailer" + "io/ioutil" + "log" + "net/http" + "net/http/httptest" + "os" + "testing" + + l "github.com/redhatinsights/mbop/internal/logger" +) + +// TestMain initializes the logger before running the tests so that we don't suffer from "panics" when the code under +// test attempts to log information. +func TestMain(m *testing.M) { + err := l.Init() + if err != nil { + log.Fatalln(err) + } + + exitCode := m.Run() + + os.Exit(exitCode) +} + +// slicesAreEqual returns true if the given slices are equal. +func slicesAreEqual(t *testing.T, s1 []string, s2 []string) bool { + if len(s1) != len(s2) { + t.Errorf(`slices are not of the same length. Want "%s" and "%s" to be equal`, s1, s2) + + return false + } + + for i := 0; i < len(s1); i++ { + if s1[i] != s2[i] { + t.Errorf(`slices do not contain the same elements. Want "%s" and "%s" to be equal`, s1, s2) + + return false + } + } + + return true +} + +// TestSendEmailsFailedParseBody tests that an invalid incoming payload results in a "bad request" response. +func TestSendEmailsFailedParseBody(t *testing.T) { + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", nil) + writer := httptest.NewRecorder() + + // Call the function under test. + SendEmails(writer, request) + + response := writer.Result() + defer response.Body.Close() + + if response.StatusCode != http.StatusBadRequest { + t.Errorf(`want "%d" status code when sending an invalid JSON payload, got "%d"`, http.StatusBadRequest, response.StatusCode) + } +} + +// TestSendEmails tests that the incoming emails are correctly parsed and processed, and that the output emails to be +// sent to the mailers contain the incoming email's data. +func TestSendEmails(t *testing.T) { + // Mock the incoming payload. + recipients := []string{"a@redhat.com", "a"} + ccList := []string{"copy@redhat.com", "b"} + bccList := []string{"hiddenCopy@redhat.com", "c"} + + email := &models.Email{ + Subject: "subject", + Body: "body", + Recipients: recipients, + CcList: ccList, + BccList: bccList, + BodyType: "html", + } + + emails := &models.Emails{ + Emails: []models.Email{*email}, + } + + // Marshal the mocked body. + requestBody, err := json.Marshal(emails) + if err != nil { + t.Fatalf("unable to marshal the emails model to JSON: %s", err) + } + + // Mock the request and the response writer. + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", bytes.NewBuffer(requestBody)) + writer := httptest.NewRecorder() + + // Change the mailer module to the "mock" one, and make sure that it gets reverted after the test. + originalMailerModule := config.Get().MailerModule + defer func() { + config.Get().MailerModule = originalMailerModule + }() + config.Get().MailerModule = "mock" + + // Use the "mock emailer" module for the test. + sender := &mailer.MockEmailer{} + + // Change the users' module to "mock", and then rever the value to the original one after the test. + originalUsersModule := config.Get().UsersModule + defer func() { + config.Get().UsersModule = originalUsersModule + }() + config.Get().UsersModule = "mock" + + // Call the function under test. + sendEmails(writer, request, sender) + + // Assert that the operation succeeded. + response := writer.Result() + defer response.Body.Close() + + // Assert that we are returning the expected status code. + if response.StatusCode != http.StatusOK { + t.Errorf(`want "%d" status code when the email sending operation succeeds, got "%d"`, http.StatusOK, response.StatusCode) + } + + // Assert that the returned body is the correct one. + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatalf("unable to read the response body after sending an emai: %s", err) + } + + expectedMessageBody := `{"message":"success"}` + if string(responseBody) != expectedMessageBody { + t.Errorf(`unexpected response body. Want "%s", got "%s"`, expectedMessageBody, string(responseBody)) + } + + // Assert that we did not accidentally modify the "from address". + if config.Get().FromEmail != sender.FromAddress { + t.Errorf(`the "from address" email should not have been modified by the test. Want "%s", got "%s"`, config.Get().FromEmail, sender.FromAddress) + } + + // Assert that only one email "was sent". + if 1 != len(sender.Emails) { + t.Errorf("want 1 email to be sent, got %d sent", len(sender.Emails)) + } + + // Assert that the sent email contains the expected fields. + sentEmail := sender.Emails[0] + + // Assert that the subject is correct. + if email.Subject != sentEmail.Subject { + t.Errorf(`unexpected email subject sent. Want "%s", got "%s"`, email.Subject, sentEmail.Subject) + } + + // Assert that the body is correct. + if email.Body != sentEmail.Body { + t.Errorf(`unexpected email body sent. Want "%s", got "%s"`, email.Body, sentEmail.Body) + } + + // Assert that the recipients are correct. + email.Recipients[1] = "a@mocked.biz" + if !slicesAreEqual(t, email.Recipients, sentEmail.Recipients) { + t.Error(`unexpected recipients specified in the sent email`) + } + + // Assert that the CC recipients are correct. + email.CcList[1] = "b@mocked.biz" + if !slicesAreEqual(t, email.CcList, sentEmail.CcList) { + t.Error(`unexpected CC recipients specified in the sent email`) + } + + // Assert that the BCC recipients are correct. + email.BccList[1] = "c@mocked.biz" + if !slicesAreEqual(t, email.BccList, sentEmail.BccList) { + t.Error(`unexpected BCC recipients specified in the sent email`) + } + + // Assert that the specified body type is correct. + if email.BodyType != sentEmail.BodyType { + t.Errorf(`unexpected email body type sent. Want "%s", got "%s"`, email.BodyType, sentEmail.BodyType) + } +} + +// TestSendEmailsOverrideFromAddress tests that the incoming emails are correctly parsed and processed, and that the +// output emails to be sent to the mailers contain the incoming email's data. The "from" address is overridden in the +// incoming payload. +func TestSendEmailsOverrideFromAddress(t *testing.T) { + // Mock the incoming payload. + recipients := []string{"a@redhat.com", "a"} + ccList := []string{"copy@redhat.com", "b"} + bccList := []string{"hiddenCopy@redhat.com", "c"} + + email := &models.Email{ + Subject: "subject", + Body: "body", + Recipients: recipients, + CcList: ccList, + BccList: bccList, + BodyType: "html", + } + + overriddenFromAddress := "custom-from-address@redhat.com" + emails := &models.Emails{ + Emails: []models.Email{*email}, + EmailSender: overriddenFromAddress, + } + + // Marshal the mocked body. + requestBody, err := json.Marshal(emails) + if err != nil { + t.Fatalf("unable to marshal the emails model to JSON: %s", err) + } + + // Mock the request and the response writer. + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", bytes.NewBuffer(requestBody)) + writer := httptest.NewRecorder() + + // Change the mailer module to the "mock" one, and make sure that it gets reverted after the test. + originalMailerModule := config.Get().MailerModule + defer func() { + config.Get().MailerModule = originalMailerModule + }() + config.Get().MailerModule = "mock" + + // Use the "mock emailer" module for the test. + sender := &mailer.MockEmailer{} + + // Change the users' module to "mock", and then rever the value to the original one after the test. + originalUsersModule := config.Get().UsersModule + defer func() { + config.Get().UsersModule = originalUsersModule + }() + config.Get().UsersModule = "mock" + + // Call the function under test. + sendEmails(writer, request, sender) + + // Assert that the operation succeeded. + response := writer.Result() + defer response.Body.Close() + + // Assert that we are returning the expected status code. + if response.StatusCode != http.StatusOK { + t.Errorf(`want "%d" status code when the email sending operation succeeds, got "%d"`, http.StatusOK, response.StatusCode) + } + + // Assert that the returned body is the correct one. + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatalf("unable to read the response body after sending an emai: %s", err) + } + + expectedMessageBody := `{"message":"success"}` + if string(responseBody) != expectedMessageBody { + t.Errorf(`unexpected response body. Want "%s", got "%s"`, expectedMessageBody, string(responseBody)) + } + + // Assert that we did not accidentally modify the "from address". + if overriddenFromAddress != sender.FromAddress { + t.Errorf(`the "from address" should have been overriden. Want "%s", got "%s"`, overriddenFromAddress, sender.FromAddress) + } + + // Assert that only one email "was sent". + if 1 != len(sender.Emails) { + t.Errorf("want 1 email to be sent, got %d sent", len(sender.Emails)) + } + + // Assert that the sent email contains the expected fields. + sentEmail := sender.Emails[0] + + // Assert that the subject is correct. + if email.Subject != sentEmail.Subject { + t.Errorf(`unexpected email subject sent. Want "%s", got "%s"`, email.Subject, sentEmail.Subject) + } + + // Assert that the body is correct. + if email.Body != sentEmail.Body { + t.Errorf(`unexpected email body sent. Want "%s", got "%s"`, email.Body, sentEmail.Body) + } + + // Assert that the recipients are correct. + email.Recipients[1] = "a@mocked.biz" + if !slicesAreEqual(t, email.Recipients, sentEmail.Recipients) { + t.Error(`unexpected recipients specified in the sent email`) + } + + // Assert that the CC recipients are correct. + email.CcList[1] = "b@mocked.biz" + if !slicesAreEqual(t, email.CcList, sentEmail.CcList) { + t.Error(`unexpected CC recipients specified in the sent email`) + } + + // Assert that the BCC recipients are correct. + email.BccList[1] = "c@mocked.biz" + if !slicesAreEqual(t, email.BccList, sentEmail.BccList) { + t.Error(`unexpected BCC recipients specified in the sent email`) + } + + // Assert that the specified body type is correct. + if email.BodyType != sentEmail.BodyType { + t.Errorf(`unexpected email body type sent. Want "%s", got "%s"`, email.BodyType, sentEmail.BodyType) + } +} + +// TestSendEmailsSkipUsersResolution tests that the incoming emails are correctly parsed and processed, and that the +// output emails to be sent to the mailers contain the incoming email's data. It skips the user resolution and asserts +// that the recipients are left untouched. +func TestSendEmailsSkipUsersResolution(t *testing.T) { + // Mock the incoming payload. + recipients := []string{"a@redhat.com", "a"} + ccList := []string{"copy@redhat.com", "b"} + bccList := []string{"hiddenCopy@redhat.com", "c"} + + email := &models.Email{ + Subject: "subject", + Body: "body", + Recipients: recipients, + CcList: ccList, + BccList: bccList, + BodyType: "html", + } + + emails := &models.Emails{ + Emails: []models.Email{*email}, + SkipUsersResolution: true, + } + + // Marshal the mocked body. + requestBody, err := json.Marshal(emails) + if err != nil { + t.Fatalf("unable to marshal the emails model to JSON: %s", err) + } + + // Mock the request and the response writer. + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", bytes.NewBuffer(requestBody)) + writer := httptest.NewRecorder() + + // Change the mailer module to the "mock" one, and make sure that it gets reverted after the test. + originalMailerModule := config.Get().MailerModule + defer func() { + config.Get().MailerModule = originalMailerModule + }() + config.Get().MailerModule = "mock" + + // Use the "mock emailer" module for the test. + sender := &mailer.MockEmailer{} + + // Change the users' module to "mock", and then rever the value to the original one after the test. + originalUsersModule := config.Get().UsersModule + defer func() { + config.Get().UsersModule = originalUsersModule + }() + config.Get().UsersModule = "mock" + + // Call the function under test. + sendEmails(writer, request, sender) + + // Assert that the operation succeeded. + response := writer.Result() + defer response.Body.Close() + + // Assert that we are returning the expected status code. + if response.StatusCode != http.StatusOK { + t.Errorf(`want "%d" status code when the email sending operation succeeds, got "%d"`, http.StatusOK, response.StatusCode) + } + + // Assert that the returned body is the correct one. + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatalf("unable to read the response body after sending an emai: %s", err) + } + + expectedMessageBody := `{"message":"success"}` + if string(responseBody) != expectedMessageBody { + t.Errorf(`unexpected response body. Want "%s", got "%s"`, expectedMessageBody, string(responseBody)) + } + + // Assert that we did not accidentally modify the "from address". + if config.Get().FromEmail != sender.FromAddress { + t.Errorf(`the "from address" email should not have been modified by the test. Want "%s", got "%s"`, config.Get().FromEmail, sender.FromAddress) + } + + // Assert that only one email "was sent". + if 1 != len(sender.Emails) { + t.Errorf("want 1 email to be sent, got %d sent", len(sender.Emails)) + } + + // Assert that the sent email contains the expected fields. + sentEmail := sender.Emails[0] + + // Assert that the subject is correct. + if email.Subject != sentEmail.Subject { + t.Errorf(`unexpected email subject sent. Want "%s", got "%s"`, email.Subject, sentEmail.Subject) + } + + // Assert that the body is correct. + if email.Body != sentEmail.Body { + t.Errorf(`unexpected email body sent. Want "%s", got "%s"`, email.Body, sentEmail.Body) + } + + // Assert that the recipients are correct. + if !slicesAreEqual(t, email.Recipients, sentEmail.Recipients) { + t.Error(`unexpected recipients specified in the sent email`) + } + + // Assert that the CC recipients are correct. + if !slicesAreEqual(t, email.CcList, sentEmail.CcList) { + t.Error(`unexpected CC recipients specified in the sent email`) + } + + // Assert that the BCC recipients are correct. + if !slicesAreEqual(t, email.BccList, sentEmail.BccList) { + t.Error(`unexpected BCC recipients specified in the sent email`) + } + + // Assert that the specified body type is correct. + if email.BodyType != sentEmail.BodyType { + t.Errorf(`unexpected email body type sent. Want "%s", got "%s"`, email.BodyType, sentEmail.BodyType) + } +} + +// TestSendEmailsDefaultRecipientFromConfig tests that the incoming emails are correctly parsed and processed, and that +// the output emails to be sent to the mailers contain the incoming email's data. The default recipient is not +// specified, so it is expected that the default recipient will be grabbed from the configuration. +func TestSendEmailsDefaultRecipientFromConfig(t *testing.T) { + // Mock the incoming payload. + email := &models.Email{ + Subject: "subject", + Body: "body", + BodyType: "html", + } + + emails := &models.Emails{ + Emails: []models.Email{*email}, + } + + // Marshal the mocked body. + requestBody, err := json.Marshal(emails) + if err != nil { + t.Fatalf("unable to marshal the emails model to JSON: %s", err) + } + + // Mock the request and the response writer. + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", bytes.NewBuffer(requestBody)) + writer := httptest.NewRecorder() + + // Change the mailer module to the "mock" one, and make sure that it gets reverted after the test. + originalMailerModule := config.Get().MailerModule + defer func() { + config.Get().MailerModule = originalMailerModule + }() + config.Get().MailerModule = "mock" + + // Use the "mock emailer" module for the test. + sender := &mailer.MockEmailer{} + + // Change the users' module to "mock", and then rever the value to the original one after the test. + originalUsersModule := config.Get().UsersModule + defer func() { + config.Get().UsersModule = originalUsersModule + }() + config.Get().UsersModule = "mock" + + // Call the function under test. + sendEmails(writer, request, sender) + + // Assert that the operation succeeded. + response := writer.Result() + defer response.Body.Close() + + // Assert that we are returning the expected status code. + if response.StatusCode != http.StatusOK { + t.Errorf(`want "%d" status code when the email sending operation succeeds, got "%d"`, http.StatusOK, response.StatusCode) + } + + // Assert that the returned body is the correct one. + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatalf("unable to read the response body after sending an emai: %s", err) + } + + expectedMessageBody := `{"message":"success"}` + if string(responseBody) != expectedMessageBody { + t.Errorf(`unexpected response body. Want "%s", got "%s"`, expectedMessageBody, string(responseBody)) + } + + // Assert that we did not accidentally modify the "from address". + if config.Get().FromEmail != sender.FromAddress { + t.Errorf(`the "from address" email should not have been modified by the test. Want "%s", got "%s"`, config.Get().FromEmail, sender.FromAddress) + } + + // Assert that only one email "was sent". + if 1 != len(sender.Emails) { + t.Errorf("want 1 email to be sent, got %d sent", len(sender.Emails)) + } + + // Assert that the sent email contains the expected fields. + sentEmail := sender.Emails[0] + + // Assert that the subject is correct. + if email.Subject != sentEmail.Subject { + t.Errorf(`unexpected email subject sent. Want "%s", got "%s"`, email.Subject, sentEmail.Subject) + } + + // Assert that the body is correct. + if email.Body != sentEmail.Body { + t.Errorf(`unexpected email body sent. Want "%s", got "%s"`, email.Body, sentEmail.Body) + } + + // Assert that the recipients are correct. + if !slicesAreEqual(t, []string{config.Get().ToEmail}, sentEmail.Recipients) { + t.Error("unexpected default recipient specified. Wanted the default recipient from the configuration.") + } + + // Assert that the specified body type is correct. + if email.BodyType != sentEmail.BodyType { + t.Errorf(`unexpected email body type sent. Want "%s", got "%s"`, email.BodyType, sentEmail.BodyType) + } +} + +// TestSendEmailsDefaultRecipientOverridden tests that the incoming emails are correctly parsed and processed, and that +// the output emails to be sent to the mailers contain the incoming email's data. The default recipient is specified +// in the incoming payload, so it should be overridden. +func TestSendEmailsDefaultRecipientOverridden(t *testing.T) { + // Mock the incoming payload. + email := &models.Email{ + Subject: "subject", + Body: "body", + BodyType: "html", + } + + // Override the default recipient. + defaultRecipient := "default-recipient@redhat.com" + emails := &models.Emails{ + Emails: []models.Email{*email}, + DefaultRecipient: defaultRecipient, + } + + // Marshal the mocked body. + requestBody, err := json.Marshal(emails) + if err != nil { + t.Fatalf("unable to marshal the emails model to JSON: %s", err) + } + + // Mock the request and the response writer. + request := httptest.NewRequest(http.MethodPost, "/v1/sendEmails", bytes.NewBuffer(requestBody)) + writer := httptest.NewRecorder() + + // Change the mailer module to the "mock" one, and make sure that it gets reverted after the test. + originalMailerModule := config.Get().MailerModule + defer func() { + config.Get().MailerModule = originalMailerModule + }() + config.Get().MailerModule = "mock" + + // Use the "mock emailer" module for the test. + sender := &mailer.MockEmailer{} + + // Change the users' module to "mock", and then rever the value to the original one after the test. + originalUsersModule := config.Get().UsersModule + defer func() { + config.Get().UsersModule = originalUsersModule + }() + config.Get().UsersModule = "mock" + + // Call the function under test. + sendEmails(writer, request, sender) + + // Assert that the operation succeeded. + response := writer.Result() + defer response.Body.Close() + + // Assert that we are returning the expected status code. + if response.StatusCode != http.StatusOK { + t.Errorf(`want "%d" status code when the email sending operation succeeds, got "%d"`, http.StatusOK, response.StatusCode) + } + + // Assert that the returned body is the correct one. + responseBody, err := ioutil.ReadAll(response.Body) + if err != nil { + t.Fatalf("unable to read the response body after sending an emai: %s", err) + } + + expectedMessageBody := `{"message":"success"}` + if string(responseBody) != expectedMessageBody { + t.Errorf(`unexpected response body. Want "%s", got "%s"`, expectedMessageBody, string(responseBody)) + } + + // Assert that we did not accidentally modify the "from address". + if config.Get().FromEmail != sender.FromAddress { + t.Errorf(`the "from address" email should not have been modified by the test. Want "%s", got "%s"`, config.Get().FromEmail, sender.FromAddress) + } + + // Assert that only one email "was sent". + if 1 != len(sender.Emails) { + t.Errorf("want 1 email to be sent, got %d sent", len(sender.Emails)) + } + + // Assert that the sent email contains the expected fields. + sentEmail := sender.Emails[0] + + // Assert that the subject is correct. + if email.Subject != sentEmail.Subject { + t.Errorf(`unexpected email subject sent. Want "%s", got "%s"`, email.Subject, sentEmail.Subject) + } + + // Assert that the body is correct. + if email.Body != sentEmail.Body { + t.Errorf(`unexpected email body sent. Want "%s", got "%s"`, email.Body, sentEmail.Body) + } + + // Assert that the recipients are correct. + if !slicesAreEqual(t, []string{defaultRecipient}, sentEmail.Recipients) { + t.Error("unexpected default recipient specified. Wanted the overridden default recipient specified in the payload.") + } + + // Assert that the specified body type is correct. + if email.BodyType != sentEmail.BodyType { + t.Errorf(`unexpected email body type sent. Want "%s", got "%s"`, email.BodyType, sentEmail.BodyType) + } +} diff --git a/internal/service/mailer/mailer_interface.go b/internal/service/mailer/mailer_interface.go index 8975696..bdf9266 100644 --- a/internal/service/mailer/mailer_interface.go +++ b/internal/service/mailer/mailer_interface.go @@ -24,6 +24,8 @@ func NewMailer() (Emailer, error) { } sender = &awsSESEmailer{client: sesv2.NewFromConfig(*cfg)} + case "mock": + sender = &MockEmailer{} case "print": sender = &printEmailer{} default: diff --git a/internal/service/mailer/mock_mailer.go b/internal/service/mailer/mock_mailer.go new file mode 100644 index 0000000..0fd6619 --- /dev/null +++ b/internal/service/mailer/mock_mailer.go @@ -0,0 +1,23 @@ +package mailer + +import ( + "context" + "github.com/redhatinsights/mbop/internal/models" +) + +// MockEmailer is a mocked mailer that is intended to be used for tests. +type MockEmailer struct { + Emails []*models.Email + FromAddress string +} + +// Build flag. +var _ = (Emailer)(&printEmailer{}) + +// SendEmail copies the incoming arguments into the struct to be able to check them afterwards in the tests. +func (m *MockEmailer) SendEmail(_ context.Context, email *models.Email, fromAddress string) error { + m.Emails = append(m.Emails, email) + m.FromAddress = fromAddress + + return nil +}