diff --git a/pkg/services/sqlstore/alert_notification_test.go b/pkg/services/sqlstore/alert_notification_test.go index 18ba9df943d..bec171a4c6c 100644 --- a/pkg/services/sqlstore/alert_notification_test.go +++ b/pkg/services/sqlstore/alert_notification_test.go @@ -13,400 +13,423 @@ import ( "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func TestAlertNotificationSQLAccess(t *testing.T) { - Convey("Testing Alert notification sql access", t, func() { + var sqlStore *SQLStore + setup := func() { sqlStore := InitTestDB(t) // Set up bus handlers bus.AddHandler("deleteAlertNotification", func(cmd *models.DeleteAlertNotificationCommand) error { return sqlStore.DeleteAlertNotification(cmd) }) + } - Convey("Alert notification state", func() { - var alertID int64 = 7 - var orgID int64 = 5 - var notifierID int64 = 10 - oldTimeNow := timeNow - now := time.Date(2018, 9, 30, 0, 0, 0, 0, time.UTC) - timeNow = func() time.Time { return now } + t.Run("Alert notification state", func(t *testing.T) { + setup() + var alertID int64 = 7 + var orgID int64 = 5 + var notifierID int64 = 10 + oldTimeNow := timeNow + now := time.Date(2018, 9, 30, 0, 0, 0, 0, time.UTC) + timeNow = func() time.Time { return now } - Convey("Get no existing state should create a new state", func() { - query := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} - err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query) - So(err, ShouldBeNil) - So(query.Result, ShouldNotBeNil) - So(query.Result.State, ShouldEqual, "unknown") - So(query.Result.Version, ShouldEqual, 0) - So(query.Result.UpdatedAt, ShouldEqual, now.Unix()) + defer func() { timeNow = oldTimeNow }() - Convey("Get existing state should not create a new state", func() { - query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} - err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2) - So(err, ShouldBeNil) - So(query2.Result, ShouldNotBeNil) - So(query2.Result.Id, ShouldEqual, query.Result.Id) - So(query2.Result.UpdatedAt, ShouldEqual, now.Unix()) + t.Run("Get no existing state should create a new state", func(t *testing.T) { + query := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} + err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query) + require.Nil(t, err) + require.NotNil(t, query.Result) + require.Equal(t, models.AlertNotificationStateUnknown, query.Result.State) + require.Equal(t, int64(0), query.Result.Version) + require.Equal(t, now.Unix(), query.Result.UpdatedAt) + + t.Run("Get existing state should not create a new state", func(t *testing.T) { + query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} + err := sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2) + require.Nil(t, err) + require.NotNil(t, query2.Result) + require.Equal(t, query.Result.Id, query2.Result.Id) + require.Equal(t, now.Unix(), query2.Result.UpdatedAt) + }) + + t.Run("Update existing state to pending with correct version should update database", func(t *testing.T) { + s := *query.Result + + cmd := models.SetAlertNotificationStateToPendingCommand{ + Id: s.Id, + Version: s.Version, + AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, + } + + err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) + require.Nil(t, err) + require.Equal(t, int64(1), cmd.ResultVersion) + + query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} + err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2) + require.Nil(t, err) + require.Equal(t, int64(1), query2.Result.Version) + require.Equal(t, models.AlertNotificationStatePending, query2.Result.State) + require.Equal(t, now.Unix(), query2.Result.UpdatedAt) + + t.Run("Update existing state to completed should update database", func(t *testing.T) { + s := *query.Result + setStateCmd := models.SetAlertNotificationStateToCompleteCommand{ + Id: s.Id, + Version: cmd.ResultVersion, + } + err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &setStateCmd) + require.Nil(t, err) + + query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} + err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3) + require.Nil(t, err) + require.Equal(t, int64(2), query3.Result.Version) + require.Equal(t, models.AlertNotificationStateCompleted, query3.Result.State) + require.Equal(t, now.Unix(), query3.Result.UpdatedAt) }) - Convey("Update existing state to pending with correct version should update database", func() { + t.Run("Update existing state to completed should update database. regardless of version", func(t *testing.T) { s := *query.Result - - cmd := models.SetAlertNotificationStateToPendingCommand{ - Id: s.Id, - Version: s.Version, - AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, + unknownVersion := int64(1000) + cmd := models.SetAlertNotificationStateToCompleteCommand{ + Id: s.Id, + Version: unknownVersion, } + err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &cmd) + require.Nil(t, err) - err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) - So(err, ShouldBeNil) - So(cmd.ResultVersion, ShouldEqual, 1) - - query2 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} - err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query2) - So(err, ShouldBeNil) - So(query2.Result.Version, ShouldEqual, 1) - So(query2.Result.State, ShouldEqual, models.AlertNotificationStatePending) - So(query2.Result.UpdatedAt, ShouldEqual, now.Unix()) - - Convey("Update existing state to completed should update database", func() { - s := *query.Result - setStateCmd := models.SetAlertNotificationStateToCompleteCommand{ - Id: s.Id, - Version: cmd.ResultVersion, - } - err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &setStateCmd) - So(err, ShouldBeNil) - - query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} - err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3) - So(err, ShouldBeNil) - So(query3.Result.Version, ShouldEqual, 2) - So(query3.Result.State, ShouldEqual, models.AlertNotificationStateCompleted) - So(query3.Result.UpdatedAt, ShouldEqual, now.Unix()) - }) - - Convey("Update existing state to completed should update database. regardless of version", func() { - s := *query.Result - unknownVersion := int64(1000) - cmd := models.SetAlertNotificationStateToCompleteCommand{ - Id: s.Id, - Version: unknownVersion, - } - err := sqlStore.SetAlertNotificationStateToCompleteCommand(context.Background(), &cmd) - So(err, ShouldBeNil) - - query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} - err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3) - So(err, ShouldBeNil) - So(query3.Result.Version, ShouldEqual, unknownVersion+1) - So(query3.Result.State, ShouldEqual, models.AlertNotificationStateCompleted) - So(query3.Result.UpdatedAt, ShouldEqual, now.Unix()) - }) - }) - - Convey("Update existing state to pending with incorrect version should return version mismatch error", func() { - s := *query.Result - s.Version = 1000 - cmd := models.SetAlertNotificationStateToPendingCommand{ - Id: s.NotifierId, - Version: s.Version, - AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, - } - err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) - So(err, ShouldEqual, models.ErrAlertNotificationStateVersionConflict) - }) - - Convey("Updating existing state to pending with incorrect version since alert rule state update version is higher", func() { - s := *query.Result - cmd := models.SetAlertNotificationStateToPendingCommand{ - Id: s.Id, - Version: s.Version, - AlertRuleStateUpdatedVersion: 1000, - } - err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) - So(err, ShouldBeNil) - - So(cmd.ResultVersion, ShouldEqual, 1) - }) - - Convey("different version and same alert state change version should return error", func() { - s := *query.Result - s.Version = 1000 - cmd := models.SetAlertNotificationStateToPendingCommand{ - Id: s.Id, - Version: s.Version, - AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, - } - err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) - So(err, ShouldNotBeNil) + query3 := &models.GetOrCreateNotificationStateQuery{AlertId: alertID, OrgId: orgID, NotifierId: notifierID} + err = sqlStore.GetOrCreateAlertNotificationState(context.Background(), query3) + require.Nil(t, err) + require.Equal(t, unknownVersion+1, query3.Result.Version) + require.Equal(t, models.AlertNotificationStateCompleted, query3.Result.State) + require.Equal(t, now.Unix(), query3.Result.UpdatedAt) }) }) - Reset(func() { - timeNow = oldTimeNow + t.Run("Update existing state to pending with incorrect version should return version mismatch error", func(t *testing.T) { + s := *query.Result + s.Version = 1000 + cmd := models.SetAlertNotificationStateToPendingCommand{ + Id: s.NotifierId, + Version: s.Version, + AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, + } + err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) + require.Equal(t, models.ErrAlertNotificationStateVersionConflict, err) + }) + + t.Run("Updating existing state to pending with incorrect version since alert rule state update version is higher", func(t *testing.T) { + s := *query.Result + cmd := models.SetAlertNotificationStateToPendingCommand{ + Id: s.Id, + Version: s.Version, + AlertRuleStateUpdatedVersion: 1000, + } + err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) + require.Nil(t, err) + + require.Equal(t, int64(1), cmd.ResultVersion) + }) + + t.Run("different version and same alert state change version should return error", func(t *testing.T) { + s := *query.Result + s.Version = 1000 + cmd := models.SetAlertNotificationStateToPendingCommand{ + Id: s.Id, + Version: s.Version, + AlertRuleStateUpdatedVersion: s.AlertRuleStateUpdatedVersion, + } + err := sqlStore.SetAlertNotificationStateToPendingCommand(context.Background(), &cmd) + require.Error(t, err) }) }) + }) - Convey("Alert notifications should be empty", func() { - cmd := &models.GetAlertNotificationsQuery{ - OrgId: 2, - Name: "email", - } + t.Run("Alert notifications should be empty", func(t *testing.T) { + setup() + cmd := &models.GetAlertNotificationsQuery{ + OrgId: 2, + Name: "email", + } - err := sqlStore.GetAlertNotifications(cmd) - So(err, ShouldBeNil) - So(cmd.Result, ShouldBeNil) + err := sqlStore.GetAlertNotifications(cmd) + require.Nil(t, err) + require.Nil(t, cmd.Result) + }) + + t.Run("Cannot save alert notifier with send reminder = true", func(t *testing.T) { + setup() + cmd := &models.CreateAlertNotificationCommand{ + Name: "ops", + Type: "email", + OrgId: 1, + SendReminder: true, + Settings: simplejson.New(), + } + + t.Run("and missing frequency", func(t *testing.T) { + err := sqlStore.CreateAlertNotificationCommand(cmd) + require.Equal(t, models.ErrNotificationFrequencyNotFound, err) }) - Convey("Cannot save alert notifier with send reminder = true", func() { - cmd := &models.CreateAlertNotificationCommand{ - Name: "ops", - Type: "email", + t.Run("invalid frequency", func(t *testing.T) { + cmd.Frequency = "invalid duration" + + err := sqlStore.CreateAlertNotificationCommand(cmd) + require.True(t, regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString( + err.Error())) + }) + }) + + t.Run("Cannot update alert notifier with send reminder = false", func(t *testing.T) { + setup() + cmd := &models.CreateAlertNotificationCommand{ + Name: "ops update", + Type: "email", + OrgId: 1, + SendReminder: false, + Settings: simplejson.New(), + } + + err := sqlStore.CreateAlertNotificationCommand(cmd) + require.Nil(t, err) + + updateCmd := &models.UpdateAlertNotificationCommand{ + Id: cmd.Result.Id, + SendReminder: true, + } + + t.Run("and missing frequency", func(t *testing.T) { + err := sqlStore.UpdateAlertNotification(updateCmd) + require.Equal(t, models.ErrNotificationFrequencyNotFound, err) + }) + + t.Run("invalid frequency", func(t *testing.T) { + updateCmd.Frequency = "invalid duration" + + err := sqlStore.UpdateAlertNotification(updateCmd) + require.Error(t, err) + require.True(t, regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString( + err.Error())) + }) + }) + + t.Run("Can save Alert Notification", func(t *testing.T) { + setup() + cmd := &models.CreateAlertNotificationCommand{ + Name: "ops", + Type: "email", + OrgId: 1, + SendReminder: true, + Frequency: "10s", + Settings: simplejson.New(), + } + + err := sqlStore.CreateAlertNotificationCommand(cmd) + require.Nil(t, err) + require.NotEqual(t, 0, cmd.Result.Id) + require.NotEqual(t, 0, cmd.Result.OrgId) + require.Equal(t, "email", cmd.Result.Type) + require.Equal(t, 10*time.Second, cmd.Result.Frequency) + require.False(t, cmd.Result.DisableResolveMessage) + require.NotEmpty(t, cmd.Result.Uid) + + t.Run("Cannot save Alert Notification with the same name", func(t *testing.T) { + err = sqlStore.CreateAlertNotificationCommand(cmd) + require.Error(t, err) + }) + t.Run("Cannot save Alert Notification with the same name and another uid", func(t *testing.T) { + anotherUidCmd := &models.CreateAlertNotificationCommand{ + Name: cmd.Name, + Type: cmd.Type, OrgId: 1, - SendReminder: true, - Settings: simplejson.New(), + SendReminder: cmd.SendReminder, + Frequency: cmd.Frequency, + Settings: cmd.Settings, + Uid: "notifier1", } - - Convey("and missing frequency", func() { - err := sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldEqual, models.ErrNotificationFrequencyNotFound) - }) - - Convey("invalid frequency", func() { - cmd.Frequency = "invalid duration" - - err := sqlStore.CreateAlertNotificationCommand(cmd) - So(regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString( - err.Error()), ShouldBeTrue) - }) + err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd) + require.Error(t, err) + }) + t.Run("Can save Alert Notification with another name and another uid", func(t *testing.T) { + anotherUidCmd := &models.CreateAlertNotificationCommand{ + Name: "another ops", + Type: cmd.Type, + OrgId: 1, + SendReminder: cmd.SendReminder, + Frequency: cmd.Frequency, + Settings: cmd.Settings, + Uid: "notifier2", + } + err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd) + require.Nil(t, err) }) - Convey("Cannot update alert notifier with send reminder = false", func() { - cmd := &models.CreateAlertNotificationCommand{ - Name: "ops update", - Type: "email", - OrgId: 1, + t.Run("Can update alert notification", func(t *testing.T) { + newCmd := &models.UpdateAlertNotificationCommand{ + Name: "NewName", + Type: "webhook", + OrgId: cmd.Result.OrgId, + SendReminder: true, + DisableResolveMessage: true, + Frequency: "60s", + Settings: simplejson.New(), + Id: cmd.Result.Id, + } + err := sqlStore.UpdateAlertNotification(newCmd) + require.Nil(t, err) + require.Equal(t, "NewName", newCmd.Result.Name) + require.Equal(t, 60*time.Second, newCmd.Result.Frequency) + require.True(t, newCmd.Result.DisableResolveMessage) + }) + + t.Run("Can update alert notification to disable sending of reminders", func(t *testing.T) { + newCmd := &models.UpdateAlertNotificationCommand{ + Name: "NewName", + Type: "webhook", + OrgId: cmd.Result.OrgId, SendReminder: false, Settings: simplejson.New(), - } - - err := sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldBeNil) - - updateCmd := &models.UpdateAlertNotificationCommand{ Id: cmd.Result.Id, - SendReminder: true, + } + err := sqlStore.UpdateAlertNotification(newCmd) + require.Nil(t, err) + require.False(t, newCmd.Result.SendReminder) + }) + }) + + t.Run("Can search using an array of ids", func(t *testing.T) { + setup() + cmd1 := models.CreateAlertNotificationCommand{Name: "nagios", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + cmd2 := models.CreateAlertNotificationCommand{Name: "slack", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + cmd3 := models.CreateAlertNotificationCommand{Name: "ops2", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + cmd4 := models.CreateAlertNotificationCommand{IsDefault: true, Name: "default", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + + otherOrg := models.CreateAlertNotificationCommand{Name: "default", Type: "email", OrgId: 2, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + + require.Nil(t, sqlStore.CreateAlertNotificationCommand(&cmd1)) + require.Nil(t, sqlStore.CreateAlertNotificationCommand(&cmd2)) + require.Nil(t, sqlStore.CreateAlertNotificationCommand(&cmd3)) + require.Nil(t, sqlStore.CreateAlertNotificationCommand(&cmd4)) + require.Nil(t, sqlStore.CreateAlertNotificationCommand(&otherOrg)) + + t.Run("search", func(t *testing.T) { + query := &models.GetAlertNotificationsWithUidToSendQuery{ + Uids: []string{cmd1.Result.Uid, cmd2.Result.Uid, "112341231"}, + OrgId: 1, } - Convey("and missing frequency", func() { - err := sqlStore.UpdateAlertNotification(updateCmd) - So(err, ShouldEqual, models.ErrNotificationFrequencyNotFound) - }) - - Convey("invalid frequency", func() { - updateCmd.Frequency = "invalid duration" - - err := sqlStore.UpdateAlertNotification(updateCmd) - So(err, ShouldNotBeNil) - So(regexp.MustCompile(`^time: invalid duration "?invalid duration"?$`).MatchString( - err.Error()), ShouldBeTrue) - }) + err := sqlStore.GetAlertNotificationsWithUidToSend(query) + require.Nil(t, err) + require.Equal(t, 3, len(query.Result)) }) - Convey("Can save Alert Notification", func() { - cmd := &models.CreateAlertNotificationCommand{ - Name: "ops", - Type: "email", - OrgId: 1, - SendReminder: true, - Frequency: "10s", - Settings: simplejson.New(), + t.Run("all", func(t *testing.T) { + query := &models.GetAllAlertNotificationsQuery{ + OrgId: 1, } - err := sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldBeNil) - So(cmd.Result.Id, ShouldNotEqual, 0) - So(cmd.Result.OrgId, ShouldNotEqual, 0) - So(cmd.Result.Type, ShouldEqual, "email") - So(cmd.Result.Frequency, ShouldEqual, 10*time.Second) - So(cmd.Result.DisableResolveMessage, ShouldBeFalse) - So(cmd.Result.Uid, ShouldNotBeEmpty) - - Convey("Cannot save Alert Notification with the same name", func() { - err = sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldNotBeNil) - }) - Convey("Cannot save Alert Notification with the same name and another uid", func() { - anotherUidCmd := &models.CreateAlertNotificationCommand{ - Name: cmd.Name, - Type: cmd.Type, - OrgId: 1, - SendReminder: cmd.SendReminder, - Frequency: cmd.Frequency, - Settings: cmd.Settings, - Uid: "notifier1", - } - err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd) - So(err, ShouldNotBeNil) - }) - Convey("Can save Alert Notification with another name and another uid", func() { - anotherUidCmd := &models.CreateAlertNotificationCommand{ - Name: "another ops", - Type: cmd.Type, - OrgId: 1, - SendReminder: cmd.SendReminder, - Frequency: cmd.Frequency, - Settings: cmd.Settings, - Uid: "notifier2", - } - err = sqlStore.CreateAlertNotificationCommand(anotherUidCmd) - So(err, ShouldBeNil) - }) - - Convey("Can update alert notification", func() { - newCmd := &models.UpdateAlertNotificationCommand{ - Name: "NewName", - Type: "webhook", - OrgId: cmd.Result.OrgId, - SendReminder: true, - DisableResolveMessage: true, - Frequency: "60s", - Settings: simplejson.New(), - Id: cmd.Result.Id, - } - err := sqlStore.UpdateAlertNotification(newCmd) - So(err, ShouldBeNil) - So(newCmd.Result.Name, ShouldEqual, "NewName") - So(newCmd.Result.Frequency, ShouldEqual, 60*time.Second) - So(newCmd.Result.DisableResolveMessage, ShouldBeTrue) - }) - - Convey("Can update alert notification to disable sending of reminders", func() { - newCmd := &models.UpdateAlertNotificationCommand{ - Name: "NewName", - Type: "webhook", - OrgId: cmd.Result.OrgId, - SendReminder: false, - Settings: simplejson.New(), - Id: cmd.Result.Id, - } - err := sqlStore.UpdateAlertNotification(newCmd) - So(err, ShouldBeNil) - So(newCmd.Result.SendReminder, ShouldBeFalse) - }) + err := sqlStore.GetAllAlertNotifications(query) + require.Nil(t, err) + require.Equal(t, 4, len(query.Result)) + require.Equal(t, cmd4.Name, query.Result[0].Name) + require.Equal(t, cmd1.Name, query.Result[1].Name) + require.Equal(t, cmd3.Name, query.Result[2].Name) + require.Equal(t, cmd2.Name, query.Result[3].Name) }) + }) - Convey("Can search using an array of ids", func() { - cmd1 := models.CreateAlertNotificationCommand{Name: "nagios", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} - cmd2 := models.CreateAlertNotificationCommand{Name: "slack", Type: "webhook", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} - cmd3 := models.CreateAlertNotificationCommand{Name: "ops2", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} - cmd4 := models.CreateAlertNotificationCommand{IsDefault: true, Name: "default", Type: "email", OrgId: 1, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + t.Run("Notification Uid by Id Caching", func(t *testing.T) { + setup() + ss := InitTestDB(t) - otherOrg := models.CreateAlertNotificationCommand{Name: "default", Type: "email", OrgId: 2, SendReminder: true, Frequency: "10s", Settings: simplejson.New()} + notification := &models.CreateAlertNotificationCommand{Uid: "aNotificationUid", OrgId: 1, Name: "aNotificationUid"} + err := sqlStore.CreateAlertNotificationCommand(notification) + require.Nil(t, err) - So(sqlStore.CreateAlertNotificationCommand(&cmd1), ShouldBeNil) - So(sqlStore.CreateAlertNotificationCommand(&cmd2), ShouldBeNil) - So(sqlStore.CreateAlertNotificationCommand(&cmd3), ShouldBeNil) - So(sqlStore.CreateAlertNotificationCommand(&cmd4), ShouldBeNil) - So(sqlStore.CreateAlertNotificationCommand(&otherOrg), ShouldBeNil) + byUidQuery := &models.GetAlertNotificationsWithUidQuery{ + Uid: notification.Uid, + OrgId: notification.OrgId, + } - Convey("search", func() { - query := &models.GetAlertNotificationsWithUidToSendQuery{ - Uids: []string{cmd1.Result.Uid, cmd2.Result.Uid, "112341231"}, - OrgId: 1, - } + notificationByUidErr := sqlStore.GetAlertNotificationsWithUid(byUidQuery) + require.Nil(t, notificationByUidErr) - err := sqlStore.GetAlertNotificationsWithUidToSend(query) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 3) - }) - - Convey("all", func() { - query := &models.GetAllAlertNotificationsQuery{ - OrgId: 1, - } - - err := sqlStore.GetAllAlertNotifications(query) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 4) - So(query.Result[0].Name, ShouldEqual, cmd4.Name) - So(query.Result[1].Name, ShouldEqual, cmd1.Name) - So(query.Result[2].Name, ShouldEqual, cmd3.Name) - So(query.Result[3].Name, ShouldEqual, cmd2.Name) - }) - }) - - Convey("Notification Uid by Id Caching", func() { - ss := InitTestDB(t) - - notification := &models.CreateAlertNotificationCommand{Uid: "aNotificationUid", OrgId: 1, Name: "aNotificationUid"} - err := sqlStore.CreateAlertNotificationCommand(notification) - So(err, ShouldBeNil) - - byUidQuery := &models.GetAlertNotificationsWithUidQuery{ - Uid: notification.Uid, - OrgId: notification.OrgId, + t.Run("Can cache notification Uid", func(t *testing.T) { + byIdQuery := &models.GetAlertNotificationUidQuery{ + Id: byUidQuery.Result.Id, + OrgId: byUidQuery.Result.OrgId, } - notificationByUidErr := sqlStore.GetAlertNotificationsWithUid(byUidQuery) - So(notificationByUidErr, ShouldBeNil) + cacheKey := newAlertNotificationUidCacheKey(byIdQuery.OrgId, byIdQuery.Id) - Convey("Can cache notification Uid", func() { - byIdQuery := &models.GetAlertNotificationUidQuery{ - Id: byUidQuery.Result.Id, - OrgId: byUidQuery.Result.OrgId, - } + resultBeforeCaching, foundBeforeCaching := ss.CacheService.Get(cacheKey) + require.False(t, foundBeforeCaching) + require.Nil(t, resultBeforeCaching) - cacheKey := newAlertNotificationUidCacheKey(byIdQuery.OrgId, byIdQuery.Id) + notificationByIdErr := ss.GetAlertNotificationUidWithId(byIdQuery) + require.Nil(t, notificationByIdErr) - resultBeforeCaching, foundBeforeCaching := ss.CacheService.Get(cacheKey) - So(foundBeforeCaching, ShouldBeFalse) - So(resultBeforeCaching, ShouldBeNil) - - notificationByIdErr := ss.GetAlertNotificationUidWithId(byIdQuery) - So(notificationByIdErr, ShouldBeNil) - - resultAfterCaching, foundAfterCaching := ss.CacheService.Get(cacheKey) - So(foundAfterCaching, ShouldBeTrue) - So(resultAfterCaching, ShouldEqual, notification.Uid) - }) - - Convey("Retrieves from cache when exists", func() { - query := &models.GetAlertNotificationUidQuery{ - Id: 999, - OrgId: 100, - } - cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id) - ss.CacheService.Set(cacheKey, "a-cached-uid", -1) - - err := ss.GetAlertNotificationUidWithId(query) - So(err, ShouldBeNil) - So(query.Result, ShouldEqual, "a-cached-uid") - }) - - Convey("Returns an error without populating cache when the notification doesn't exist in the database", func() { - query := &models.GetAlertNotificationUidQuery{ - Id: -1, - OrgId: 100, - } - - err := ss.GetAlertNotificationUidWithId(query) - So(query.Result, ShouldEqual, "") - So(err, ShouldNotBeNil) - So(errors.Is(err, models.ErrAlertNotificationFailedTranslateUniqueID), ShouldBeTrue) - - cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id) - result, found := ss.CacheService.Get(cacheKey) - So(found, ShouldBeFalse) - So(result, ShouldBeNil) - }) + resultAfterCaching, foundAfterCaching := ss.CacheService.Get(cacheKey) + require.True(t, foundAfterCaching) + require.Equal(t, notification.Uid, resultAfterCaching) }) - Convey("Cannot update non-existing Alert Notification", func() { - updateCmd := &models.UpdateAlertNotificationCommand{ + t.Run("Retrieves from cache when exists", func(t *testing.T) { + query := &models.GetAlertNotificationUidQuery{ + Id: 999, + OrgId: 100, + } + cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id) + ss.CacheService.Set(cacheKey, "a-cached-uid", -1) + + err := ss.GetAlertNotificationUidWithId(query) + require.Nil(t, err) + require.Equal(t, "a-cached-uid", query.Result) + }) + + t.Run("Returns an error without populating cache when the notification doesn't exist in the database", func(t *testing.T) { + query := &models.GetAlertNotificationUidQuery{ + Id: -1, + OrgId: 100, + } + + err := ss.GetAlertNotificationUidWithId(query) + require.Equal(t, "", query.Result) + require.Error(t, err) + require.True(t, errors.Is(err, models.ErrAlertNotificationFailedTranslateUniqueID)) + + cacheKey := newAlertNotificationUidCacheKey(query.OrgId, query.Id) + result, found := ss.CacheService.Get(cacheKey) + require.False(t, found) + require.Nil(t, result) + }) + }) + + t.Run("Cannot update non-existing Alert Notification", func(t *testing.T) { + setup() + updateCmd := &models.UpdateAlertNotificationCommand{ + Name: "NewName", + Type: "webhook", + OrgId: 1, + SendReminder: true, + DisableResolveMessage: true, + Frequency: "60s", + Settings: simplejson.New(), + Id: 1, + } + err := sqlStore.UpdateAlertNotification(updateCmd) + require.Equal(t, models.ErrAlertNotificationNotFound, err) + + t.Run("using UID", func(t *testing.T) { + updateWithUidCmd := &models.UpdateAlertNotificationWithUidCommand{ Name: "NewName", Type: "webhook", OrgId: 1, @@ -414,78 +437,65 @@ func TestAlertNotificationSQLAccess(t *testing.T) { DisableResolveMessage: true, Frequency: "60s", Settings: simplejson.New(), - Id: 1, + Uid: "uid", + NewUid: "newUid", } - err := sqlStore.UpdateAlertNotification(updateCmd) - So(err, ShouldEqual, models.ErrAlertNotificationNotFound) - - Convey("using UID", func() { - updateWithUidCmd := &models.UpdateAlertNotificationWithUidCommand{ - Name: "NewName", - Type: "webhook", - OrgId: 1, - SendReminder: true, - DisableResolveMessage: true, - Frequency: "60s", - Settings: simplejson.New(), - Uid: "uid", - NewUid: "newUid", - } - err := sqlStore.UpdateAlertNotificationWithUid(updateWithUidCmd) - So(err, ShouldEqual, models.ErrAlertNotificationNotFound) - }) + err := sqlStore.UpdateAlertNotificationWithUid(updateWithUidCmd) + require.Equal(t, models.ErrAlertNotificationNotFound, err) }) + }) - Convey("Can delete Alert Notification", func() { - cmd := &models.CreateAlertNotificationCommand{ - Name: "ops update", - Type: "email", - OrgId: 1, - SendReminder: false, - Settings: simplejson.New(), - } + t.Run("Can delete Alert Notification", func(t *testing.T) { + setup() + cmd := &models.CreateAlertNotificationCommand{ + Name: "ops update", + Type: "email", + OrgId: 1, + SendReminder: false, + Settings: simplejson.New(), + } + err := sqlStore.CreateAlertNotificationCommand(cmd) + require.Nil(t, err) + + deleteCmd := &models.DeleteAlertNotificationCommand{ + Id: cmd.Result.Id, + OrgId: 1, + } + err = sqlStore.DeleteAlertNotification(deleteCmd) + require.Nil(t, err) + + t.Run("using UID", func(t *testing.T) { err := sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldBeNil) + require.Nil(t, err) - deleteCmd := &models.DeleteAlertNotificationCommand{ - Id: cmd.Result.Id, + deleteWithUidCmd := &models.DeleteAlertNotificationWithUidCommand{ + Uid: cmd.Result.Uid, OrgId: 1, } - err = sqlStore.DeleteAlertNotification(deleteCmd) - So(err, ShouldBeNil) - Convey("using UID", func() { - err := sqlStore.CreateAlertNotificationCommand(cmd) - So(err, ShouldBeNil) - - deleteWithUidCmd := &models.DeleteAlertNotificationWithUidCommand{ - Uid: cmd.Result.Uid, - OrgId: 1, - } - - err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd) - So(err, ShouldBeNil) - So(deleteWithUidCmd.DeletedAlertNotificationId, ShouldEqual, cmd.Result.Id) - }) + err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd) + require.Nil(t, err) + require.Equal(t, cmd.Result.Id, deleteWithUidCmd.DeletedAlertNotificationId) }) + }) - Convey("Cannot delete non-existing Alert Notification", func() { - deleteCmd := &models.DeleteAlertNotificationCommand{ - Id: 1, + t.Run("Cannot delete non-existing Alert Notification", func(t *testing.T) { + setup() + deleteCmd := &models.DeleteAlertNotificationCommand{ + Id: 1, + OrgId: 1, + } + err := sqlStore.DeleteAlertNotification(deleteCmd) + require.Equal(t, models.ErrAlertNotificationNotFound, err) + + t.Run("using UID", func(t *testing.T) { + deleteWithUidCmd := &models.DeleteAlertNotificationWithUidCommand{ + Uid: "uid", OrgId: 1, } - err := sqlStore.DeleteAlertNotification(deleteCmd) - So(err, ShouldEqual, models.ErrAlertNotificationNotFound) - - Convey("using UID", func() { - deleteWithUidCmd := &models.DeleteAlertNotificationWithUidCommand{ - Uid: "uid", - OrgId: 1, - } - err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd) - So(err, ShouldEqual, models.ErrAlertNotificationNotFound) - }) + err = sqlStore.DeleteAlertNotificationWithUid(deleteWithUidCmd) + require.Equal(t, models.ErrAlertNotificationNotFound, err) }) }) } diff --git a/pkg/services/sqlstore/alert_test.go b/pkg/services/sqlstore/alert_test.go index d461de62a35..84b4cf9ec60 100644 --- a/pkg/services/sqlstore/alert_test.go +++ b/pkg/services/sqlstore/alert_test.go @@ -10,7 +10,8 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func mockTimeNow() { @@ -31,13 +32,18 @@ func TestAlertingDataAccess(t *testing.T) { mockTimeNow() defer resetTimeNow() - Convey("Testing Alerting data access", t, func() { - sqlStore := InitTestDB(t) + var sqlStore *SQLStore + var testDash *models.Dashboard + var cmd models.SaveAlertsCommand + var items []*models.Alert - testDash := insertTestDashboard(t, sqlStore, "dashboard with alerts", 1, 0, false, "alert") + setup := func(t *testing.T) { + 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{ + require.Nil(t, err) + items = []*models.Alert{ { PanelId: 1, DashboardId: testDash.Id, @@ -50,7 +56,7 @@ func TestAlertingDataAccess(t *testing.T) { }, } - cmd := models.SaveAlertsCommand{ + cmd = models.SaveAlertsCommand{ Alerts: items, DashboardId: testDash.Id, OrgId: 1, @@ -58,234 +64,237 @@ func TestAlertingDataAccess(t *testing.T) { } err = SaveAlerts(&cmd) + require.Nil(t, err) + } - Convey("Can create one alert", func() { - So(err, ShouldBeNil) + t.Run("Can set new states", func(t *testing.T) { + setup(t) + + // 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) + require.Nil(t, err2) + + insertedAlert := alertQuery.Result[0] + + t.Run("new state ok", func(t *testing.T) { + cmd := &models.SetAlertStateCommand{ + AlertId: insertedAlert.Id, + State: models.AlertStateOK, + } + + err := SetAlertState(cmd) + require.Nil(t, err) }) - Convey("Can set new states", func() { + alert, _ := getAlertById(t, insertedAlert.Id) + stateDateBeforePause := alert.NewStateDate - // 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) + t.Run("can pause all alerts", func(t *testing.T) { + err := pauseAllAlerts(t, true) + require.Nil(t, err) - insertedAlert := alertQuery.Result[0] - - Convey("new state ok", func() { + t.Run("cannot updated paused alert", func(t *testing.T) { cmd := &models.SetAlertStateCommand{ AlertId: insertedAlert.Id, State: models.AlertStateOK, } err = SetAlertState(cmd) - So(err, ShouldBeNil) + require.Error(t, err) }) - alert, _ := getAlertById(insertedAlert.Id) - stateDateBeforePause := alert.NewStateDate + t.Run("alert is paused", func(t *testing.T) { + alert, _ = getAlertById(t, insertedAlert.Id) + currentState := alert.State + require.Equal(t, models.AlertStatePaused, currentState) + }) - Convey("can pause all alerts", func() { - err := pauseAllAlerts(true) - So(err, ShouldBeNil) + t.Run("pausing alerts should update their NewStateDate", func(t *testing.T) { + alert, _ = getAlertById(t, insertedAlert.Id) + stateDateAfterPause := alert.NewStateDate + require.True(t, stateDateBeforePause.Before(stateDateAfterPause)) + }) - Convey("cannot updated paused alert", func() { - cmd := &models.SetAlertStateCommand{ - AlertId: insertedAlert.Id, - State: models.AlertStateOK, - } + t.Run("unpausing alerts should update their NewStateDate again", func(t *testing.T) { + err := pauseAllAlerts(t, false) + require.Nil(t, err) + alert, _ = getAlertById(t, insertedAlert.Id) + stateDateAfterUnpause := alert.NewStateDate + require.True(t, stateDateBeforePause.Before(stateDateAfterUnpause)) + }) + }) + }) - err = SetAlertState(cmd) - So(err, ShouldNotBeNil) - }) + t.Run("Can read properties", func(t *testing.T) { + setup(t) + alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} + err2 := HandleAlertsQuery(&alertQuery) - Convey("alert is paused", func() { - alert, _ = getAlertById(insertedAlert.Id) - currentState := alert.State - So(currentState, ShouldEqual, "paused") - }) + alert := alertQuery.Result[0] + require.Nil(t, err2) + require.Greater(t, alert.Id, int64(0)) + require.Equal(t, testDash.Id, alert.DashboardId) + require.Equal(t, int64(1), alert.PanelId) + require.Equal(t, "Alerting title", alert.Name) + require.Equal(t, models.AlertStateUnknown, alert.State) + require.NotNil(t, alert.NewStateDate) + require.NotNil(t, alert.EvalData) + require.Equal(t, "test", alert.EvalData.Get("test").MustString()) + require.NotNil(t, alert.EvalDate) + require.Equal(t, "", alert.ExecutionError) + require.NotNil(t, alert.DashboardUid) + require.Equal(t, "dashboard-with-alerts", alert.DashboardSlug) + }) - Convey("pausing alerts should update their NewStateDate", func() { - alert, _ = getAlertById(insertedAlert.Id) - stateDateAfterPause := alert.NewStateDate - So(stateDateBeforePause, ShouldHappenBefore, stateDateAfterPause) - }) + t.Run("Viewer can read alerts", func(t *testing.T) { + setup(t) + 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) - 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) - }) + require.Nil(t, err2) + require.Equal(t, 1, len(alertQuery.Result)) + }) + + t.Run("Alerts with same dashboard id and panel id should update", func(t *testing.T) { + setup(t) + modifiedItems := items + modifiedItems[0].Name = "Name" + + modifiedCmd := models.SaveAlertsCommand{ + DashboardId: testDash.Id, + OrgId: 1, + UserId: 1, + Alerts: modifiedItems, + } + + err := SaveAlerts(&modifiedCmd) + + t.Run("Can save alerts with same dashboard and panel id", func(t *testing.T) { + require.Nil(t, err) + }) + + t.Run("Alerts should be updated", func(t *testing.T) { + query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} + err2 := HandleAlertsQuery(&query) + + require.Nil(t, err2) + require.Equal(t, 1, len(query.Result)) + require.Equal(t, "Name", query.Result[0].Name) + + t.Run("Alert state should not be updated", func(t *testing.T) { + require.Equal(t, models.AlertStateUnknown, query.Result[0].State) }) }) - 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") + t.Run("Updates without changes should be ignored", func(t *testing.T) { + err3 := SaveAlerts(&modifiedCmd) + require.Nil(t, err3) }) + }) - 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{ + t.Run("Multiple alerts per dashboard", func(t *testing.T) { + setup(t) + multipleItems := []*models.Alert{ + { DashboardId: testDash.Id, + PanelId: 1, + Name: "1", OrgId: 1, - UserId: 1, - Alerts: modifiedItems, - } + 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(), + }, + } - err := SaveAlerts(&modifiedCmd) + cmd.Alerts = multipleItems + err := SaveAlerts(&cmd) - Convey("Can save alerts with same dashboard and panel id", func() { - So(err, ShouldBeNil) - }) + t.Run("Should save 3 dashboards", func(t *testing.T) { + require.Nil(t, err) - 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) + queryForDashboard := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} + err2 := HandleAlertsQuery(&queryForDashboard) - 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) - }) + require.Nil(t, err2) + require.Equal(t, 3, len(queryForDashboard.Result)) }) - 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(), - }, - } + t.Run("should updated two dashboards and delete one", func(t *testing.T) { + missingOneAlert := multipleItems[:2] - cmd.Alerts = multipleItems + cmd.Alerts = missingOneAlert 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(context.Background(), &models.DeleteDashboardCommand{ - OrgId: 1, - Id: testDash.Id, - }) - So(err, ShouldBeNil) - - Convey("Alerts should be removed", func() { + t.Run("should delete the missing alert", func(t *testing.T) { 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) + require.Nil(t, err2) + require.Equal(t, 2, len(query.Result)) }) }) }) + + t.Run("When dashboard is removed", func(t *testing.T) { + setup(t) + 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) + require.Nil(t, err) + + err = DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{ + OrgId: 1, + Id: testDash.Id, + }) + require.Nil(t, err) + + t.Run("Alerts should be removed", func(t *testing.T) { + query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} + err2 := HandleAlertsQuery(&query) + + require.Nil(t, err2) + require.Equal(t, 0, len(query.Result)) + }) + }) } func TestPausingAlerts(t *testing.T) { mockTimeNow() defer resetTimeNow() - Convey("Given an alert", t, func() { + t.Run("Given an alert", func(t *testing.T) { 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) + require.Nil(t, err) stateDateBeforePause := alert.NewStateDate stateDateAfterPause := stateDateBeforePause @@ -293,45 +302,45 @@ func TestPausingAlerts(t *testing.T) { // 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) + require.Nil(t, err2) insertedAlert := alertQuery.Result[0] - Convey("when paused", func() { - _, err := pauseAlert(testDash.OrgId, insertedAlert.Id, true) - So(err, ShouldBeNil) + t.Run("when paused", func(t *testing.T) { + _, err := pauseAlert(t, testDash.OrgId, insertedAlert.Id, true) + require.Nil(t, err) - Convey("the NewStateDate should be updated", func() { - alert, err := getAlertById(insertedAlert.Id) - So(err, ShouldBeNil) + t.Run("the NewStateDate should be updated", func(t *testing.T) { + alert, err := getAlertById(t, insertedAlert.Id) + require.Nil(t, err) stateDateAfterPause = alert.NewStateDate - So(stateDateBeforePause, ShouldHappenBefore, stateDateAfterPause) + require.True(t, stateDateBeforePause.Before(stateDateAfterPause)) }) }) - Convey("when unpaused", func() { - _, err := pauseAlert(testDash.OrgId, insertedAlert.Id, false) - So(err, ShouldBeNil) + t.Run("when unpaused", func(t *testing.T) { + _, err := pauseAlert(t, testDash.OrgId, insertedAlert.Id, false) + require.Nil(t, err) - Convey("the NewStateDate should be updated again", func() { - alert, err := getAlertById(insertedAlert.Id) - So(err, ShouldBeNil) + t.Run("the NewStateDate should be updated again", func(t *testing.T) { + alert, err := getAlertById(t, insertedAlert.Id) + require.Nil(t, err) stateDateAfterUnpause := alert.NewStateDate - So(stateDateAfterPause, ShouldHappenBefore, stateDateAfterUnpause) + require.True(t, stateDateAfterPause.Before(stateDateAfterUnpause)) }) }) }) } -func pauseAlert(orgId int64, alertId int64, pauseState bool) (int64, error) { +func pauseAlert(t *testing.T, orgId int64, alertId int64, pauseState bool) (int64, error) { cmd := &models.PauseAlertCommand{ OrgId: orgId, AlertIds: []int64{alertId}, Paused: pauseState, } err := PauseAlert(cmd) - So(err, ShouldBeNil) + require.Nil(t, err) return cmd.ResultCount, err } func insertTestAlert(title string, message string, orgId int64, dashId int64, settings *simplejson.Json) (*models.Alert, error) { @@ -358,20 +367,20 @@ func insertTestAlert(title string, message string, orgId int64, dashId int64, se return cmd.Alerts[0], err } -func getAlertById(id int64) (*models.Alert, error) { +func getAlertById(t *testing.T, id int64) (*models.Alert, error) { q := &models.GetAlertByIdQuery{ Id: id, } err := GetAlertById(q) - So(err, ShouldBeNil) + require.Nil(t, err) return q.Result, err } -func pauseAllAlerts(pauseState bool) error { +func pauseAllAlerts(t *testing.T, pauseState bool) error { cmd := &models.PauseAllAlertCommand{ Paused: pauseState, } err := PauseAllAlerts(cmd) - So(err, ShouldBeNil) + require.Nil(t, err) return err } diff --git a/pkg/services/sqlstore/dashboard_acl_test.go b/pkg/services/sqlstore/dashboard_acl_test.go index 24d6aea954d..2f346221b0e 100644 --- a/pkg/services/sqlstore/dashboard_acl_test.go +++ b/pkg/services/sqlstore/dashboard_acl_test.go @@ -8,236 +8,241 @@ import ( "testing" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func TestDashboardAclDataAccess(t *testing.T) { - Convey("Testing DB", t, func() { - sqlStore := InitTestDB(t) + var sqlStore *SQLStore + var currentUser models.User + var savedFolder, childDash *models.Dashboard - Convey("Given a dashboard folder and a user", func() { - currentUser := createUser(t, sqlStore, "viewer", "Viewer", false) - savedFolder := insertTestDashboard(t, sqlStore, "1 test dash folder", 1, 0, true, "prod", "webapp") - childDash := insertTestDashboard(t, sqlStore, "2 test dash", 1, savedFolder.Id, false, "prod", "webapp") + setup := func(t *testing.T) { + sqlStore = InitTestDB(t) + currentUser = createUser(t, sqlStore, "viewer", "Viewer", false) + savedFolder = insertTestDashboard(t, sqlStore, "1 test dash folder", 1, 0, true, "prod", "webapp") + childDash = insertTestDashboard(t, sqlStore, "2 test dash", 1, savedFolder.Id, false, "prod", "webapp") + } - Convey("When adding dashboard permission with userId and teamId set to 0", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ - OrgID: 1, - DashboardID: savedFolder.Id, - Permission: models.PERMISSION_EDIT, - }) - So(err, ShouldEqual, models.ErrDashboardAclInfoMissing) + t.Run("Dashboard permission with userId and teamId set to 0", func(t *testing.T) { + setup(t) + err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ + OrgID: 1, + DashboardID: savedFolder.Id, + Permission: models.PERMISSION_EDIT, + }) + require.Equal(t, models.ErrDashboardAclInfoMissing, err) + }) + + t.Run("Folder acl should include default acl", func(t *testing.T) { + setup(t) + query := models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} + + err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + require.Equal(t, 2, len(query.Result)) + defaultPermissionsId := int64(-1) + require.Equal(t, defaultPermissionsId, query.Result[0].DashboardId) + require.Equal(t, models.ROLE_VIEWER, *query.Result[0].Role) + require.False(t, query.Result[0].Inherited) + require.Equal(t, defaultPermissionsId, query.Result[1].DashboardId) + require.Equal(t, models.ROLE_EDITOR, *query.Result[1].Role) + require.False(t, query.Result[1].Inherited) + }) + + t.Run("Dashboard acl should include acl for parent folder", func(t *testing.T) { + setup(t) + query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} + + err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + require.Equal(t, 2, len(query.Result)) + defaultPermissionsId := int64(-1) + require.Equal(t, defaultPermissionsId, query.Result[0].DashboardId) + require.Equal(t, models.ROLE_VIEWER, *query.Result[0].Role) + require.True(t, query.Result[0].Inherited) + require.Equal(t, defaultPermissionsId, query.Result[1].DashboardId) + require.Equal(t, models.ROLE_EDITOR, *query.Result[1].Role) + require.True(t, query.Result[1].Inherited) + }) + + t.Run("Folder with removed default permissions returns no acl items", func(t *testing.T) { + setup(t) + err := sqlStore.UpdateDashboardACL(savedFolder.Id, nil) + require.Nil(t, err) + + query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} + err = sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + require.Equal(t, 0, len(query.Result)) + }) + + t.Run("Given a dashboard folder and a user", func(t *testing.T) { + + t.Run("Given dashboard folder permission", func(t *testing.T) { + setup(t) + err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ + OrgID: 1, + UserID: currentUser.Id, + DashboardID: savedFolder.Id, + Permission: models.PERMISSION_EDIT, + }) + require.Nil(t, err) + + t.Run("When reading dashboard acl should include acl for parent folder", func(t *testing.T) { + query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} + + err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + require.Equal(t, 1, len(query.Result)) + require.Equal(t, savedFolder.Id, query.Result[0].DashboardId) }) - Convey("Given dashboard folder with default permissions", func() { - Convey("When reading folder acl should include default acl", func() { - query := models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 2) - defaultPermissionsId := -1 - So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[0].Role, ShouldEqual, models.ROLE_VIEWER) - So(query.Result[0].Inherited, ShouldBeFalse) - So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[1].Role, ShouldEqual, models.ROLE_EDITOR) - So(query.Result[1].Inherited, ShouldBeFalse) - }) - - Convey("When reading dashboard acl should include acl for parent folder", func() { - query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 2) - defaultPermissionsId := -1 - So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[0].Role, ShouldEqual, models.ROLE_VIEWER) - So(query.Result[0].Inherited, ShouldBeTrue) - So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[1].Role, ShouldEqual, models.ROLE_EDITOR) - So(query.Result[1].Inherited, ShouldBeTrue) - }) - }) - - Convey("Given dashboard folder with removed default permissions", func() { - err := sqlStore.UpdateDashboardACL(savedFolder.Id, nil) - So(err, ShouldBeNil) - - Convey("When reading dashboard acl should return no acl items", func() { - query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 0) - }) - }) - - Convey("Given dashboard folder permission", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ - OrgID: 1, - UserID: currentUser.Id, - DashboardID: savedFolder.Id, - Permission: models.PERMISSION_EDIT, - }) - So(err, ShouldBeNil) - - Convey("When reading dashboard acl should include acl for parent folder", func() { - query := models.GetDashboardAclInfoListQuery{DashboardID: childDash.Id, OrgID: 1} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 1) - So(query.Result[0].DashboardId, ShouldEqual, savedFolder.Id) - }) - - Convey("Given child dashboard permission", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, childDash.Id, models.DashboardAcl{ - OrgID: 1, - UserID: currentUser.Id, - DashboardID: childDash.Id, - Permission: models.PERMISSION_EDIT, - }) - So(err, ShouldBeNil) - - Convey("When reading dashboard acl should include acl for parent folder and child", func() { - query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 2) - So(query.Result[0].DashboardId, ShouldEqual, savedFolder.Id) - So(query.Result[0].Inherited, ShouldBeTrue) - So(query.Result[1].DashboardId, ShouldEqual, childDash.Id) - So(query.Result[1].Inherited, ShouldBeFalse) - }) - }) - }) - - Convey("Given child dashboard permission in folder with no permissions", func() { + t.Run("Given child dashboard permission", func(t *testing.T) { err := testHelperUpdateDashboardAcl(t, sqlStore, childDash.Id, models.DashboardAcl{ OrgID: 1, UserID: currentUser.Id, DashboardID: childDash.Id, Permission: models.PERMISSION_EDIT, }) - So(err, ShouldBeNil) + require.Nil(t, err) - Convey("When reading dashboard acl should include default acl for parent folder and the child acl", func() { + t.Run("When reading dashboard acl should include acl for parent folder and child", func(t *testing.T) { query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id} err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) + require.Nil(t, err) - defaultPermissionsId := -1 - So(len(query.Result), ShouldEqual, 3) - So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[0].Role, ShouldEqual, models.ROLE_VIEWER) - So(query.Result[0].Inherited, ShouldBeTrue) - So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[1].Role, ShouldEqual, models.ROLE_EDITOR) - So(query.Result[1].Inherited, ShouldBeTrue) - So(query.Result[2].DashboardId, ShouldEqual, childDash.Id) - So(query.Result[2].Inherited, ShouldBeFalse) - }) - }) - - Convey("Should be able to add dashboard permission", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ - OrgID: 1, - UserID: currentUser.Id, - DashboardID: savedFolder.Id, - Permission: models.PERMISSION_EDIT, - }) - So(err, ShouldBeNil) - - q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} - err = sqlStore.GetDashboardAclInfoList(context.Background(), q1) - So(err, ShouldBeNil) - - So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) - So(q1.Result[0].Permission, ShouldEqual, models.PERMISSION_EDIT) - So(q1.Result[0].PermissionName, ShouldEqual, "Edit") - So(q1.Result[0].UserId, ShouldEqual, currentUser.Id) - So(q1.Result[0].UserLogin, ShouldEqual, currentUser.Login) - So(q1.Result[0].UserEmail, ShouldEqual, currentUser.Email) - - Convey("Should be able to delete an existing permission", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id) - So(err, ShouldBeNil) - - q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} - err = sqlStore.GetDashboardAclInfoList(context.Background(), q3) - So(err, ShouldBeNil) - So(len(q3.Result), ShouldEqual, 0) - }) - }) - - Convey("Given a team", func() { - team1, err := sqlStore.CreateTeam("group1 name", "", 1) - So(err, ShouldBeNil) - - Convey("Should be able to add a user permission for a team", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ - OrgID: 1, - TeamID: team1.Id, - DashboardID: savedFolder.Id, - Permission: models.PERMISSION_EDIT, - }) - So(err, ShouldBeNil) - - q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} - err = sqlStore.GetDashboardAclInfoList(context.Background(), q1) - So(err, ShouldBeNil) - So(q1.Result[0].DashboardId, ShouldEqual, savedFolder.Id) - So(q1.Result[0].Permission, ShouldEqual, models.PERMISSION_EDIT) - So(q1.Result[0].TeamId, ShouldEqual, team1.Id) - }) - - Convey("Should be able to update an existing permission for a team", func() { - err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ - OrgID: 1, - TeamID: team1.Id, - DashboardID: savedFolder.Id, - Permission: models.PERMISSION_ADMIN, - }) - So(err, ShouldBeNil) - - q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} - err = sqlStore.GetDashboardAclInfoList(context.Background(), q3) - So(err, ShouldBeNil) - So(len(q3.Result), ShouldEqual, 1) - So(q3.Result[0].DashboardId, ShouldEqual, savedFolder.Id) - So(q3.Result[0].Permission, ShouldEqual, models.PERMISSION_ADMIN) - So(q3.Result[0].TeamId, ShouldEqual, team1.Id) + require.Equal(t, 2, len(query.Result)) + require.Equal(t, savedFolder.Id, query.Result[0].DashboardId) + require.True(t, query.Result[0].Inherited) + require.Equal(t, childDash.Id, query.Result[1].DashboardId) + require.False(t, query.Result[1].Inherited) }) }) }) - Convey("Given a root folder", func() { - var rootFolderId int64 = 0 - - Convey("When reading dashboard acl should return default permissions", func() { - query := models.GetDashboardAclInfoListQuery{DashboardID: rootFolderId, OrgID: 1} - - err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) - So(err, ShouldBeNil) - - So(len(query.Result), ShouldEqual, 2) - defaultPermissionsId := -1 - So(query.Result[0].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[0].Role, ShouldEqual, models.ROLE_VIEWER) - So(query.Result[0].Inherited, ShouldBeFalse) - So(query.Result[1].DashboardId, ShouldEqual, defaultPermissionsId) - So(*query.Result[1].Role, ShouldEqual, models.ROLE_EDITOR) - So(query.Result[1].Inherited, ShouldBeFalse) + t.Run("Reading dashboard acl should include default acl for parent folder and the child acl", func(t *testing.T) { + setup(t) + err := testHelperUpdateDashboardAcl(t, sqlStore, childDash.Id, models.DashboardAcl{ + OrgID: 1, + UserID: currentUser.Id, + DashboardID: childDash.Id, + Permission: models.PERMISSION_EDIT, }) + require.Nil(t, err) + + query := models.GetDashboardAclInfoListQuery{OrgID: 1, DashboardID: childDash.Id} + + err = sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + defaultPermissionsId := int64(-1) + require.Equal(t, 3, len(query.Result)) + require.Equal(t, defaultPermissionsId, query.Result[0].DashboardId) + require.Equal(t, models.ROLE_VIEWER, *query.Result[0].Role) + require.True(t, query.Result[0].Inherited) + require.Equal(t, defaultPermissionsId, query.Result[1].DashboardId) + require.Equal(t, models.ROLE_EDITOR, *query.Result[1].Role) + require.True(t, query.Result[1].Inherited) + require.Equal(t, childDash.Id, query.Result[2].DashboardId) + require.False(t, query.Result[2].Inherited) + }) + + t.Run("Add and delete dashboard permission", func(t *testing.T) { + setup(t) + err := testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ + OrgID: 1, + UserID: currentUser.Id, + DashboardID: savedFolder.Id, + Permission: models.PERMISSION_EDIT, + }) + require.Nil(t, err) + + q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} + err = sqlStore.GetDashboardAclInfoList(context.Background(), q1) + require.Nil(t, err) + + require.Equal(t, savedFolder.Id, q1.Result[0].DashboardId) + require.Equal(t, models.PERMISSION_EDIT, q1.Result[0].Permission) + require.Equal(t, "Edit", q1.Result[0].PermissionName) + require.Equal(t, currentUser.Id, q1.Result[0].UserId) + require.Equal(t, currentUser.Login, q1.Result[0].UserLogin) + require.Equal(t, currentUser.Email, q1.Result[0].UserEmail) + + err = testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id) + require.Nil(t, err) + + q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} + err = sqlStore.GetDashboardAclInfoList(context.Background(), q3) + require.Nil(t, err) + require.Equal(t, 0, len(q3.Result)) + }) + + t.Run("Should be able to add a user permission for a team", func(t *testing.T) { + setup(t) + team1, err := sqlStore.CreateTeam("group1 name", "", 1) + require.Nil(t, err) + + err = testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ + OrgID: 1, + TeamID: team1.Id, + DashboardID: savedFolder.Id, + Permission: models.PERMISSION_EDIT, + }) + require.Nil(t, err) + + q1 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} + err = sqlStore.GetDashboardAclInfoList(context.Background(), q1) + require.Nil(t, err) + require.Equal(t, savedFolder.Id, q1.Result[0].DashboardId) + require.Equal(t, models.PERMISSION_EDIT, q1.Result[0].Permission) + require.Equal(t, team1.Id, q1.Result[0].TeamId) + }) + + t.Run("Should be able to update an existing permission for a team", func(t *testing.T) { + setup(t) + team1, err := sqlStore.CreateTeam("group1 name", "", 1) + require.Nil(t, err) + err = testHelperUpdateDashboardAcl(t, sqlStore, savedFolder.Id, models.DashboardAcl{ + OrgID: 1, + TeamID: team1.Id, + DashboardID: savedFolder.Id, + Permission: models.PERMISSION_ADMIN, + }) + require.Nil(t, err) + + q3 := &models.GetDashboardAclInfoListQuery{DashboardID: savedFolder.Id, OrgID: 1} + err = sqlStore.GetDashboardAclInfoList(context.Background(), q3) + require.Nil(t, err) + require.Equal(t, 1, len(q3.Result)) + require.Equal(t, savedFolder.Id, q3.Result[0].DashboardId) + require.Equal(t, models.PERMISSION_ADMIN, q3.Result[0].Permission) + require.Equal(t, team1.Id, q3.Result[0].TeamId) }) }) + + t.Run("Default permissions for root folder dashboards", func(t *testing.T) { + setup(t) + var rootFolderId int64 = 0 + sqlStore := InitTestDB(t) + + query := models.GetDashboardAclInfoListQuery{DashboardID: rootFolderId, OrgID: 1} + + err := sqlStore.GetDashboardAclInfoList(context.Background(), &query) + require.Nil(t, err) + + require.Equal(t, 2, len(query.Result)) + defaultPermissionsId := int64(-1) + require.Equal(t, defaultPermissionsId, query.Result[0].DashboardId) + require.Equal(t, models.ROLE_VIEWER, *query.Result[0].Role) + require.False(t, query.Result[0].Inherited) + require.Equal(t, defaultPermissionsId, query.Result[1].DashboardId) + require.Equal(t, models.ROLE_EDITOR, *query.Result[1].Role) + require.False(t, query.Result[1].Inherited) + }) } diff --git a/pkg/services/sqlstore/dashboard_provisioning_test.go b/pkg/services/sqlstore/dashboard_provisioning_test.go index 40731d4dc56..b58b62e573b 100644 --- a/pkg/services/sqlstore/dashboard_provisioning_test.go +++ b/pkg/services/sqlstore/dashboard_provisioning_test.go @@ -10,132 +10,130 @@ import ( "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func TestDashboardProvisioningTest(t *testing.T) { - Convey("Testing Dashboard provisioning", t, func() { - sqlStore := InitTestDB(t) + sqlStore := InitTestDB(t) - folderCmd := models.SaveDashboardCommand{ - OrgId: 1, - FolderId: 0, - IsFolder: true, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": "test dashboard", - }), + folderCmd := models.SaveDashboardCommand{ + OrgId: 1, + FolderId: 0, + IsFolder: true, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": "test dashboard", + }), + } + + dash, err := sqlStore.SaveDashboard(folderCmd) + require.Nil(t, err) + + saveDashboardCmd := models.SaveDashboardCommand{ + OrgId: 1, + IsFolder: false, + FolderId: dash.Id, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": "test dashboard", + }), + } + + t.Run("Saving dashboards with provisioning meta data", func(t *testing.T) { + now := time.Now() + + provisioning := &models.DashboardProvisioning{ + Name: "default", + ExternalId: "/var/grafana.json", + Updated: now.Unix(), } - dash, err := sqlStore.SaveDashboard(folderCmd) - So(err, ShouldBeNil) - - saveDashboardCmd := models.SaveDashboardCommand{ - OrgId: 1, - IsFolder: false, - FolderId: dash.Id, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": "test dashboard", - }), - } - - Convey("Saving dashboards with provisioning meta data", func() { - now := time.Now() + dash, err := sqlStore.SaveProvisionedDashboard(saveDashboardCmd, provisioning) + require.Nil(t, err) + require.NotNil(t, dash) + require.NotEqual(t, 0, dash.Id) + dashId := dash.Id + t.Run("Deleting orphaned provisioned dashboards", func(t *testing.T) { + saveCmd := models.SaveDashboardCommand{ + OrgId: 1, + IsFolder: false, + FolderId: dash.Id, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": "another_dashboard", + }), + } provisioning := &models.DashboardProvisioning{ - Name: "default", + Name: "another_reader", ExternalId: "/var/grafana.json", Updated: now.Unix(), } - dash, err := sqlStore.SaveProvisionedDashboard(saveDashboardCmd, provisioning) - So(err, ShouldBeNil) - So(dash, ShouldNotBeNil) - So(dash.Id, ShouldNotEqual, 0) - dashId := dash.Id + anotherDash, err := sqlStore.SaveProvisionedDashboard(saveCmd, provisioning) + require.Nil(t, err) - Convey("Deleting orphaned provisioned dashboards", func() { - saveCmd := models.SaveDashboardCommand{ - OrgId: 1, - IsFolder: false, - FolderId: dash.Id, - Dashboard: simplejson.NewFromAny(map[string]interface{}{ - "id": nil, - "title": "another_dashboard", - }), - } - provisioning := &models.DashboardProvisioning{ - Name: "another_reader", - ExternalId: "/var/grafana.json", - Updated: now.Unix(), - } + query := &models.GetDashboardsQuery{DashboardIds: []int64{anotherDash.Id}} + err = GetDashboards(context.Background(), query) + require.Nil(t, err) + require.NotNil(t, query.Result) - anotherDash, err := sqlStore.SaveProvisionedDashboard(saveCmd, provisioning) - So(err, ShouldBeNil) + deleteCmd := &models.DeleteOrphanedProvisionedDashboardsCommand{ReaderNames: []string{"default"}} + require.Nil(t, DeleteOrphanedProvisionedDashboards(context.Background(), deleteCmd)) - query := &models.GetDashboardsQuery{DashboardIds: []int64{anotherDash.Id}} - err = GetDashboards(context.Background(), query) - So(err, ShouldBeNil) - So(query.Result, ShouldNotBeNil) + query = &models.GetDashboardsQuery{DashboardIds: []int64{dash.Id, anotherDash.Id}} + err = GetDashboards(context.Background(), query) + require.Nil(t, err) - deleteCmd := &models.DeleteOrphanedProvisionedDashboardsCommand{ReaderNames: []string{"default"}} - So(DeleteOrphanedProvisionedDashboards(context.Background(), deleteCmd), ShouldBeNil) + require.Equal(t, 1, len(query.Result)) + require.Equal(t, dashId, query.Result[0].Id) + }) - query = &models.GetDashboardsQuery{DashboardIds: []int64{dash.Id, anotherDash.Id}} - err = GetDashboards(context.Background(), query) - So(err, ShouldBeNil) + t.Run("Can query for provisioned dashboards", func(t *testing.T) { + rslt, err := sqlStore.GetProvisionedDashboardData("default") + require.Nil(t, err) - So(len(query.Result), ShouldEqual, 1) - So(query.Result[0].Id, ShouldEqual, dashId) - }) + require.Equal(t, 1, len(rslt)) + require.Equal(t, dashId, rslt[0].DashboardId) + require.Equal(t, now.Unix(), rslt[0].Updated) + }) - Convey("Can query for provisioned dashboards", func() { - rslt, err := sqlStore.GetProvisionedDashboardData("default") - So(err, ShouldBeNil) + t.Run("Can query for one provisioned dashboard", func(t *testing.T) { + data, err := sqlStore.GetProvisionedDataByDashboardID(dash.Id) + require.Nil(t, err) + require.NotNil(t, data) + }) - So(len(rslt), ShouldEqual, 1) - So(rslt[0].DashboardId, ShouldEqual, dashId) - So(rslt[0].Updated, ShouldEqual, now.Unix()) - }) + t.Run("Can query for none provisioned dashboard", func(t *testing.T) { + data, err := sqlStore.GetProvisionedDataByDashboardID(3000) + require.Nil(t, err) + require.Nil(t, data) + }) - Convey("Can query for one provisioned dashboard", func() { - data, err := sqlStore.GetProvisionedDataByDashboardID(dash.Id) - So(err, ShouldBeNil) + t.Run("Deleting folder should delete provision meta data", func(t *testing.T) { + deleteCmd := &models.DeleteDashboardCommand{ + Id: dash.Id, + OrgId: 1, + } - So(data, ShouldNotBeNil) - }) + require.Nil(t, DeleteDashboard(context.Background(), deleteCmd)) - Convey("Can query for none provisioned dashboard", func() { - data, err := sqlStore.GetProvisionedDataByDashboardID(3000) - So(err, ShouldBeNil) - So(data, ShouldBeNil) - }) + data, err := sqlStore.GetProvisionedDataByDashboardID(dash.Id) + require.Nil(t, err) + require.Nil(t, data) + }) - Convey("Deleting folder should delete provision meta data", func() { - deleteCmd := &models.DeleteDashboardCommand{ - Id: dash.Id, - OrgId: 1, - } + t.Run("UnprovisionDashboard should delete provisioning metadata", func(t *testing.T) { + unprovisionCmd := &models.UnprovisionDashboardCommand{ + Id: dashId, + } - So(DeleteDashboard(context.Background(), deleteCmd), ShouldBeNil) + require.Nil(t, UnprovisionDashboard(context.Background(), unprovisionCmd)) - data, err := sqlStore.GetProvisionedDataByDashboardID(dash.Id) - So(err, ShouldBeNil) - So(data, ShouldBeNil) - }) - - Convey("UnprovisionDashboard should delete provisioning metadata", func() { - unprovisionCmd := &models.UnprovisionDashboardCommand{ - Id: dashId, - } - - So(UnprovisionDashboard(context.Background(), unprovisionCmd), ShouldBeNil) - - data, err := sqlStore.GetProvisionedDataByDashboardID(dashId) - So(err, ShouldBeNil) - So(data, ShouldBeNil) - }) + data, err := sqlStore.GetProvisionedDataByDashboardID(dashId) + require.Nil(t, err) + require.Nil(t, data) }) }) } diff --git a/pkg/services/sqlstore/dashboard_version_test.go b/pkg/services/sqlstore/dashboard_version_test.go index d44618fd735..949dc26414c 100644 --- a/pkg/services/sqlstore/dashboard_version_test.go +++ b/pkg/services/sqlstore/dashboard_version_test.go @@ -8,11 +8,10 @@ import ( "reflect" "testing" - . "github.com/smartystreets/goconvey/convey" - "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" + "github.com/stretchr/testify/require" ) func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) { @@ -26,151 +25,152 @@ func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Das Dashboard: simplejson.NewFromAny(data), } _, err := sqlStore.SaveDashboard(saveCmd) - So(err, ShouldBeNil) + require.Nil(t, err) } func TestGetDashboardVersion(t *testing.T) { - Convey("Testing dashboard version retrieval", t, func() { - sqlStore := InitTestDB(t) + sqlStore := InitTestDB(t) - Convey("Get a Dashboard ID and version ID", func() { - savedDash := insertTestDashboard(t, sqlStore, "test dash 26", 1, 0, false, "diff") + t.Run("Get a Dashboard ID and version ID", func(t *testing.T) { + savedDash := insertTestDashboard(t, sqlStore, "test dash 26", 1, 0, false, "diff") - query := models.GetDashboardVersionQuery{ - DashboardId: savedDash.Id, - Version: savedDash.Version, - OrgId: 1, - } + query := models.GetDashboardVersionQuery{ + DashboardId: savedDash.Id, + Version: savedDash.Version, + OrgId: 1, + } - err := GetDashboardVersion(&query) - So(err, ShouldBeNil) - So(savedDash.Id, ShouldEqual, query.DashboardId) - So(savedDash.Version, ShouldEqual, query.Version) + err := GetDashboardVersion(&query) + require.Nil(t, err) + require.Equal(t, query.DashboardId, savedDash.Id) + require.Equal(t, query.Version, savedDash.Version) - dashCmd := models.GetDashboardQuery{ - OrgId: savedDash.OrgId, - Uid: savedDash.Uid, - } + dashCmd := models.GetDashboardQuery{ + OrgId: savedDash.OrgId, + Uid: savedDash.Uid, + } - err = GetDashboard(context.Background(), &dashCmd) - So(err, ShouldBeNil) - eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data) - So(eq, ShouldEqual, true) - }) + err = GetDashboard(context.Background(), &dashCmd) + require.Nil(t, err) + eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data) + require.Equal(t, true, eq) + }) - Convey("Attempt to get a version that doesn't exist", func() { - query := models.GetDashboardVersionQuery{ - DashboardId: int64(999), - Version: 123, - OrgId: 1, - } + t.Run("Attempt to get a version that doesn't exist", func(t *testing.T) { + query := models.GetDashboardVersionQuery{ + DashboardId: int64(999), + Version: 123, + OrgId: 1, + } - err := GetDashboardVersion(&query) - So(err, ShouldNotBeNil) - So(err, ShouldEqual, models.ErrDashboardVersionNotFound) - }) + err := GetDashboardVersion(&query) + require.Error(t, err) + require.Equal(t, models.ErrDashboardVersionNotFound, err) }) } func TestGetDashboardVersions(t *testing.T) { - Convey("Testing dashboard versions retrieval", t, func() { - sqlStore := InitTestDB(t) - savedDash := insertTestDashboard(t, sqlStore, "test dash 43", 1, 0, false, "diff-all") + sqlStore := InitTestDB(t) + savedDash := insertTestDashboard(t, sqlStore, "test dash 43", 1, 0, false, "diff-all") - Convey("Get all versions for a given Dashboard ID", func() { - query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} + t.Run("Get all versions for a given Dashboard ID", func(t *testing.T) { + query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} - err := GetDashboardVersions(&query) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 1) + err := GetDashboardVersions(&query) + require.Nil(t, err) + require.Equal(t, 1, len(query.Result)) + }) + + t.Run("Attempt to get the versions for a non-existent Dashboard ID", func(t *testing.T) { + query := models.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1} + + err := GetDashboardVersions(&query) + require.Error(t, err) + require.Equal(t, models.ErrNoVersionsForDashboardId, err) + require.Equal(t, 0, len(query.Result)) + }) + + t.Run("Get all versions for an updated dashboard", func(t *testing.T) { + updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{ + "tags": "different-tag", }) - Convey("Attempt to get the versions for a non-existent Dashboard ID", func() { - query := models.GetDashboardVersionsQuery{DashboardId: int64(999), OrgId: 1} + query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} + err := GetDashboardVersions(&query) - err := GetDashboardVersions(&query) - So(err, ShouldNotBeNil) - So(err, ShouldEqual, models.ErrNoVersionsForDashboardId) - So(len(query.Result), ShouldEqual, 0) - }) - - Convey("Get all versions for an updated dashboard", func() { - updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{ - "tags": "different-tag", - }) - - query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} - err := GetDashboardVersions(&query) - - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 2) - }) + require.Nil(t, err) + require.Equal(t, 2, len(query.Result)) }) } func TestDeleteExpiredVersions(t *testing.T) { - Convey("Testing dashboard versions clean up", t, func() { - sqlStore := InitTestDB(t) - versionsToKeep := 5 - versionsToWrite := 10 - setting.DashboardVersionsToKeep = versionsToKeep + versionsToKeep := 5 + versionsToWrite := 10 + setting.DashboardVersionsToKeep = versionsToKeep - savedDash := insertTestDashboard(t, sqlStore, "test dash 53", 1, 0, false, "diff-all") + var sqlStore *SQLStore + var savedDash *models.Dashboard + setup := func(t *testing.T) { + sqlStore = InitTestDB(t) + savedDash = insertTestDashboard(t, sqlStore, "test dash 53", 1, 0, false, "diff-all") for i := 0; i < versionsToWrite-1; i++ { updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{ "tags": "different-tag", }) } + } - Convey("Clean up old dashboard versions", func() { - err := DeleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}) - So(err, ShouldBeNil) + t.Run("Clean up old dashboard versions", func(t *testing.T) { + setup(t) + err := DeleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}) + require.Nil(t, err) - query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} - err = GetDashboardVersions(&query) - So(err, ShouldBeNil) + query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1} + err = GetDashboardVersions(&query) + require.Nil(t, err) - So(len(query.Result), ShouldEqual, versionsToKeep) - // Ensure latest versions were kept - So(query.Result[versionsToKeep-1].Version, ShouldEqual, versionsToWrite-versionsToKeep+1) - So(query.Result[0].Version, ShouldEqual, versionsToWrite) - }) + require.Equal(t, versionsToKeep, len(query.Result)) + // Ensure latest versions were kept + require.Equal(t, versionsToWrite-versionsToKeep+1, query.Result[versionsToKeep-1].Version) + require.Equal(t, versionsToWrite, query.Result[0].Version) + }) - Convey("Don't delete anything if there are no expired versions", func() { - setting.DashboardVersionsToKeep = versionsToWrite + t.Run("Don't delete anything if there are no expired versions", func(t *testing.T) { + setup(t) + setting.DashboardVersionsToKeep = versionsToWrite - err := DeleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}) - So(err, ShouldBeNil) + err := DeleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}) + require.Nil(t, err) - query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1, Limit: versionsToWrite} - err = GetDashboardVersions(&query) - So(err, ShouldBeNil) + query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1, Limit: versionsToWrite} + err = GetDashboardVersions(&query) + require.Nil(t, err) - So(len(query.Result), ShouldEqual, versionsToWrite) - }) + require.Equal(t, versionsToWrite, len(query.Result)) + }) - Convey("Don't delete more than MAX_VERSIONS_TO_DELETE_PER_BATCH * MAX_VERSION_DELETION_BATCHES per iteration", func() { - perBatch := 10 - maxBatches := 10 + t.Run("Don't delete more than MAX_VERSIONS_TO_DELETE_PER_BATCH * MAX_VERSION_DELETION_BATCHES per iteration", func(t *testing.T) { + setup(t) + perBatch := 10 + maxBatches := 10 - versionsToWriteBigNumber := perBatch*maxBatches + versionsToWrite - for i := 0; i < versionsToWriteBigNumber-versionsToWrite; i++ { - updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{ - "tags": "different-tag", - }) - } + versionsToWriteBigNumber := perBatch*maxBatches + versionsToWrite + for i := 0; i < versionsToWriteBigNumber-versionsToWrite; i++ { + updateTestDashboard(t, sqlStore, savedDash, map[string]interface{}{ + "tags": "different-tag", + }) + } - err := deleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}, perBatch, maxBatches) - So(err, ShouldBeNil) + err := deleteExpiredVersions(&models.DeleteExpiredVersionsCommand{}, perBatch, maxBatches) + require.Nil(t, err) - query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1, Limit: versionsToWriteBigNumber} - err = GetDashboardVersions(&query) - So(err, ShouldBeNil) + query := models.GetDashboardVersionsQuery{DashboardId: savedDash.Id, OrgId: 1, Limit: versionsToWriteBigNumber} + err = GetDashboardVersions(&query) + require.Nil(t, err) - // Ensure we have at least versionsToKeep versions - So(len(query.Result), ShouldBeGreaterThanOrEqualTo, versionsToKeep) - // Ensure we haven't deleted more than perBatch * maxBatches rows - So(versionsToWriteBigNumber-len(query.Result), ShouldBeLessThanOrEqualTo, perBatch*maxBatches) - }) + // Ensure we have at least versionsToKeep versions + require.GreaterOrEqual(t, len(query.Result), versionsToKeep) + // Ensure we haven't deleted more than perBatch * maxBatches rows + require.LessOrEqual(t, versionsToWriteBigNumber-len(query.Result), perBatch*maxBatches) }) } diff --git a/pkg/services/sqlstore/login_attempt_test.go b/pkg/services/sqlstore/login_attempt_test.go index 90db30672ed..42ec4b40caa 100644 --- a/pkg/services/sqlstore/login_attempt_test.go +++ b/pkg/services/sqlstore/login_attempt_test.go @@ -8,7 +8,8 @@ import ( "time" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func mockTime(mock time.Time) time.Time { @@ -17,112 +18,116 @@ func mockTime(mock time.Time) time.Time { } func TestLoginAttempts(t *testing.T) { - Convey("Testing Login Attempts DB Access", t, func() { + var beginningOfTime, timePlusOneMinute, timePlusTwoMinutes time.Time + user := "user" + + setup := func(t *testing.T) { InitTestDB(t) - - user := "user" - beginningOfTime := mockTime(time.Date(2017, 10, 22, 8, 0, 0, 0, time.Local)) - + beginningOfTime = mockTime(time.Date(2017, 10, 22, 8, 0, 0, 0, time.Local)) err := CreateLoginAttempt(&models.CreateLoginAttemptCommand{ Username: user, IpAddress: "192.168.0.1", }) - So(err, ShouldBeNil) - - timePlusOneMinute := mockTime(beginningOfTime.Add(time.Minute * 1)) - + require.Nil(t, err) + timePlusOneMinute = mockTime(beginningOfTime.Add(time.Minute * 1)) err = CreateLoginAttempt(&models.CreateLoginAttemptCommand{ Username: user, IpAddress: "192.168.0.1", }) - So(err, ShouldBeNil) - - timePlusTwoMinutes := mockTime(beginningOfTime.Add(time.Minute * 2)) - + require.Nil(t, err) + timePlusTwoMinutes = mockTime(beginningOfTime.Add(time.Minute * 2)) err = CreateLoginAttempt(&models.CreateLoginAttemptCommand{ Username: user, IpAddress: "192.168.0.1", }) - So(err, ShouldBeNil) + require.Nil(t, err) + } - Convey("Should return a total count of zero login attempts when comparing since beginning of time + 2min and 1s", func() { - query := models.GetUserLoginAttemptCountQuery{ - Username: user, - Since: timePlusTwoMinutes.Add(time.Second * 1), - } - err := GetUserLoginAttemptCount(&query) - So(err, ShouldBeNil) - So(query.Result, ShouldEqual, 0) - }) + t.Run("Should return a total count of zero login attempts when comparing since beginning of time + 2min and 1s", func(t *testing.T) { + setup(t) + query := models.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusTwoMinutes.Add(time.Second * 1), + } + err := GetUserLoginAttemptCount(&query) + require.Nil(t, err) + require.Equal(t, int64(0), query.Result) + }) - Convey("Should return the total count of login attempts since beginning of time", func() { - query := models.GetUserLoginAttemptCountQuery{ - Username: user, - Since: beginningOfTime, - } - err := GetUserLoginAttemptCount(&query) - So(err, ShouldBeNil) - So(query.Result, ShouldEqual, 3) - }) + t.Run("Should return the total count of login attempts since beginning of time", func(t *testing.T) { + setup(t) + query := models.GetUserLoginAttemptCountQuery{ + Username: user, + Since: beginningOfTime, + } + err := GetUserLoginAttemptCount(&query) + require.Nil(t, err) + require.Equal(t, int64(3), query.Result) + }) - Convey("Should return the total count of login attempts since beginning of time + 1min", func() { - query := models.GetUserLoginAttemptCountQuery{ - Username: user, - Since: timePlusOneMinute, - } - err := GetUserLoginAttemptCount(&query) - So(err, ShouldBeNil) - So(query.Result, ShouldEqual, 2) - }) + t.Run("Should return the total count of login attempts since beginning of time + 1min", func(t *testing.T) { + setup(t) + query := models.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusOneMinute, + } + err := GetUserLoginAttemptCount(&query) + require.Nil(t, err) + require.Equal(t, int64(2), query.Result) + }) - Convey("Should return the total count of login attempts since beginning of time + 2min", func() { - query := models.GetUserLoginAttemptCountQuery{ - Username: user, - Since: timePlusTwoMinutes, - } - err := GetUserLoginAttemptCount(&query) - So(err, ShouldBeNil) - So(query.Result, ShouldEqual, 1) - }) + t.Run("Should return the total count of login attempts since beginning of time + 2min", func(t *testing.T) { + setup(t) + query := models.GetUserLoginAttemptCountQuery{ + Username: user, + Since: timePlusTwoMinutes, + } + err := GetUserLoginAttemptCount(&query) + require.Nil(t, err) + require.Equal(t, int64(1), query.Result) + }) - Convey("Should return deleted rows older than beginning of time", func() { - cmd := models.DeleteOldLoginAttemptsCommand{ - OlderThan: beginningOfTime, - } - err := DeleteOldLoginAttempts(&cmd) + t.Run("Should return deleted rows older than beginning of time", func(t *testing.T) { + setup(t) + cmd := models.DeleteOldLoginAttemptsCommand{ + OlderThan: beginningOfTime, + } + err := DeleteOldLoginAttempts(&cmd) - So(err, ShouldBeNil) - So(cmd.DeletedRows, ShouldEqual, 0) - }) + require.Nil(t, err) + require.Equal(t, int64(0), cmd.DeletedRows) + }) - Convey("Should return deleted rows older than beginning of time + 1min", func() { - cmd := models.DeleteOldLoginAttemptsCommand{ - OlderThan: timePlusOneMinute, - } - err := DeleteOldLoginAttempts(&cmd) + t.Run("Should return deleted rows older than beginning of time + 1min", func(t *testing.T) { + setup(t) + cmd := models.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusOneMinute, + } + err := DeleteOldLoginAttempts(&cmd) - So(err, ShouldBeNil) - So(cmd.DeletedRows, ShouldEqual, 1) - }) + require.Nil(t, err) + require.Equal(t, int64(1), cmd.DeletedRows) + }) - Convey("Should return deleted rows older than beginning of time + 2min", func() { - cmd := models.DeleteOldLoginAttemptsCommand{ - OlderThan: timePlusTwoMinutes, - } - err := DeleteOldLoginAttempts(&cmd) + t.Run("Should return deleted rows older than beginning of time + 2min", func(t *testing.T) { + setup(t) + cmd := models.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusTwoMinutes, + } + err := DeleteOldLoginAttempts(&cmd) - So(err, ShouldBeNil) - So(cmd.DeletedRows, ShouldEqual, 2) - }) + require.Nil(t, err) + require.Equal(t, int64(2), cmd.DeletedRows) + }) - Convey("Should return deleted rows older than beginning of time + 2min and 1s", func() { - cmd := models.DeleteOldLoginAttemptsCommand{ - OlderThan: timePlusTwoMinutes.Add(time.Second * 1), - } - err := DeleteOldLoginAttempts(&cmd) + t.Run("Should return deleted rows older than beginning of time + 2min and 1s", func(t *testing.T) { + setup(t) + cmd := models.DeleteOldLoginAttemptsCommand{ + OlderThan: timePlusTwoMinutes.Add(time.Second * 1), + } + err := DeleteOldLoginAttempts(&cmd) - So(err, ShouldBeNil) - So(cmd.DeletedRows, ShouldEqual, 3) - }) + require.Nil(t, err) + require.Equal(t, int64(3), cmd.DeletedRows) }) } diff --git a/pkg/services/sqlstore/org_test.go b/pkg/services/sqlstore/org_test.go index c3ae7ed5212..83b7d1545ce 100644 --- a/pkg/services/sqlstore/org_test.go +++ b/pkg/services/sqlstore/org_test.go @@ -320,7 +320,6 @@ func TestAccountDataAccess(t *testing.T) { query := models.GetOrgUsersQuery{OrgId: ac1.OrgId} err = sqlStore.GetOrgUsers(context.Background(), &query) require.NoError(t, err) - fmt.Println(query.Result) // require.Equal(t, len(query.Result), 3) dash1 := insertTestDashboard(t, sqlStore, "1 test dash", ac1.OrgId, 0, false, "prod", "webapp") diff --git a/pkg/services/sqlstore/tags_test.go b/pkg/services/sqlstore/tags_test.go index aa11b9c8d4d..f1b986ded62 100644 --- a/pkg/services/sqlstore/tags_test.go +++ b/pkg/services/sqlstore/tags_test.go @@ -8,22 +8,21 @@ import ( "testing" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func TestSavingTags(t *testing.T) { - Convey("Testing tags saving", t, func() { - InitTestDB(t) + InitTestDB(t) - tagPairs := []*models.Tag{ - {Key: "outage"}, - {Key: "type", Value: "outage"}, - {Key: "server", Value: "server-1"}, - {Key: "error"}, - } - tags, err := EnsureTagsExist(newSession(context.Background()), tagPairs) + tagPairs := []*models.Tag{ + {Key: "outage"}, + {Key: "type", Value: "outage"}, + {Key: "server", Value: "server-1"}, + {Key: "error"}, + } + tags, err := EnsureTagsExist(newSession(context.Background()), tagPairs) - So(err, ShouldBeNil) - So(len(tags), ShouldEqual, 4) - }) + require.Nil(t, err) + require.Equal(t, 4, len(tags)) } diff --git a/pkg/services/sqlstore/temp_user_test.go b/pkg/services/sqlstore/temp_user_test.go index 2c2b6b542fa..40b11524991 100644 --- a/pkg/services/sqlstore/temp_user_test.go +++ b/pkg/services/sqlstore/temp_user_test.go @@ -8,82 +8,86 @@ import ( "time" "github.com/grafana/grafana/pkg/models" - . "github.com/smartystreets/goconvey/convey" + + "github.com/stretchr/testify/require" ) func TestTempUserCommandsAndQueries(t *testing.T) { - Convey("Testing Temp User commands & queries", t, func() { + cmd := models.CreateTempUserCommand{ + OrgId: 2256, + Name: "hello", + Code: "asd", + Email: "e@as.co", + Status: models.TmpUserInvitePending, + } + setup := func(t *testing.T) { InitTestDB(t) + err := CreateTempUser(&cmd) + require.Nil(t, err) + } - Convey("Given saved api key", func() { - cmd := models.CreateTempUserCommand{ - OrgId: 2256, - Name: "hello", - Code: "asd", - Email: "e@as.co", - Status: models.TmpUserInvitePending, - } - err := CreateTempUser(&cmd) - So(err, ShouldBeNil) + t.Run("Should be able to get temp users by org id", func(t *testing.T) { + setup(t) + query := models.GetTempUsersQuery{OrgId: 2256, Status: models.TmpUserInvitePending} + err := GetTempUsersQuery(&query) - Convey("Should be able to get temp users by org id", func() { - query := models.GetTempUsersQuery{OrgId: 2256, Status: models.TmpUserInvitePending} - err = GetTempUsersQuery(&query) + require.Nil(t, err) + require.Equal(t, 1, len(query.Result)) + }) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 1) - }) + t.Run("Should be able to get temp users by email", func(t *testing.T) { + setup(t) + query := models.GetTempUsersQuery{Email: "e@as.co", Status: models.TmpUserInvitePending} + err := GetTempUsersQuery(&query) - Convey("Should be able to get temp users by email", func() { - query := models.GetTempUsersQuery{Email: "e@as.co", Status: models.TmpUserInvitePending} - err = GetTempUsersQuery(&query) + require.Nil(t, err) + require.Equal(t, 1, len(query.Result)) + }) - So(err, ShouldBeNil) - So(len(query.Result), ShouldEqual, 1) - }) + t.Run("Should be able to get temp users by code", func(t *testing.T) { + setup(t) + query := models.GetTempUserByCodeQuery{Code: "asd"} + err := GetTempUserByCode(&query) - Convey("Should be able to get temp users by code", func() { - query := models.GetTempUserByCodeQuery{Code: "asd"} - err = GetTempUserByCode(&query) + require.Nil(t, err) + require.Equal(t, "hello", query.Result.Name) + }) - So(err, ShouldBeNil) - So(query.Result.Name, ShouldEqual, "hello") - }) + t.Run("Should be able update status", func(t *testing.T) { + setup(t) + cmd2 := models.UpdateTempUserStatusCommand{Code: "asd", Status: models.TmpUserRevoked} + err := UpdateTempUserStatus(&cmd2) + require.Nil(t, err) + }) - Convey("Should be able update status", func() { - cmd2 := models.UpdateTempUserStatusCommand{Code: "asd", Status: models.TmpUserRevoked} - err := UpdateTempUserStatus(&cmd2) - So(err, ShouldBeNil) - }) + t.Run("Should be able update email sent and email sent on", func(t *testing.T) { + setup(t) + cmd2 := models.UpdateTempUserWithEmailSentCommand{Code: cmd.Result.Code} + err := UpdateTempUserWithEmailSent(&cmd2) + require.Nil(t, err) - Convey("Should be able update email sent and email sent on", func() { - cmd2 := models.UpdateTempUserWithEmailSentCommand{Code: cmd.Result.Code} - err := UpdateTempUserWithEmailSent(&cmd2) - So(err, ShouldBeNil) + query := models.GetTempUsersQuery{OrgId: 2256, Status: models.TmpUserInvitePending} + err = GetTempUsersQuery(&query) - query := models.GetTempUsersQuery{OrgId: 2256, Status: models.TmpUserInvitePending} - err = GetTempUsersQuery(&query) + require.Nil(t, err) + require.True(t, query.Result[0].EmailSent) + require.False(t, query.Result[0].EmailSentOn.UTC().Before(query.Result[0].Created.UTC())) + }) - So(err, ShouldBeNil) - So(query.Result[0].EmailSent, ShouldBeTrue) - So(query.Result[0].EmailSentOn.UTC(), ShouldHappenOnOrAfter, query.Result[0].Created.UTC()) - }) + t.Run("Should be able expire temp user", func(t *testing.T) { + setup(t) + createdAt := time.Unix(cmd.Result.Created, 0) + cmd2 := models.ExpireTempUsersCommand{OlderThan: createdAt.Add(1 * time.Second)} + err := ExpireOldUserInvites(&cmd2) + require.Nil(t, err) + require.Equal(t, int64(1), cmd2.NumExpired) - Convey("Should be able expire temp user", func() { - createdAt := time.Unix(cmd.Result.Created, 0) - cmd2 := models.ExpireTempUsersCommand{OlderThan: createdAt.Add(1 * time.Second)} - err := ExpireOldUserInvites(&cmd2) - So(err, ShouldBeNil) - So(cmd2.NumExpired, ShouldEqual, int64(1)) - - Convey("Should do nothing when no temp users to expire", func() { - createdAt := time.Unix(cmd.Result.Created, 0) - cmd2 := models.ExpireTempUsersCommand{OlderThan: createdAt.Add(1 * time.Second)} - err := ExpireOldUserInvites(&cmd2) - So(err, ShouldBeNil) - So(cmd2.NumExpired, ShouldEqual, int64(0)) - }) - }) + t.Run("Should do nothing when no temp users to expire", func(t *testing.T) { + createdAt := time.Unix(cmd.Result.Created, 0) + cmd2 := models.ExpireTempUsersCommand{OlderThan: createdAt.Add(1 * time.Second)} + err := ExpireOldUserInvites(&cmd2) + require.Nil(t, err) + require.Equal(t, int64(0), cmd2.NumExpired) }) }) } diff --git a/pkg/services/sqlstore/transactions_test.go b/pkg/services/sqlstore/transactions_test.go index 78ab4f14fc3..c8f2f1a1dc0 100644 --- a/pkg/services/sqlstore/transactions_test.go +++ b/pkg/services/sqlstore/transactions_test.go @@ -8,9 +8,8 @@ import ( "errors" "testing" - . "github.com/smartystreets/goconvey/convey" - "github.com/grafana/grafana/pkg/models" + "github.com/stretchr/testify/require" ) var ErrProvokedError = errors.New("testing error") @@ -18,40 +17,40 @@ var ErrProvokedError = errors.New("testing error") func TestTransaction(t *testing.T) { ss := InitTestDB(t) - Convey("InTransaction", t, func() { - cmd := &models.AddApiKeyCommand{Key: "secret-key", Name: "key", OrgId: 1} - + cmd := &models.AddApiKeyCommand{Key: "secret-key", Name: "key", OrgId: 1} + t.Run("can update key", func(t *testing.T) { err := AddAPIKey(context.Background(), cmd) - So(err, ShouldBeNil) + require.Nil(t, err) - Convey("can update key", func() { - err := ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { - return deleteAPIKey(sess, cmd.Result.Id, 1) - }) - - So(err, ShouldBeNil) - - query := &models.GetApiKeyByIdQuery{ApiKeyId: cmd.Result.Id} - err = GetApiKeyById(query) - So(err, ShouldEqual, models.ErrInvalidApiKey) + err = ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { + return deleteAPIKey(sess, cmd.Result.Id, 1) }) - Convey("won't update if one handler fails", func() { - err := ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { - err := deleteAPIKey(sess, cmd.Result.Id, 1) - if err != nil { - return err - } + require.Nil(t, err) - return ErrProvokedError - }) + query := &models.GetApiKeyByIdQuery{ApiKeyId: cmd.Result.Id} + err = GetApiKeyById(query) + require.Equal(t, models.ErrInvalidApiKey, err) + }) - So(err, ShouldEqual, ErrProvokedError) + t.Run("won't update if one handler fails", func(t *testing.T) { + err := AddAPIKey(context.Background(), cmd) + require.Nil(t, err) - query := &models.GetApiKeyByIdQuery{ApiKeyId: cmd.Result.Id} - err = GetApiKeyById(query) - So(err, ShouldBeNil) - So(query.Result.Id, ShouldEqual, cmd.Result.Id) + err = ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { + err := deleteAPIKey(sess, cmd.Result.Id, 1) + if err != nil { + return err + } + + return ErrProvokedError }) + + require.Equal(t, ErrProvokedError, err) + + query := &models.GetApiKeyByIdQuery{ApiKeyId: cmd.Result.Id} + err = GetApiKeyById(query) + require.Nil(t, err) + require.Equal(t, cmd.Result.Id, query.Result.Id) }) }