Files
grafana/pkg/services/provisioning/notifiers/config_reader_test.go

328 lines
12 KiB
Go
Raw Normal View History

package notifiers
2018-11-28 16:35:42 +02:00
import (
"fmt"
"os"
2018-11-28 16:35:42 +02:00
"testing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
2018-11-28 16:35:42 +02:00
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/alerting/notifiers"
2018-12-14 11:53:50 +02:00
"github.com/grafana/grafana/pkg/services/sqlstore"
2018-11-28 16:35:42 +02:00
. "github.com/smartystreets/goconvey/convey"
)
var (
correctProperties = "./testdata/test-configs/correct-properties"
incorrectSettings = "./testdata/test-configs/incorrect-settings"
noRequiredFields = "./testdata/test-configs/no-required-fields"
correctPropertiesWithOrgName = "./testdata/test-configs/correct-properties-with-orgName"
brokenYaml = "./testdata/test-configs/broken-yaml"
doubleNotificationsConfig = "./testdata/test-configs/double-default"
emptyFolder = "./testdata/test-configs/empty_folder"
emptyFile = "./testdata/test-configs/empty"
twoNotificationsConfig = "./testdata/test-configs/two-notifications"
unknownNotifier = "./testdata/test-configs/unknown-notifier"
2018-11-28 16:35:42 +02:00
)
func TestNotificationAsConfig(t *testing.T) {
2019-01-28 20:43:53 +01:00
logger := log.New("fake.log")
2018-11-28 16:35:42 +02:00
Convey("Testing notification as configuration", t, func() {
2018-12-14 11:53:50 +02:00
sqlstore.InitTestDB(t)
2018-11-28 16:35:42 +02:00
for i := 1; i < 5; i++ {
orgCommand := models.CreateOrgCommand{Name: fmt.Sprintf("Main Org. %v", i)}
err := sqlstore.CreateOrg(&orgCommand)
So(err, ShouldBeNil)
}
2018-11-28 16:35:42 +02:00
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "slack",
Name: "slack",
Factory: notifiers.NewSlackNotifier,
2018-11-28 16:35:42 +02:00
})
2018-11-28 16:35:42 +02:00
alerting.RegisterNotifier(&alerting.NotifierPlugin{
Type: "email",
Name: "email",
Factory: notifiers.NewEmailNotifier,
2018-11-28 16:35:42 +02:00
})
2018-11-28 16:35:42 +02:00
Convey("Can read correct properties", func() {
_ = os.Setenv("TEST_VAR", "default")
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(correctProperties)
_ = os.Unsetenv("TEST_VAR")
2018-11-28 16:35:42 +02:00
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 1)
ntCfg := cfg[0]
nts := ntCfg.Notifications
So(len(nts), ShouldEqual, 4)
nt := nts[0]
So(nt.Name, ShouldEqual, "default-slack-notification")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 2)
So(nt.UID, ShouldEqual, "notifier1")
2018-11-28 16:35:42 +02:00
So(nt.IsDefault, ShouldBeTrue)
So(nt.Settings, ShouldResemble, map[string]interface{}{
"recipient": "XXX", "token": "xoxb", "uploadImage": true, "url": "https://slack.com",
2018-11-28 16:35:42 +02:00
})
So(nt.SecureSettings, ShouldResemble, map[string]string{
"token": "xoxbsecure", "url": "https://slack.com/secure",
})
So(nt.SendReminder, ShouldBeTrue)
So(nt.Frequency, ShouldEqual, "1h")
2018-11-28 16:35:42 +02:00
nt = nts[1]
So(nt.Name, ShouldEqual, "another-not-default-notification")
So(nt.Type, ShouldEqual, "email")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier2")
2018-11-28 16:35:42 +02:00
So(nt.IsDefault, ShouldBeFalse)
nt = nts[2]
So(nt.Name, ShouldEqual, "check-unset-is_default-is-false")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier3")
2018-11-28 16:35:42 +02:00
So(nt.IsDefault, ShouldBeFalse)
nt = nts[3]
So(nt.Name, ShouldEqual, "Added notification with whitespaces in name")
So(nt.Type, ShouldEqual, "email")
So(nt.UID, ShouldEqual, "notifier4")
So(nt.OrgID, ShouldEqual, 3)
2018-11-28 16:35:42 +02:00
deleteNts := ntCfg.DeleteNotifications
So(len(deleteNts), ShouldEqual, 4)
deleteNt := deleteNts[0]
So(deleteNt.Name, ShouldEqual, "default-slack-notification")
So(deleteNt.UID, ShouldEqual, "notifier1")
So(deleteNt.OrgID, ShouldEqual, 2)
2018-11-28 16:35:42 +02:00
deleteNt = deleteNts[1]
So(deleteNt.Name, ShouldEqual, "deleted-notification-without-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier2")
2018-11-28 16:35:42 +02:00
deleteNt = deleteNts[2]
So(deleteNt.Name, ShouldEqual, "deleted-notification-with-0-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier3")
2018-11-28 16:35:42 +02:00
deleteNt = deleteNts[3]
So(deleteNt.Name, ShouldEqual, "Deleted notification with whitespaces in name")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier4")
2018-11-28 16:35:42 +02:00
})
Convey("One configured notification", func() {
Convey("no notification in database", func() {
dc := newNotificationProvisioner(logger)
err := dc.applyChanges(twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
2018-11-28 16:35:42 +02:00
})
2018-12-14 11:53:50 +02:00
Convey("One notification in database with same name and uid", func() {
existingNotificationCmd := models.CreateAlertNotificationCommand{
2018-12-14 11:53:50 +02:00
Name: "channel1",
OrgId: 1,
Uid: "notifier1",
Type: "slack",
2018-11-28 16:35:42 +02:00
}
2018-12-14 11:53:50 +02:00
err := sqlstore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
So(existingNotificationCmd.Result, ShouldNotBeNil)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
2018-11-28 16:35:42 +02:00
Convey("should update one notification", func() {
dc := newNotificationProvisioner(logger)
2018-12-14 11:53:50 +02:00
err = dc.applyChanges(twoNotificationsConfig)
2018-11-28 16:35:42 +02:00
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
nts := notificationsQuery.Result
nt1 := nts[0]
So(nt1.Type, ShouldEqual, "email")
So(nt1.Name, ShouldEqual, "channel1")
So(nt1.Uid, ShouldEqual, "notifier1")
nt2 := nts[1]
So(nt2.Type, ShouldEqual, "slack")
So(nt2.Name, ShouldEqual, "channel2")
So(nt2.Uid, ShouldEqual, "notifier2")
2018-11-28 16:35:42 +02:00
})
})
Convey("Two notifications with is_default", func() {
dc := newNotificationProvisioner(logger)
err := dc.applyChanges(doubleNotificationsConfig)
Convey("should both be inserted", func() {
So(err, ShouldBeNil)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
So(notificationsQuery.Result[0].IsDefault, ShouldBeTrue)
So(notificationsQuery.Result[1].IsDefault, ShouldBeTrue)
2018-11-28 16:35:42 +02:00
})
})
})
Convey("Two configured notification", func() {
Convey("two other notifications in database", func() {
existingNotificationCmd := models.CreateAlertNotificationCommand{
2018-12-14 11:53:50 +02:00
Name: "channel0",
OrgId: 1,
Uid: "notifier0",
Type: "slack",
}
err := sqlstore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
existingNotificationCmd = models.CreateAlertNotificationCommand{
2018-12-14 11:53:50 +02:00
Name: "channel3",
OrgId: 1,
Uid: "notifier3",
Type: "slack",
2018-11-28 16:35:42 +02:00
}
2018-12-14 11:53:50 +02:00
err = sqlstore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
2018-11-28 16:35:42 +02:00
Convey("should have two new notifications", func() {
dc := newNotificationProvisioner(logger)
err := dc.applyChanges(twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
notificationsQuery = models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 4)
2018-11-28 16:35:42 +02:00
})
})
})
Convey("Can read correct properties with orgName instead of orgId", func() {
existingOrg1 := models.GetOrgByNameQuery{Name: "Main Org. 1"}
err := sqlstore.GetOrgByName(&existingOrg1)
2018-12-14 11:53:50 +02:00
So(err, ShouldBeNil)
So(existingOrg1.Result, ShouldNotBeNil)
existingOrg2 := models.GetOrgByNameQuery{Name: "Main Org. 2"}
err = sqlstore.GetOrgByName(&existingOrg2)
2018-12-14 11:53:50 +02:00
So(err, ShouldBeNil)
So(existingOrg2.Result, ShouldNotBeNil)
existingNotificationCmd := models.CreateAlertNotificationCommand{
2018-12-14 11:53:50 +02:00
Name: "default-notification-delete",
OrgId: existingOrg2.Result.Id,
Uid: "notifier2",
Type: "slack",
}
2018-12-14 11:53:50 +02:00
err = sqlstore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
dc := newNotificationProvisioner(logger)
err = dc.applyChanges(correctPropertiesWithOrgName)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: existingOrg2.Result.Id}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
nt := notificationsQuery.Result[0]
So(nt.Name, ShouldEqual, "default-notification-create")
So(nt.OrgId, ShouldEqual, existingOrg2.Result.Id)
})
2018-12-14 11:53:50 +02:00
Convey("Config doesn't contain required field", func() {
dc := newNotificationProvisioner(logger)
err := dc.applyChanges(noRequiredFields)
2018-12-14 11:53:50 +02:00
So(err, ShouldNotBeNil)
errString := err.Error()
So(errString, ShouldContainSubstring, "Deleted alert notification item 1 in configuration doesn't contain required field uid")
So(errString, ShouldContainSubstring, "Deleted alert notification item 2 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 1 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 2 in configuration doesn't contain required field uid")
})
2018-11-28 16:35:42 +02:00
Convey("Empty yaml file", func() {
Convey("should have not changed repo", func() {
dc := newNotificationProvisioner(logger)
err := dc.applyChanges(emptyFile)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
2018-12-14 11:53:50 +02:00
err = sqlstore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldBeEmpty)
2018-11-28 16:35:42 +02:00
})
})
2018-11-28 16:35:42 +02:00
Convey("Broken yaml should return error", func() {
reader := &configReader{log: log.New("test logger")}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
})
2018-11-28 16:35:42 +02:00
Convey("Skip invalid directory", func() {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(emptyFolder)
2018-11-28 16:35:42 +02:00
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
})
2018-11-28 16:35:42 +02:00
Convey("Unknown notifier should return error", func() {
cfgProvider := &configReader{log: log.New("test logger")}
_, err := cfgProvider.readConfig(unknownNotifier)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, `unsupported notification type "nonexisting"`)
2018-11-28 16:35:42 +02:00
})
Convey("Read incorrect properties", func() {
cfgProvider := &configReader{log: log.New("test logger")}
_, err := cfgProvider.readConfig(incorrectSettings)
So(err, ShouldNotBeNil)
Slack: Use chat.postMessage API by default (#32511) * Slack: Use only chat.postMessage API Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Slack: Check for response error Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Slack: Support custom webhook URL Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Simplify Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rewrite tests to use stdlib Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/services/alerting/notifiers/slack.go Co-authored-by: Dimitris Sotirakis <sotirakis.dim@gmail.com> * Clarify URL field name Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix linting issue Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix up new Slack notifier Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Improve tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix lint Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Slack: Make token not required Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Alerting: Send validation errors back to client Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Document how token is required Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Make recipient required when using Slack API Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix field description Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Dimitris Sotirakis <sotirakis.dim@gmail.com>
2021-04-22 16:00:21 +02:00
So(err.Error(), ShouldEqual, "alert validation error: token must be specified when using the Slack chat API")
})
2018-11-28 16:35:42 +02:00
})
}