// +build integration package sqlstore import ( "testing" "time" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" . "github.com/smartystreets/goconvey/convey" ) func mockTimeNow() { var timeSeed int64 timeNow = func() time.Time { loc := time.FixedZone("MockZoneUTC-5", -5*60*60) fakeNow := time.Unix(timeSeed, 0).In(loc) timeSeed++ return fakeNow } } func resetTimeNow() { timeNow = time.Now } func TestAlertingDataAccess(t *testing.T) { mockTimeNow() defer resetTimeNow() Convey("Testing Alerting data access", t, func() { sqlStore := InitTestDB(t) testDash := insertTestDashboard(t, sqlStore, "dashboard with alerts", 1, 0, false, "alert") evalData, err := simplejson.NewJson([]byte(`{"test": "test"}`)) So(err, ShouldBeNil) items := []*models.Alert{ { PanelId: 1, DashboardId: testDash.Id, OrgId: testDash.OrgId, Name: "Alerting title", Message: "Alerting message", Settings: simplejson.New(), Frequency: 1, EvalData: evalData, }, } cmd := models.SaveAlertsCommand{ Alerts: items, DashboardId: testDash.Id, OrgId: 1, UserId: 1, } err = SaveAlerts(&cmd) Convey("Can create one alert", func() { So(err, ShouldBeNil) }) Convey("Can set new states", func() { // Get alert so we can use its ID in tests alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&alertQuery) So(err2, ShouldBeNil) insertedAlert := alertQuery.Result[0] Convey("new state ok", func() { cmd := &models.SetAlertStateCommand{ AlertId: insertedAlert.Id, State: models.AlertStateOK, } err = SetAlertState(cmd) So(err, ShouldBeNil) }) alert, _ := getAlertById(insertedAlert.Id) stateDateBeforePause := alert.NewStateDate Convey("can pause all alerts", func() { err := pauseAllAlerts(true) So(err, ShouldBeNil) Convey("cannot updated paused alert", func() { cmd := &models.SetAlertStateCommand{ AlertId: insertedAlert.Id, State: models.AlertStateOK, } err = SetAlertState(cmd) So(err, ShouldNotBeNil) }) Convey("alert is paused", func() { alert, _ = getAlertById(insertedAlert.Id) currentState := alert.State So(currentState, ShouldEqual, "paused") }) Convey("pausing alerts should update their NewStateDate", func() { alert, _ = getAlertById(insertedAlert.Id) stateDateAfterPause := alert.NewStateDate So(stateDateBeforePause, ShouldHappenBefore, stateDateAfterPause) }) Convey("unpausing alerts should update their NewStateDate again", func() { err := pauseAllAlerts(false) So(err, ShouldBeNil) alert, _ = getAlertById(insertedAlert.Id) stateDateAfterUnpause := alert.NewStateDate So(stateDateBeforePause, ShouldHappenBefore, stateDateAfterUnpause) }) }) }) Convey("Can read properties", func() { alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&alertQuery) alert := alertQuery.Result[0] So(err2, ShouldBeNil) So(alert.Id, ShouldBeGreaterThan, 0) So(alert.DashboardId, ShouldEqual, testDash.Id) So(alert.PanelId, ShouldEqual, 1) So(alert.Name, ShouldEqual, "Alerting title") So(alert.State, ShouldEqual, models.AlertStateUnknown) So(alert.NewStateDate, ShouldNotBeNil) So(alert.EvalData, ShouldNotBeNil) So(alert.EvalData.Get("test").MustString(), ShouldEqual, "test") So(alert.EvalDate, ShouldNotBeNil) So(alert.ExecutionError, ShouldEqual, "") So(alert.DashboardUid, ShouldNotBeNil) So(alert.DashboardSlug, ShouldEqual, "dashboard-with-alerts") }) Convey("Viewer can read alerts", func() { viewerUser := &models.SignedInUser{OrgRole: models.ROLE_VIEWER, OrgId: 1} alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: viewerUser} err2 := HandleAlertsQuery(&alertQuery) So(err2, ShouldBeNil) So(alertQuery.Result, ShouldHaveLength, 1) }) Convey("Alerts with same dashboard id and panel id should update", func() { modifiedItems := items modifiedItems[0].Name = "Name" modifiedCmd := models.SaveAlertsCommand{ DashboardId: testDash.Id, OrgId: 1, UserId: 1, Alerts: modifiedItems, } err := SaveAlerts(&modifiedCmd) Convey("Can save alerts with same dashboard and panel id", func() { So(err, ShouldBeNil) }) Convey("Alerts should be updated", func() { query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(err2, ShouldBeNil) So(len(query.Result), ShouldEqual, 1) So(query.Result[0].Name, ShouldEqual, "Name") Convey("Alert state should not be updated", func() { So(query.Result[0].State, ShouldEqual, models.AlertStateUnknown) }) }) Convey("Updates without changes should be ignored", func() { err3 := SaveAlerts(&modifiedCmd) So(err3, ShouldBeNil) }) }) Convey("Multiple alerts per dashboard", func() { multipleItems := []*models.Alert{ { DashboardId: testDash.Id, PanelId: 1, Name: "1", OrgId: 1, Settings: simplejson.New(), }, { DashboardId: testDash.Id, PanelId: 2, Name: "2", OrgId: 1, Settings: simplejson.New(), }, { DashboardId: testDash.Id, PanelId: 3, Name: "3", OrgId: 1, Settings: simplejson.New(), }, } cmd.Alerts = multipleItems err = SaveAlerts(&cmd) Convey("Should save 3 dashboards", func() { So(err, ShouldBeNil) queryForDashboard := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&queryForDashboard) So(err2, ShouldBeNil) So(len(queryForDashboard.Result), ShouldEqual, 3) }) Convey("should updated two dashboards and delete one", func() { missingOneAlert := multipleItems[:2] cmd.Alerts = missingOneAlert err = SaveAlerts(&cmd) Convey("should delete the missing alert", func() { query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(err2, ShouldBeNil) So(len(query.Result), ShouldEqual, 2) }) }) }) Convey("When dashboard is removed", func() { items := []*models.Alert{ { PanelId: 1, DashboardId: testDash.Id, Name: "Alerting title", Message: "Alerting message", }, } cmd := models.SaveAlertsCommand{ Alerts: items, DashboardId: testDash.Id, OrgId: 1, UserId: 1, } err = SaveAlerts(&cmd) So(err, ShouldBeNil) err = DeleteDashboard(&models.DeleteDashboardCommand{ OrgId: 1, Id: testDash.Id, }) So(err, ShouldBeNil) Convey("Alerts should be removed", func() { query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&query) So(err2, ShouldBeNil) So(len(query.Result), ShouldEqual, 0) }) }) }) } func TestPausingAlerts(t *testing.T) { mockTimeNow() defer resetTimeNow() Convey("Given an alert", t, func() { sqlStore := InitTestDB(t) testDash := insertTestDashboard(t, sqlStore, "dashboard with alerts", 1, 0, false, "alert") alert, err := insertTestAlert("Alerting title", "Alerting message", testDash.OrgId, testDash.Id, simplejson.New()) So(err, ShouldBeNil) stateDateBeforePause := alert.NewStateDate stateDateAfterPause := stateDateBeforePause // Get alert so we can use its ID in tests alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} err2 := HandleAlertsQuery(&alertQuery) So(err2, ShouldBeNil) insertedAlert := alertQuery.Result[0] Convey("when paused", func() { _, err := pauseAlert(testDash.OrgId, insertedAlert.Id, true) So(err, ShouldBeNil) Convey("the NewStateDate should be updated", func() { alert, err := getAlertById(insertedAlert.Id) So(err, ShouldBeNil) stateDateAfterPause = alert.NewStateDate So(stateDateBeforePause, ShouldHappenBefore, stateDateAfterPause) }) }) Convey("when unpaused", func() { _, err := pauseAlert(testDash.OrgId, insertedAlert.Id, false) So(err, ShouldBeNil) Convey("the NewStateDate should be updated again", func() { alert, err := getAlertById(insertedAlert.Id) So(err, ShouldBeNil) stateDateAfterUnpause := alert.NewStateDate So(stateDateAfterPause, ShouldHappenBefore, stateDateAfterUnpause) }) }) }) } func pauseAlert(orgId int64, alertId int64, pauseState bool) (int64, error) { cmd := &models.PauseAlertCommand{ OrgId: orgId, AlertIds: []int64{alertId}, Paused: pauseState, } err := PauseAlert(cmd) So(err, ShouldBeNil) return cmd.ResultCount, err } func insertTestAlert(title string, message string, orgId int64, dashId int64, settings *simplejson.Json) (*models.Alert, error) { items := []*models.Alert{ { PanelId: 1, DashboardId: dashId, OrgId: orgId, Name: title, Message: message, Settings: settings, Frequency: 1, }, } cmd := models.SaveAlertsCommand{ Alerts: items, DashboardId: dashId, OrgId: orgId, UserId: 1, } err := SaveAlerts(&cmd) return cmd.Alerts[0], err } func getAlertById(id int64) (*models.Alert, error) { q := &models.GetAlertByIdQuery{ Id: id, } err := GetAlertById(q) So(err, ShouldBeNil) return q.Result, err } func pauseAllAlerts(pauseState bool) error { cmd := &models.PauseAllAlertCommand{ Paused: pauseState, } err := PauseAllAlerts(cmd) So(err, ShouldBeNil) return err }