mirror of
https://github.com/grafana/grafana.git
synced 2024-11-23 09:26:43 -06:00
Alerting: Add integration tests for dual-stage email templating (#43484)
* Resolve merge conflicts * Remove cruft from local exploration * Move integration tests to intercept using new abstraction layer instead of channel * Fix linter error after rebase
This commit is contained in:
parent
4502e40ed8
commit
703d7deeda
@ -10,7 +10,10 @@ import (
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/notifications"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func TestEmailNotifier(t *testing.T) {
|
||||
@ -102,3 +105,202 @@ func TestEmailNotifier(t *testing.T) {
|
||||
}, expected)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEmailNotifierIntegration(t *testing.T) {
|
||||
ns := createCoreEmailService(t)
|
||||
|
||||
emailTmpl := templateForTests(t)
|
||||
externalURL, err := url.Parse("http://localhost/base")
|
||||
require.NoError(t, err)
|
||||
emailTmpl.ExternalURL = externalURL
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
alerts []*types.Alert
|
||||
messageTmpl string
|
||||
expSubject string
|
||||
expSnippets []string
|
||||
}{
|
||||
{
|
||||
name: "single alert with templated message",
|
||||
alerts: []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "AlwaysFiring", "severity": "warning"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageTmpl: `Hi, this is a custom template.
|
||||
{{ if gt (len .Alerts.Firing) 0 }}
|
||||
You have {{ len .Alerts.Firing }} alerts firing.
|
||||
{{ range .Alerts.Firing }} Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} {{ end }}
|
||||
{{ end }}`,
|
||||
expSubject: "[FIRING:1] (AlwaysFiring warning)",
|
||||
expSnippets: []string{
|
||||
"Hi, this is a custom template.",
|
||||
"You have 1 alerts firing.",
|
||||
"Firing: AlwaysFiring at warning",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multiple alerts with templated message",
|
||||
alerts: []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "FiringOne", "severity": "warning"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "FiringTwo", "severity": "critical"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageTmpl: `Hi, this is a custom template.
|
||||
{{ if gt (len .Alerts.Firing) 0 }}
|
||||
You have {{ len .Alerts.Firing }} alerts firing.
|
||||
{{ range .Alerts.Firing }} Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} {{ end }}
|
||||
{{ end }}`,
|
||||
expSubject: "[FIRING:2] ",
|
||||
expSnippets: []string{
|
||||
"Hi, this is a custom template.",
|
||||
"You have 2 alerts firing.",
|
||||
"Firing: FiringOne at warning",
|
||||
"Firing: FiringTwo at critical",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty message with alerts uses default template content",
|
||||
alerts: []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "FiringOne", "severity": "warning"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "FiringTwo", "severity": "critical"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageTmpl: "",
|
||||
expSubject: "[FIRING:2] ",
|
||||
expSnippets: []string{
|
||||
"Firing: 2 alerts",
|
||||
"<li>alertname: FiringOne</li><li>severity: warning</li>",
|
||||
"<li>alertname: FiringTwo</li><li>severity: critical</li>",
|
||||
"<a href=\"http://fix.me\"",
|
||||
"<a href=\"http://localhost/base/d/abc",
|
||||
"<a href=\"http://localhost/base/d/abc?viewPanel=5",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "message containing HTML gets HTMLencoded",
|
||||
alerts: []*types.Alert{
|
||||
{
|
||||
Alert: model.Alert{
|
||||
Labels: model.LabelSet{"alertname": "AlwaysFiring", "severity": "warning"},
|
||||
Annotations: model.LabelSet{"runbook_url": "http://fix.me", "__dashboardUid__": "abc", "__panelId__": "5"},
|
||||
},
|
||||
},
|
||||
},
|
||||
messageTmpl: `<marquee>Hi, this is a custom template.</marquee>
|
||||
{{ if gt (len .Alerts.Firing) 0 }}
|
||||
<ol>
|
||||
{{range .Alerts.Firing }}<li>Firing: {{ .Labels.alertname }} at {{ .Labels.severity }} </li> {{ end }}
|
||||
</ol>
|
||||
{{ end }}`,
|
||||
expSubject: "[FIRING:1] (AlwaysFiring warning)",
|
||||
expSnippets: []string{
|
||||
"<marquee>Hi, this is a custom template.</marquee>",
|
||||
"<li>Firing: AlwaysFiring at warning </li>",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
emailNotifier := createSut(t, c.messageTmpl, emailTmpl, ns)
|
||||
|
||||
ok, err := emailNotifier.Notify(context.Background(), c.alerts...)
|
||||
require.NoError(t, err)
|
||||
require.True(t, ok)
|
||||
|
||||
sentMsg := getSingleSentMessage(t, ns)
|
||||
|
||||
require.NotNil(t, sentMsg)
|
||||
|
||||
require.Equal(t, "\"Grafana Admin\" <from@address.com>", sentMsg.From)
|
||||
require.Equal(t, sentMsg.To[0], "someops@example.com")
|
||||
|
||||
require.Equal(t, c.expSubject, sentMsg.Subject)
|
||||
|
||||
require.Contains(t, sentMsg.Body, "text/html")
|
||||
html := sentMsg.Body["text/html"]
|
||||
require.NotNil(t, html)
|
||||
|
||||
for _, s := range c.expSnippets {
|
||||
require.Contains(t, html, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createCoreEmailService(t *testing.T) *notifications.NotificationService {
|
||||
t.Helper()
|
||||
|
||||
bus := bus.New()
|
||||
cfg := setting.NewCfg()
|
||||
cfg.StaticRootPath = "../../../../../public/"
|
||||
cfg.BuildVersion = "4.0.0"
|
||||
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"}
|
||||
cfg.Smtp.Host = "localhost:1234"
|
||||
mailer := notifications.NewFakeMailer()
|
||||
|
||||
ns, err := notifications.ProvideService(bus, cfg, mailer)
|
||||
require.NoError(t, err)
|
||||
|
||||
return ns
|
||||
}
|
||||
|
||||
func createSut(t *testing.T, messageTmpl string, emailTmpl *template.Template, ns notifications.EmailSender) *EmailNotifier {
|
||||
t.Helper()
|
||||
|
||||
json := `{
|
||||
"addresses": "someops@example.com;somedev@example.com",
|
||||
"singleEmail": true
|
||||
}`
|
||||
settingsJSON, err := simplejson.NewJson([]byte(json))
|
||||
if messageTmpl != "" {
|
||||
settingsJSON.Set("message", messageTmpl)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
emailNotifier, err := NewEmailNotifier(&NotificationChannelConfig{
|
||||
Name: "ops",
|
||||
Type: "email",
|
||||
Settings: settingsJSON,
|
||||
}, ns, emailTmpl)
|
||||
require.NoError(t, err)
|
||||
|
||||
return emailNotifier
|
||||
}
|
||||
|
||||
func getSingleSentMessage(t *testing.T, ns *notifications.NotificationService) *notifications.Message {
|
||||
t.Helper()
|
||||
|
||||
mailer := ns.GetMailer().(*notifications.FakeMailer)
|
||||
require.Len(t, mailer.Sent, 1)
|
||||
sent := mailer.Sent[0]
|
||||
mailer.Sent = []*notifications.Message{}
|
||||
return sent
|
||||
}
|
||||
|
@ -118,6 +118,10 @@ func (ns *NotificationService) Run(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NotificationService) GetMailer() Mailer {
|
||||
return ns.mailer
|
||||
}
|
||||
|
||||
func (ns *NotificationService) SendWebhookSync(ctx context.Context, cmd *models.SendWebhookSync) error {
|
||||
return ns.sendWebRequestSync(ctx, &Webhook{
|
||||
Url: cmd.Url,
|
||||
|
Loading…
Reference in New Issue
Block a user