package notifiers import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/alerting" . "github.com/smartystreets/goconvey/convey" ) func TestShouldSendAlertNotification(t *testing.T) { tnow := time.Now() tcs := []struct { name string prevState models.AlertStateType newState models.AlertStateType sendReminder bool frequency time.Duration state *models.AlertNotificationState expect bool }{ { name: "pending -> ok should not trigger an notification", newState: models.AlertStateOK, prevState: models.AlertStatePending, sendReminder: false, expect: false, }, { name: "ok -> alerting should trigger an notification", newState: models.AlertStateAlerting, prevState: models.AlertStateOK, sendReminder: false, expect: true, }, { name: "ok -> pending should not trigger an notification", newState: models.AlertStatePending, prevState: models.AlertStateOK, sendReminder: false, expect: false, }, { name: "ok -> ok should not trigger an notification", newState: models.AlertStateOK, prevState: models.AlertStateOK, sendReminder: false, expect: false, }, { name: "ok -> ok with reminder should not trigger an notification", newState: models.AlertStateOK, prevState: models.AlertStateOK, sendReminder: true, expect: false, }, { name: "alerting -> ok should trigger an notification", newState: models.AlertStateOK, prevState: models.AlertStateAlerting, sendReminder: false, expect: true, }, { name: "alerting -> ok should trigger an notification when reminders enabled", newState: models.AlertStateOK, prevState: models.AlertStateAlerting, frequency: time.Minute * 10, sendReminder: true, state: &models.AlertNotificationState{UpdatedAt: tnow.Add(-time.Minute).Unix()}, expect: true, }, { name: "alerting -> alerting with reminder and no state should trigger", newState: models.AlertStateAlerting, prevState: models.AlertStateAlerting, frequency: time.Minute * 10, sendReminder: true, expect: true, }, { name: "alerting -> alerting with reminder and last notification sent 1 minute ago should not trigger", newState: models.AlertStateAlerting, prevState: models.AlertStateAlerting, frequency: time.Minute * 10, sendReminder: true, state: &models.AlertNotificationState{UpdatedAt: tnow.Add(-time.Minute).Unix()}, expect: false, }, { name: "alerting -> alerting with reminder and last notifciation sent 11 minutes ago should trigger", newState: models.AlertStateAlerting, prevState: models.AlertStateAlerting, frequency: time.Minute * 10, sendReminder: true, state: &models.AlertNotificationState{UpdatedAt: tnow.Add(-11 * time.Minute).Unix()}, expect: true, }, { name: "OK -> alerting with notifciation state pending and updated 30 seconds ago should not trigger", newState: models.AlertStateAlerting, prevState: models.AlertStateOK, state: &models.AlertNotificationState{State: models.AlertNotificationStatePending, UpdatedAt: tnow.Add(-30 * time.Second).Unix()}, expect: false, }, { name: "OK -> alerting with notifciation state pending and updated 2 minutes ago should trigger", newState: models.AlertStateAlerting, prevState: models.AlertStateOK, state: &models.AlertNotificationState{State: models.AlertNotificationStatePending, UpdatedAt: tnow.Add(-2 * time.Minute).Unix()}, expect: true, }, { name: "unknown -> ok", prevState: models.AlertStateUnknown, newState: models.AlertStateOK, expect: false, }, { name: "unknown -> pending", prevState: models.AlertStateUnknown, newState: models.AlertStatePending, expect: false, }, { name: "unknown -> alerting", prevState: models.AlertStateUnknown, newState: models.AlertStateAlerting, expect: true, }, { name: "no_data -> pending", prevState: models.AlertStateNoData, newState: models.AlertStatePending, expect: false, }, } for _, tc := range tcs { evalContext := alerting.NewEvalContext(context.Background(), &alerting.Rule{ State: tc.prevState, }) if tc.state == nil { tc.state = &models.AlertNotificationState{} } evalContext.Rule.State = tc.newState nb := &NotifierBase{SendReminder: tc.sendReminder, Frequency: tc.frequency} r := nb.ShouldNotify(evalContext.Ctx, evalContext, tc.state) assert.Equal(t, r, tc.expect, "failed test %s. expected %+v to return: %v", tc.name, tc, tc.expect) } } func TestBaseNotifier(t *testing.T) { Convey("default constructor for notifiers", t, func() { bJson := simplejson.New() model := &models.AlertNotification{ Uid: "1", Name: "name", Type: "email", Settings: bJson, } Convey("can parse false value", func() { bJson.Set("uploadImage", false) base := NewNotifierBase(model) So(base.UploadImage, ShouldBeFalse) }) Convey("can parse true value", func() { bJson.Set("uploadImage", true) base := NewNotifierBase(model) So(base.UploadImage, ShouldBeTrue) }) Convey("default value should be true for backwards compatibility", func() { base := NewNotifierBase(model) So(base.UploadImage, ShouldBeTrue) }) Convey("default value should be false for backwards compatibility", func() { base := NewNotifierBase(model) So(base.DisableResolveMessage, ShouldBeFalse) }) }) }