grafana/pkg/services/notifications/notifications_test.go
Serge Zaitsev b2ab57d14b
Chore: Remove result field from notifications (#65170)
* remove result field from notifications

* fix test
2023-03-28 13:44:15 +02:00

310 lines
9.0 KiB
Go

package notifications
import (
"context"
"regexp"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
)
func newBus(t *testing.T) bus.Bus {
t.Helper()
tracer := tracing.InitializeTracerForTest()
return bus.ProvideBus(tracer)
}
func TestProvideService(t *testing.T) {
bus := newBus(t)
t.Run("When invalid from_address in configuration", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.FromAddress = "@notanemail@"
_, _, err := createSutWithConfig(t, bus, cfg)
require.Error(t, err)
})
t.Run("When all template_patterns fail to parse", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.TemplatesPatterns = []string{"/usr/not-a-dir/**", "/usr/also-not-a-dir/**"}
_, _, err := createSutWithConfig(t, bus, cfg)
require.Error(t, err)
})
t.Run("When some template_patterns fail to parse", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.TemplatesPatterns = append(cfg.Smtp.TemplatesPatterns, "/usr/not-a-dir/**")
_, _, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
})
}
func TestSendEmailSync(t *testing.T) {
bus := newBus(t)
t.Run("When sending emails synchronously", func(t *testing.T) {
ns, mailer := createSut(t, bus)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"asdf@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
},
}
err := ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.NoError(t, err)
require.NotEmpty(t, mailer.Sent)
sent := mailer.Sent[len(mailer.Sent)-1]
require.Equal(t, "subject", sent.Subject)
require.Equal(t, []string{"asdf@grafana.com"}, sent.To)
})
t.Run("When using Single Email mode with multiple recipients", func(t *testing.T) {
ns, mailer := createSut(t, bus)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: true,
Template: "welcome_on_signup",
},
}
err := ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.NoError(t, err)
require.Len(t, mailer.Sent, 1)
})
t.Run("When using Multi Email mode with multiple recipients", func(t *testing.T) {
ns, mailer := createSut(t, bus)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
},
}
err := ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.NoError(t, err)
require.Len(t, mailer.Sent, 3)
})
t.Run("When attaching files to emails", func(t *testing.T) {
ns, mailer := createSut(t, bus)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"asdf@grafana.com"},
SingleEmail: true,
Template: "welcome_on_signup",
AttachedFiles: []*SendEmailAttachFile{
{
Name: "attachment.txt",
Content: []byte("text file content"),
},
},
},
}
err := ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.NoError(t, err)
require.NotEmpty(t, mailer.Sent)
sent := mailer.Sent[len(mailer.Sent)-1]
require.Len(t, sent.AttachedFiles, 1)
file := sent.AttachedFiles[len(sent.AttachedFiles)-1]
require.Equal(t, "attachment.txt", file.Name)
require.Equal(t, []byte("text file content"), file.Content)
})
t.Run("When SMTP disabled in configuration", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.Enabled = false
ns, mailer, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: true,
Template: "welcome_on_signup",
},
}
err = ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.ErrorIs(t, err, ErrSmtpNotEnabled)
require.Empty(t, mailer.Sent)
})
t.Run("When invalid content type in configuration", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.ContentTypes = append(cfg.Smtp.ContentTypes, "multipart/form-data")
ns, mailer, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
},
}
err = ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.Error(t, err)
require.Empty(t, mailer.Sent)
})
t.Run("When SMTP dialer is disconnected", func(t *testing.T) {
ns := createDisconnectedSut(t, bus)
cmd := &SendEmailCommandSync{
SendEmailCommand: SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
},
}
err := ns.SendEmailCommandHandlerSync(context.Background(), cmd)
require.Error(t, err)
})
}
func TestSendEmailAsync(t *testing.T) {
bus := newBus(t)
t.Run("When sending reset email password", func(t *testing.T) {
sut, _ := createSut(t, bus)
testuser := user.User{Email: "asd@asd.com", Login: "asd@asd.com"}
err := sut.SendResetPasswordEmail(context.Background(), &SendResetPasswordEmailCommand{User: &testuser})
require.NoError(t, err)
sentMsg := <-sut.mailQueue
assert.Contains(t, sentMsg.Body["text/html"], "body")
assert.NotContains(t, sentMsg.Body["text/plain"], "body")
assert.Equal(t, "Reset your Grafana password - asd@asd.com", sentMsg.Subject)
assert.NotContains(t, sentMsg.Body["text/html"], "Subject")
assert.NotContains(t, sentMsg.Body["text/plain"], "Subject")
// find code in mail
r, _ := regexp.Compile(`code=(\w+)`)
match := r.FindString(sentMsg.Body["text/plain"])
code := match[len("code="):]
// verify code
query := ValidateResetPasswordCodeQuery{Code: code}
getUserByLogin := func(ctx context.Context, login string) (*user.User, error) {
return &testuser, nil
}
_, err = sut.ValidateResetPasswordCode(context.Background(), &query, getUserByLogin)
require.NoError(t, err)
})
t.Run("When SMTP disabled in configuration", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.Enabled = false
ns, mailer, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
cmd := &SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: true,
Template: "welcome_on_signup",
}
err = ns.SendEmailCommandHandler(context.Background(), cmd)
require.ErrorIs(t, err, ErrSmtpNotEnabled)
require.Empty(t, mailer.Sent)
})
t.Run("When invalid content type in configuration", func(t *testing.T) {
cfg := createSmtpConfig()
cfg.Smtp.ContentTypes = append(cfg.Smtp.ContentTypes, "multipart/form-data")
ns, mailer, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
cmd := &SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
}
err = ns.SendEmailCommandHandler(context.Background(), cmd)
require.Error(t, err)
require.Empty(t, mailer.Sent)
})
t.Run("When SMTP dialer is disconnected", func(t *testing.T) {
ns := createDisconnectedSut(t, bus)
cmd := &SendEmailCommand{
Subject: "subject",
To: []string{"1@grafana.com", "2@grafana.com", "3@grafana.com"},
SingleEmail: false,
Template: "welcome_on_signup",
}
err := ns.SendEmailCommandHandler(context.Background(), cmd)
// The async version should not surface connection errors via Bus. It should only log them.
require.NoError(t, err)
})
}
func createSut(t *testing.T, bus bus.Bus) (*NotificationService, *FakeMailer) {
t.Helper()
cfg := createSmtpConfig()
ns, fm, err := createSutWithConfig(t, bus, cfg)
require.NoError(t, err)
return ns, fm
}
func createSutWithConfig(t *testing.T, bus bus.Bus, cfg *setting.Cfg) (*NotificationService, *FakeMailer, error) {
smtp := NewFakeMailer()
ns, err := ProvideService(bus, cfg, smtp, nil)
return ns, smtp, err
}
func createDisconnectedSut(t *testing.T, bus bus.Bus) *NotificationService {
t.Helper()
cfg := createSmtpConfig()
smtp := NewFakeDisconnectedMailer()
ns, err := ProvideService(bus, cfg, smtp, nil)
require.NoError(t, err)
return ns
}
func createSmtpConfig() *setting.Cfg {
cfg := setting.NewCfg()
cfg.StaticRootPath = "../../../public/"
cfg.Smtp.Enabled = true
cfg.Smtp.TemplatesPatterns = []string{"emails/*.html", "emails/*.txt"}
cfg.Smtp.FromAddress = "from@address.com"
cfg.Smtp.FromName = "Grafana Admin"
cfg.Smtp.ContentTypes = []string{"text/html", "text/plain"}
return cfg
}