Chore: Add alert ctx (#41161)

* Add context for alert

* Remove context.TODO

* Remove xorm

* Remove context.TODO

* Fix UsageStatsQuerier interface
This commit is contained in:
idafurjes 2021-11-03 14:10:39 +01:00 committed by GitHub
parent 0997065e04
commit 9340430723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 198 additions and 186 deletions

View File

@ -330,7 +330,7 @@ func (hs *HTTPServer) PostDashboard(c *models.ReqContext, cmd models.SaveDashboa
} }
dashSvc := dashboards.NewService(hs.SQLStore) dashSvc := dashboards.NewService(hs.SQLStore)
dashboard, err := dashSvc.SaveDashboard(dashItem, allowUiUpdate) dashboard, err := dashSvc.SaveDashboard(ctx, dashItem, allowUiUpdate)
if hs.Live != nil { if hs.Live != nil {
// Tell everyone listening that the dashboard changed // Tell everyone listening that the dashboard changed

View File

@ -18,5 +18,5 @@ type Store interface {
SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error) SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error)
UpdateDashboardACLCtx(ctx context.Context, uid int64, items []*models.DashboardAcl) error UpdateDashboardACLCtx(ctx context.Context, uid int64, items []*models.DashboardAcl) error
// SaveAlerts saves dashboard alerts. // SaveAlerts saves dashboard alerts.
SaveAlerts(dashID int64, alerts []*models.Alert) error SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error
} }

View File

@ -16,10 +16,10 @@ func (usm *UsageStatsMock) RegisterMetricsFunc(fn MetricsFunc) {
usm.metricsFuncs = append(usm.metricsFuncs, fn) usm.metricsFuncs = append(usm.metricsFuncs, fn)
} }
func (usm *UsageStatsMock) GetUsageReport(_ context.Context) (Report, error) { func (usm *UsageStatsMock) GetUsageReport(ctx context.Context) (Report, error) {
all := make(map[string]interface{}) all := make(map[string]interface{})
for _, fn := range usm.metricsFuncs { for _, fn := range usm.metricsFuncs {
fnMetrics, err := fn() fnMetrics, err := fn(ctx)
require.NoError(usm.T, err) require.NoError(usm.T, err)
for name, value := range fnMetrics { for name, value := range fnMetrics {

View File

@ -15,7 +15,7 @@ type Report struct {
UsageStatsId string `json:"usageStatsId"` UsageStatsId string `json:"usageStatsId"`
} }
type MetricsFunc func() (map[string]interface{}, error) type MetricsFunc func(context.Context) (map[string]interface{}, error)
type SendReportCallbackFunc func() type SendReportCallbackFunc func()

View File

@ -93,7 +93,7 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
metrics["stats.edition.oss.count"] = ossEditionCount metrics["stats.edition.oss.count"] = ossEditionCount
metrics["stats.edition.enterprise.count"] = enterpriseEditionCount metrics["stats.edition.enterprise.count"] = enterpriseEditionCount
uss.registerExternalMetrics(metrics) uss.registerExternalMetrics(ctx, metrics)
// must run after registration of external metrics // must run after registration of external metrics
if v, ok := metrics["stats.valid_license.count"]; ok { if v, ok := metrics["stats.valid_license.count"]; ok {
@ -231,9 +231,9 @@ func (uss *UsageStats) GetUsageReport(ctx context.Context) (usagestats.Report, e
return report, nil return report, nil
} }
func (uss *UsageStats) registerExternalMetrics(metrics map[string]interface{}) { func (uss *UsageStats) registerExternalMetrics(ctx context.Context, metrics map[string]interface{}) {
for _, fn := range uss.externalMetrics { for _, fn := range uss.externalMetrics {
fnMetrics, err := fn() fnMetrics, err := fn(ctx)
if err != nil { if err != nil {
uss.log.Error("Failed to fetch external metrics", "error", err) uss.log.Error("Failed to fetch external metrics", "error", err)
continue continue

View File

@ -448,11 +448,11 @@ func TestMetrics(t *testing.T) {
metricName := "stats.test_metric.count" metricName := "stats.test_metric.count"
t.Run("Adds a new metric to the external metrics", func(t *testing.T) { t.Run("Adds a new metric to the external metrics", func(t *testing.T) {
uss.RegisterMetricsFunc(func() (map[string]interface{}, error) { uss.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{metricName: 1}, nil return map[string]interface{}{metricName: 1}, nil
}) })
metrics, err := uss.externalMetrics[0]() metrics, err := uss.externalMetrics[0](context.Background())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, map[string]interface{}{metricName: 1}, metrics) assert.Equal(t, map[string]interface{}{metricName: 1}, metrics)
}) })
@ -502,7 +502,7 @@ func TestMetrics(t *testing.T) {
}) })
t.Run("Should include external metrics", func(t *testing.T) { t.Run("Should include external metrics", func(t *testing.T) {
uss.RegisterMetricsFunc(func() (map[string]interface{}, error) { uss.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{metricName: 1}, nil return map[string]interface{}{metricName: 1}, nil
}) })
@ -519,26 +519,26 @@ func TestMetrics(t *testing.T) {
metrics := map[string]interface{}{"stats.test_metric.count": 1, "stats.test_metric_second.count": 2} metrics := map[string]interface{}{"stats.test_metric.count": 1, "stats.test_metric_second.count": 2}
extMetricName := "stats.test_external_metric.count" extMetricName := "stats.test_external_metric.count"
uss.RegisterMetricsFunc(func() (map[string]interface{}, error) { uss.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{extMetricName: 1}, nil return map[string]interface{}{extMetricName: 1}, nil
}) })
uss.registerExternalMetrics(metrics) uss.registerExternalMetrics(context.Background(), metrics)
assert.Equal(t, 1, metrics[extMetricName]) assert.Equal(t, 1, metrics[extMetricName])
t.Run("When loading a metric results to an error", func(t *testing.T) { t.Run("When loading a metric results to an error", func(t *testing.T) {
uss.RegisterMetricsFunc(func() (map[string]interface{}, error) { uss.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{extMetricName: 1}, nil return map[string]interface{}{extMetricName: 1}, nil
}) })
extErrorMetricName := "stats.test_external_metric_error.count" extErrorMetricName := "stats.test_external_metric_error.count"
t.Run("Should not add it to metrics", func(t *testing.T) { t.Run("Should not add it to metrics", func(t *testing.T) {
uss.RegisterMetricsFunc(func() (map[string]interface{}, error) { uss.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{extErrorMetricName: 1}, errors.New("some error") return map[string]interface{}{extErrorMetricName: 1}, errors.New("some error")
}) })
uss.registerExternalMetrics(metrics) uss.registerExternalMetrics(context.Background(), metrics)
extErrorMetric := metrics[extErrorMetricName] extErrorMetric := metrics[extErrorMetricName]
extMetric := metrics[extMetricName] extMetric := metrics[extMetricName]

View File

@ -43,7 +43,7 @@ func (ac *OSSAccessControlService) IsDisabled() bool {
} }
func (ac *OSSAccessControlService) registerUsageMetrics() { func (ac *OSSAccessControlService) registerUsageMetrics() {
ac.UsageStats.RegisterMetricsFunc(func() (map[string]interface{}, error) { ac.UsageStats.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
return map[string]interface{}{ return map[string]interface{}{
"stats.oss.accesscontrol.enabled.count": ac.getUsageMetrics(), "stats.oss.accesscontrol.enabled.count": ac.getUsageMetrics(),
}, nil }, nil

View File

@ -21,14 +21,14 @@ type UsageStats struct {
// UsageStatsQuerier returns usage stats about alert rules // UsageStatsQuerier returns usage stats about alert rules
// configured in Grafana. // configured in Grafana.
type UsageStatsQuerier interface { type UsageStatsQuerier interface {
QueryUsageStats() (*UsageStats, error) QueryUsageStats(context.Context) (*UsageStats, error)
} }
// QueryUsageStats returns usage stats about alert rules // QueryUsageStats returns usage stats about alert rules
// configured in Grafana. // configured in Grafana.
func (e *AlertEngine) QueryUsageStats() (*UsageStats, error) { func (e *AlertEngine) QueryUsageStats(ctx context.Context) (*UsageStats, error) {
cmd := &models.GetAllAlertsQuery{} cmd := &models.GetAllAlertsQuery{}
err := e.Bus.Dispatch(cmd) err := e.Bus.DispatchCtx(ctx, cmd)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -56,7 +56,7 @@ func TestAlertingUsageStats(t *testing.T) {
return nil return nil
}) })
result, err := ae.QueryUsageStats() result, err := ae.QueryUsageStats(context.Background())
require.NoError(t, err, "getAlertingUsage should not return error") require.NoError(t, err, "getAlertingUsage should not return error")
expected := map[string]int{ expected := map[string]int{

View File

@ -97,7 +97,7 @@ func (e *AlertEngine) alertingTicker(grafanaCtx context.Context) error {
case tick := <-e.ticker.C: case tick := <-e.ticker.C:
// TEMP SOLUTION update rules ever tenth tick // TEMP SOLUTION update rules ever tenth tick
if tickIndex%10 == 0 { if tickIndex%10 == 0 {
e.scheduler.Update(e.ruleReader.fetch()) e.scheduler.Update(e.ruleReader.fetch(grafanaCtx))
} }
e.scheduler.Tick(tick, e.execQueue) e.scheduler.Tick(tick, e.execQueue)
@ -246,8 +246,8 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan
} }
func (e *AlertEngine) registerUsageMetrics() { func (e *AlertEngine) registerUsageMetrics() {
e.usageStatsService.RegisterMetricsFunc(func() (map[string]interface{}, error) { e.usageStatsService.RegisterMetricsFunc(func(ctx context.Context) (map[string]interface{}, error) {
alertingUsageStats, err := e.QueryUsageStats() alertingUsageStats, err := e.QueryUsageStats(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,6 +1,7 @@
package alerting package alerting
import ( import (
"context"
"sync" "sync"
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
@ -10,7 +11,7 @@ import (
) )
type ruleReader interface { type ruleReader interface {
fetch() []*Rule fetch(context.Context) []*Rule
} }
type defaultRuleReader struct { type defaultRuleReader struct {
@ -26,10 +27,10 @@ func newRuleReader() *defaultRuleReader {
return ruleReader return ruleReader
} }
func (arr *defaultRuleReader) fetch() []*Rule { func (arr *defaultRuleReader) fetch(ctx context.Context) []*Rule {
cmd := &models.GetAllAlertsQuery{} cmd := &models.GetAllAlertsQuery{}
if err := bus.Dispatch(cmd); err != nil { if err := bus.DispatchCtx(ctx, cmd); err != nil {
arr.log.Error("Could not load alerts", "error", err) arr.log.Error("Could not load alerts", "error", err)
return []*Rule{} return []*Rule{}
} }

View File

@ -21,7 +21,7 @@ import (
// DashboardService is a service for operating on dashboards. // DashboardService is a service for operating on dashboards.
type DashboardService interface { type DashboardService interface {
SaveDashboard(dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error)
ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error)
DeleteDashboard(dashboardId int64, orgId int64) error DeleteDashboard(dashboardId int64, orgId int64) error
MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error
@ -29,8 +29,8 @@ type DashboardService interface {
// DashboardProvisioningService is a service for operating on provisioned dashboards. // DashboardProvisioningService is a service for operating on provisioned dashboards.
type DashboardProvisioningService interface { type DashboardProvisioningService interface {
SaveProvisionedDashboard(dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) SaveProvisionedDashboard(ctx context.Context, dto *SaveDashboardDTO, provisioning *models.DashboardProvisioning) (*models.Dashboard, error)
SaveFolderForProvisionedDashboards(*SaveDashboardDTO) (*models.Dashboard, error) SaveFolderForProvisionedDashboards(context.Context, *SaveDashboardDTO) (*models.Dashboard, error)
GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error)
GetProvisionedDashboardDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error) GetProvisionedDashboardDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error)
UnprovisionDashboard(dashboardID int64) error UnprovisionDashboard(dashboardID int64) error
@ -205,17 +205,17 @@ func validateDashboardRefreshInterval(dash *models.Dashboard) error {
// UpdateAlerting updates alerting. // UpdateAlerting updates alerting.
// //
// Stubbable by tests. // Stubbable by tests.
var UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error { var UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error {
extractor := alerting.NewDashAlertExtractor(dashboard, orgID, user) extractor := alerting.NewDashAlertExtractor(dashboard, orgID, user)
alerts, err := extractor.GetAlerts() alerts, err := extractor.GetAlerts()
if err != nil { if err != nil {
return err return err
} }
return store.SaveAlerts(dashboard.Id, alerts) return store.SaveAlerts(ctx, dashboard.Id, alerts)
} }
func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO, func (dr *dashboardServiceImpl) SaveProvisionedDashboard(ctx context.Context, dto *SaveDashboardDTO,
provisioning *models.DashboardProvisioning) (*models.Dashboard, error) { provisioning *models.DashboardProvisioning) (*models.Dashboard, error) {
if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil {
dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid", dr.log.Warn("Changing refresh interval for provisioned dashboard to minimum refresh interval", "dashboardUid",
@ -241,14 +241,14 @@ func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO,
} }
// alerts // alerts
if err := UpdateAlerting(dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil {
return nil, err return nil, err
} }
return dash, nil return dash, nil
} }
func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(dto *SaveDashboardDTO) (*models.Dashboard, error) { func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(ctx context.Context, dto *SaveDashboardDTO) (*models.Dashboard, error) {
dto.User = &models.SignedInUser{ dto.User = &models.SignedInUser{
UserId: 0, UserId: 0,
OrgRole: models.ROLE_ADMIN, OrgRole: models.ROLE_ADMIN,
@ -263,14 +263,14 @@ func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(dto *SaveDash
return nil, err return nil, err
} }
if err := UpdateAlerting(dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil {
return nil, err return nil, err
} }
return dash, nil return dash, nil
} }
func (dr *dashboardServiceImpl) SaveDashboard(dto *SaveDashboardDTO, func (dr *dashboardServiceImpl) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO,
allowUiUpdate bool) (*models.Dashboard, error) { allowUiUpdate bool) (*models.Dashboard, error) {
if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil { if err := validateDashboardRefreshInterval(dto.Dashboard); err != nil {
dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval", dr.log.Warn("Changing refresh interval for imported dashboard to minimum refresh interval",
@ -289,7 +289,7 @@ func (dr *dashboardServiceImpl) SaveDashboard(dto *SaveDashboardDTO,
return nil, fmt.Errorf("saving dashboard failed: %w", err) return nil, fmt.Errorf("saving dashboard failed: %w", err)
} }
if err := UpdateAlerting(dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil { if err := UpdateAlerting(ctx, dr.dashboardStore, dto.OrgId, dash, dto.User); err != nil {
return nil, err return nil, err
} }
@ -360,7 +360,7 @@ type FakeDashboardService struct {
ProvisionedDashData *models.DashboardProvisioning ProvisionedDashData *models.DashboardProvisioning
} }
func (s *FakeDashboardService) SaveDashboard(dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) { func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) {
s.SavedDashboards = append(s.SavedDashboards, dto) s.SavedDashboards = append(s.SavedDashboards, dto)
if s.SaveDashboardResult == nil && s.SaveDashboardError == nil { if s.SaveDashboardResult == nil && s.SaveDashboardError == nil {
@ -371,7 +371,7 @@ func (s *FakeDashboardService) SaveDashboard(dto *SaveDashboardDTO, allowUiUpdat
} }
func (s *FakeDashboardService) ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) { func (s *FakeDashboardService) ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) {
return s.SaveDashboard(dto, true) return s.SaveDashboard(context.Background(), dto, true)
} }
func (s *FakeDashboardService) DeleteDashboard(dashboardId int64, orgId int64) error { func (s *FakeDashboardService) DeleteDashboard(dashboardId int64, orgId int64) error {

View File

@ -4,6 +4,7 @@
package dashboards package dashboards
import ( import (
"context"
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
@ -24,7 +25,7 @@ func TestIntegratedDashboardService(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
UpdateAlerting = origUpdateAlerting UpdateAlerting = origUpdateAlerting
}) })
UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error { UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error {
return nil return nil
} }
@ -849,7 +850,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore
t.Helper() t.Helper()
dto := toSaveDashboardDto(cmd) dto := toSaveDashboardDto(cmd)
res, err := NewService(sqlStore).SaveDashboard(&dto, false) res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
require.NoError(t, err) require.NoError(t, err)
return res return res
@ -857,7 +858,7 @@ func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore
func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLStore) error { func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLStore) error {
dto := toSaveDashboardDto(cmd) dto := toSaveDashboardDto(cmd)
_, err := NewService(sqlStore).SaveDashboard(&dto, false) _, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
return err return err
} }
@ -883,7 +884,7 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
}, },
} }
res, err := NewService(sqlStore).SaveDashboard(&dto, false) res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
require.NoError(t, err) require.NoError(t, err)
return res return res
@ -910,7 +911,7 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore.
}, },
} }
res, err := NewService(sqlStore).SaveDashboard(&dto, false) res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
require.NoError(t, err) require.NoError(t, err)
return res return res

View File

@ -1,6 +1,7 @@
package dashboards package dashboards
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
@ -37,7 +38,7 @@ func TestDashboardService(t *testing.T) {
for _, title := range titles { for _, title := range titles {
dto.Dashboard = models.NewDashboard(title) dto.Dashboard = models.NewDashboard(title)
_, err := service.SaveDashboard(dto, false) _, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardTitleEmpty) require.Equal(t, err, models.ErrDashboardTitleEmpty)
} }
}) })
@ -45,13 +46,13 @@ func TestDashboardService(t *testing.T) {
t.Run("Should return validation error if it's a folder and have a folder id", func(t *testing.T) { t.Run("Should return validation error if it's a folder and have a folder id", func(t *testing.T) {
dto.Dashboard = models.NewDashboardFolder("Folder") dto.Dashboard = models.NewDashboardFolder("Folder")
dto.Dashboard.FolderId = 1 dto.Dashboard.FolderId = 1
_, err := service.SaveDashboard(dto, false) _, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardFolderCannotHaveParent) require.Equal(t, err, models.ErrDashboardFolderCannotHaveParent)
}) })
t.Run("Should return validation error if folder is named General", func(t *testing.T) { t.Run("Should return validation error if folder is named General", func(t *testing.T) {
dto.Dashboard = models.NewDashboardFolder("General") dto.Dashboard = models.NewDashboardFolder("General")
_, err := service.SaveDashboard(dto, false) _, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardFolderNameExists) require.Equal(t, err, models.ErrDashboardFolderNameExists)
}) })
@ -104,7 +105,7 @@ func TestDashboardService(t *testing.T) {
dto.Dashboard = models.NewDashboard("Dash") dto.Dashboard = models.NewDashboard("Dash")
dto.Dashboard.SetId(3) dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1} dto.User = &models.SignedInUser{UserId: 1}
_, err := service.SaveDashboard(dto, false) _, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err, models.ErrDashboardCannotSaveProvisionedDashboard) require.Equal(t, err, models.ErrDashboardCannotSaveProvisionedDashboard)
}) })
@ -120,7 +121,7 @@ func TestDashboardService(t *testing.T) {
dto.Dashboard = models.NewDashboard("Dash") dto.Dashboard = models.NewDashboard("Dash")
dto.Dashboard.SetId(3) dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1} dto.User = &models.SignedInUser{UserId: 1}
_, err := service.SaveDashboard(dto, true) _, err := service.SaveDashboard(context.Background(), dto, true)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -134,7 +135,7 @@ func TestDashboardService(t *testing.T) {
} }
dto.Dashboard = models.NewDashboard("Dash") dto.Dashboard = models.NewDashboard("Dash")
_, err := service.SaveDashboard(dto, false) _, err := service.SaveDashboard(context.Background(), dto, false)
require.Equal(t, err.Error(), "alert validation error") require.Equal(t, err.Error(), "alert validation error")
}) })
}) })
@ -147,7 +148,7 @@ func TestDashboardService(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
UpdateAlerting = origUpdateAlerting UpdateAlerting = origUpdateAlerting
}) })
UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }
@ -163,7 +164,7 @@ func TestDashboardService(t *testing.T) {
dto.Dashboard = models.NewDashboard("Dash") dto.Dashboard = models.NewDashboard("Dash")
dto.Dashboard.SetId(3) dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1} dto.User = &models.SignedInUser{UserId: 1}
_, err := service.SaveProvisionedDashboard(dto, nil) _, err := service.SaveProvisionedDashboard(context.Background(), dto, nil)
require.NoError(t, err) require.NoError(t, err)
}) })
@ -184,7 +185,7 @@ func TestDashboardService(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
UpdateAlerting = origUpdateAlerting UpdateAlerting = origUpdateAlerting
}) })
UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }
@ -193,7 +194,7 @@ func TestDashboardService(t *testing.T) {
dto.Dashboard.SetId(3) dto.Dashboard.SetId(3)
dto.User = &models.SignedInUser{UserId: 1} dto.User = &models.SignedInUser{UserId: 1}
dto.Dashboard.Data.Set("refresh", "1s") dto.Dashboard.Data.Set("refresh", "1s")
_, err := service.SaveProvisionedDashboard(dto, nil) _, err := service.SaveProvisionedDashboard(context.Background(), dto, nil)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, dto.Dashboard.Data.Get("refresh").MustString(), "5m") require.Equal(t, dto.Dashboard.Data.Get("refresh").MustString(), "5m")
}) })
@ -220,7 +221,7 @@ func TestDashboardService(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
UpdateAlerting = origUpdateAlerting UpdateAlerting = origUpdateAlerting
}) })
UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }
@ -317,6 +318,6 @@ func (s *fakeDashboardStore) SaveDashboard(cmd models.SaveDashboardCommand) (*mo
return cmd.GetDashboardModel(), nil return cmd.GetDashboardModel(), nil
} }
func (s *fakeDashboardStore) SaveAlerts(dashID int64, alerts []*models.Alert) error { func (s *fakeDashboardStore) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
return nil return nil
} }

View File

@ -94,7 +94,7 @@ func TestFolderService(t *testing.T) {
t.Cleanup(func() { t.Cleanup(func() {
UpdateAlerting = origUpdateAlerting UpdateAlerting = origUpdateAlerting
}) })
UpdateAlerting = func(store dashboards.Store, orgID int64, dashboard *models.Dashboard, UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }

View File

@ -189,12 +189,12 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user models.Sign
t.Cleanup(func() { t.Cleanup(func() {
dashboards.UpdateAlerting = origUpdateAlerting dashboards.UpdateAlerting = origUpdateAlerting
}) })
dashboards.UpdateAlerting = func(store dboards.Store, orgID int64, dashboard *models.Dashboard, dashboards.UpdateAlerting = func(ctx context.Context, store dboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }
dashboard, err := dashboards.NewService(sqlStore).SaveDashboard(dashItem, true) dashboard, err := dashboards.NewService(sqlStore).SaveDashboard(context.Background(), dashItem, true)
require.NoError(t, err) require.NoError(t, err)
return dashboard return dashboard

View File

@ -1417,12 +1417,12 @@ func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user *models.Sig
t.Cleanup(func() { t.Cleanup(func() {
dashboards.UpdateAlerting = origUpdateAlerting dashboards.UpdateAlerting = origUpdateAlerting
}) })
dashboards.UpdateAlerting = func(store dboards.Store, orgID int64, dashboard *models.Dashboard, dashboards.UpdateAlerting = func(ctx context.Context, store dboards.Store, orgID int64, dashboard *models.Dashboard,
user *models.SignedInUser) error { user *models.SignedInUser) error {
return nil return nil
} }
dashboard, err := dashboards.NewService(sqlStore).SaveDashboard(dashItem, true) dashboard, err := dashboards.NewService(sqlStore).SaveDashboard(context.Background(), dashItem, true)
require.NoError(t, err) require.NoError(t, err)
return dashboard return dashboard

View File

@ -1210,7 +1210,7 @@ func (g *GrafanaLive) resetLiveStats() {
func (g *GrafanaLive) registerUsageMetrics() { func (g *GrafanaLive) registerUsageMetrics() {
g.usageStatsService.RegisterSendReportCallback(g.resetLiveStats) g.usageStatsService.RegisterSendReportCallback(g.resetLiveStats)
g.usageStatsService.RegisterMetricsFunc(func() (map[string]interface{}, error) { g.usageStatsService.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
liveUsersAvg := 0 liveUsersAvg := 0
liveClientsAvg := 0 liveClientsAvg := 0

View File

@ -146,7 +146,7 @@ func (fr *FileReader) storeDashboardsInFolder(ctx context.Context, filesFoundOnD
// save dashboards based on json files // save dashboards based on json files
for path, fileInfo := range filesFoundOnDisk { for path, fileInfo := range filesFoundOnDisk {
provisioningMetadata, err := fr.saveDashboard(path, folderID, fileInfo, dashboardRefs) provisioningMetadata, err := fr.saveDashboard(ctx, path, folderID, fileInfo, dashboardRefs)
if err != nil { if err != nil {
fr.log.Error("failed to save dashboard", "error", err) fr.log.Error("failed to save dashboard", "error", err)
continue continue
@ -174,7 +174,7 @@ func (fr *FileReader) storeDashboardsInFoldersFromFileStructure(ctx context.Cont
return fmt.Errorf("can't provision folder %q from file system structure: %w", folderName, err) return fmt.Errorf("can't provision folder %q from file system structure: %w", folderName, err)
} }
provisioningMetadata, err := fr.saveDashboard(path, folderID, fileInfo, dashboardRefs) provisioningMetadata, err := fr.saveDashboard(ctx, path, folderID, fileInfo, dashboardRefs)
usageTracker.track(provisioningMetadata) usageTracker.track(provisioningMetadata)
if err != nil { if err != nil {
fr.log.Error("failed to save dashboard", "error", err) fr.log.Error("failed to save dashboard", "error", err)
@ -218,7 +218,7 @@ func (fr *FileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[s
} }
// saveDashboard saves or updates the dashboard provisioning file at path. // saveDashboard saves or updates the dashboard provisioning file at path.
func (fr *FileReader) saveDashboard(path string, folderID int64, fileInfo os.FileInfo, func (fr *FileReader) saveDashboard(ctx context.Context, path string, folderID int64, fileInfo os.FileInfo,
provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) { provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) {
provisioningMetadata := provisioningMetadata{} provisioningMetadata := provisioningMetadata{}
resolvedFileInfo, err := resolveSymlink(fileInfo, path) resolvedFileInfo, err := resolveSymlink(fileInfo, path)
@ -265,7 +265,7 @@ func (fr *FileReader) saveDashboard(path string, folderID int64, fileInfo os.Fil
Updated: resolvedFileInfo.ModTime().Unix(), Updated: resolvedFileInfo.ModTime().Unix(),
CheckSum: jsonFile.checkSum, CheckSum: jsonFile.checkSum,
} }
if _, err := fr.dashboardProvisioningService.SaveProvisionedDashboard(dash, dp); err != nil { if _, err := fr.dashboardProvisioningService.SaveProvisionedDashboard(ctx, dash, dp); err != nil {
return provisioningMetadata, err return provisioningMetadata, err
} }
} else { } else {
@ -312,7 +312,7 @@ func getOrCreateFolderID(ctx context.Context, cfg *config, service dashboards.Da
dash.OrgId = cfg.OrgID dash.OrgId = cfg.OrgID
// set dashboard folderUid if given // set dashboard folderUid if given
dash.Dashboard.SetUid(cfg.FolderUID) dash.Dashboard.SetUid(cfg.FolderUID)
dbDash, err := service.SaveFolderForProvisionedDashboards(dash) dbDash, err := service.SaveFolderForProvisionedDashboards(ctx, dash)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -565,7 +565,7 @@ func (s *fakeDashboardProvisioningService) GetProvisionedDashboardData(name stri
return s.provisioned[name], nil return s.provisioned[name], nil
} }
func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(dto *dashboards.SaveDashboardDTO, func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO,
provisioning *models.DashboardProvisioning) (*models.Dashboard, error) { provisioning *models.DashboardProvisioning) (*models.Dashboard, error) {
// Copy the structs as we need to change them but do not want to alter outside world. // Copy the structs as we need to change them but do not want to alter outside world.
var copyProvisioning = &models.DashboardProvisioning{} var copyProvisioning = &models.DashboardProvisioning{}
@ -603,7 +603,7 @@ func (s *fakeDashboardProvisioningService) SaveProvisionedDashboard(dto *dashboa
return dto.Dashboard, nil return dto.Dashboard, nil
} }
func (s *fakeDashboardProvisioningService) SaveFolderForProvisionedDashboards(dto *dashboards.SaveDashboardDTO) (*models.Dashboard, error) { func (s *fakeDashboardProvisioningService) SaveFolderForProvisionedDashboards(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*models.Dashboard, error) {
s.inserted = append(s.inserted, dto) s.inserted = append(s.inserted, dto)
return dto.Dashboard, nil return dto.Dashboard, nil
} }

View File

@ -14,40 +14,44 @@ import (
// timeNow makes it possible to test usage of time // timeNow makes it possible to test usage of time
var timeNow = time.Now var timeNow = time.Now
func init() { func (ss *SQLStore) addAlertQueryAndCommandHandlers() {
bus.AddHandler("sql", SaveAlerts) bus.AddHandlerCtx("sql", SaveAlerts)
bus.AddHandler("sql", HandleAlertsQuery) bus.AddHandlerCtx("sql", ss.HandleAlertsQuery)
bus.AddHandler("sql", GetAlertById) bus.AddHandlerCtx("sql", ss.GetAlertById)
bus.AddHandler("sql", GetAllAlertQueryHandler) bus.AddHandlerCtx("sql", ss.GetAllAlertQueryHandler)
bus.AddHandler("sql", SetAlertState) bus.AddHandlerCtx("sql", SetAlertState)
bus.AddHandler("sql", GetAlertStatesForDashboard) bus.AddHandlerCtx("sql", ss.GetAlertStatesForDashboard)
bus.AddHandler("sql", PauseAlert) bus.AddHandlerCtx("sql", PauseAlert)
bus.AddHandler("sql", PauseAllAlerts) bus.AddHandlerCtx("sql", PauseAllAlerts)
} }
func GetAlertById(query *models.GetAlertByIdQuery) error { func (ss *SQLStore) GetAlertById(ctx context.Context, query *models.GetAlertByIdQuery) error {
alert := models.Alert{} return ss.WithDbSession(ctx, func(sess *DBSession) error {
has, err := x.ID(query.Id).Get(&alert) alert := models.Alert{}
if !has { has, err := sess.ID(query.Id).Get(&alert)
return fmt.Errorf("could not find alert") if !has {
} return fmt.Errorf("could not find alert")
if err != nil { }
return err if err != nil {
} return err
}
query.Result = &alert query.Result = &alert
return nil return nil
})
} }
func GetAllAlertQueryHandler(query *models.GetAllAlertsQuery) error { func (ss *SQLStore) GetAllAlertQueryHandler(ctx context.Context, query *models.GetAllAlertsQuery) error {
var alerts []*models.Alert return ss.WithDbSession(ctx, func(sess *DBSession) error {
err := x.SQL("select * from alert").Find(&alerts) var alerts []*models.Alert
if err != nil { err := sess.SQL("select * from alert").Find(&alerts)
return err if err != nil {
} return err
}
query.Result = alerts query.Result = alerts
return nil return nil
})
} }
func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) error { func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) error {
@ -72,10 +76,11 @@ func deleteAlertByIdInternal(alertId int64, reason string, sess *DBSession) erro
return nil return nil
} }
func HandleAlertsQuery(query *models.GetAlertsQuery) error { func (ss *SQLStore) HandleAlertsQuery(ctx context.Context, query *models.GetAlertsQuery) error {
builder := SQLBuilder{} return ss.WithDbSession(ctx, func(sess *DBSession) error {
builder := SQLBuilder{}
builder.Write(`SELECT builder.Write(`SELECT
alert.id, alert.id,
alert.dashboard_id, alert.dashboard_id,
alert.panel_id, alert.panel_id,
@ -90,64 +95,65 @@ func HandleAlertsQuery(query *models.GetAlertsQuery) error {
FROM alert FROM alert
INNER JOIN dashboard on dashboard.id = alert.dashboard_id `) INNER JOIN dashboard on dashboard.id = alert.dashboard_id `)
builder.Write(`WHERE alert.org_id = ?`, query.OrgId) builder.Write(`WHERE alert.org_id = ?`, query.OrgId)
if len(strings.TrimSpace(query.Query)) > 0 { if len(strings.TrimSpace(query.Query)) > 0 {
builder.Write(" AND alert.name "+dialect.LikeStr()+" ?", "%"+query.Query+"%") builder.Write(" AND alert.name "+dialect.LikeStr()+" ?", "%"+query.Query+"%")
}
if len(query.DashboardIDs) > 0 {
builder.sql.WriteString(` AND alert.dashboard_id IN (?` + strings.Repeat(",?", len(query.DashboardIDs)-1) + `) `)
for _, dbID := range query.DashboardIDs {
builder.AddParams(dbID)
} }
}
if query.PanelId != 0 { if len(query.DashboardIDs) > 0 {
builder.Write(` AND alert.panel_id = ?`, query.PanelId) builder.sql.WriteString(` AND alert.dashboard_id IN (?` + strings.Repeat(",?", len(query.DashboardIDs)-1) + `) `)
}
if len(query.State) > 0 && query.State[0] != "all" { for _, dbID := range query.DashboardIDs {
builder.Write(` AND (`) builder.AddParams(dbID)
for i, v := range query.State {
if i > 0 {
builder.Write(" OR ")
} }
if strings.HasPrefix(v, "not_") { }
builder.Write("state <> ? ")
v = strings.TrimPrefix(v, "not_") if query.PanelId != 0 {
} else { builder.Write(` AND alert.panel_id = ?`, query.PanelId)
builder.Write("state = ? ") }
if len(query.State) > 0 && query.State[0] != "all" {
builder.Write(` AND (`)
for i, v := range query.State {
if i > 0 {
builder.Write(" OR ")
}
if strings.HasPrefix(v, "not_") {
builder.Write("state <> ? ")
v = strings.TrimPrefix(v, "not_")
} else {
builder.Write("state = ? ")
}
builder.AddParams(v)
} }
builder.AddParams(v) builder.Write(")")
} }
builder.Write(")")
}
if query.User.OrgRole != models.ROLE_ADMIN { if query.User.OrgRole != models.ROLE_ADMIN {
builder.WriteDashboardPermissionFilter(query.User, models.PERMISSION_VIEW) builder.WriteDashboardPermissionFilter(query.User, models.PERMISSION_VIEW)
}
builder.Write(" ORDER BY name ASC")
if query.Limit != 0 {
builder.Write(dialect.Limit(query.Limit))
}
alerts := make([]*models.AlertListItemDTO, 0)
if err := x.SQL(builder.GetSQLString(), builder.params...).Find(&alerts); err != nil {
return err
}
for i := range alerts {
if alerts[i].ExecutionError == " " {
alerts[i].ExecutionError = ""
} }
}
query.Result = alerts builder.Write(" ORDER BY name ASC")
return nil
if query.Limit != 0 {
builder.Write(dialect.Limit(query.Limit))
}
alerts := make([]*models.AlertListItemDTO, 0)
if err := sess.SQL(builder.GetSQLString(), builder.params...).Find(&alerts); err != nil {
return err
}
for i := range alerts {
if alerts[i].ExecutionError == " " {
alerts[i].ExecutionError = ""
}
}
query.Result = alerts
return nil
})
} }
func deleteAlertDefinition(dashboardId int64, sess *DBSession) error { func deleteAlertDefinition(dashboardId int64, sess *DBSession) error {
@ -167,7 +173,7 @@ func deleteAlertDefinition(dashboardId int64, sess *DBSession) error {
return nil return nil
} }
func (ss *SQLStore) SaveAlerts(dashID int64, alerts []*models.Alert) error { func (ss *SQLStore) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
return ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error { return ss.WithTransactionalDbSession(context.Background(), func(sess *DBSession) error {
existingAlerts, err := GetAlertsByDashboardId2(dashID, sess) existingAlerts, err := GetAlertsByDashboardId2(dashID, sess)
if err != nil { if err != nil {
@ -186,7 +192,7 @@ func (ss *SQLStore) SaveAlerts(dashID int64, alerts []*models.Alert) error {
}) })
} }
func SaveAlerts(cmd *models.SaveAlertsCommand) error { func SaveAlerts(ctx context.Context, cmd *models.SaveAlertsCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
existingAlerts, err := GetAlertsByDashboardId2(cmd.DashboardId, sess) existingAlerts, err := GetAlertsByDashboardId2(cmd.DashboardId, sess)
if err != nil { if err != nil {
@ -299,7 +305,7 @@ func GetAlertsByDashboardId2(dashboardId int64, sess *DBSession) ([]*models.Aler
return alerts, nil return alerts, nil
} }
func SetAlertState(cmd *models.SetAlertStateCommand) error { func SetAlertState(ctx context.Context, cmd *models.SetAlertStateCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
alert := models.Alert{} alert := models.Alert{}
@ -338,7 +344,7 @@ func SetAlertState(cmd *models.SetAlertStateCommand) error {
}) })
} }
func PauseAlert(cmd *models.PauseAlertCommand) error { func PauseAlert(ctx context.Context, cmd *models.PauseAlertCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
if len(cmd.AlertIds) == 0 { if len(cmd.AlertIds) == 0 {
return fmt.Errorf("command contains no alertids") return fmt.Errorf("command contains no alertids")
@ -372,7 +378,7 @@ func PauseAlert(cmd *models.PauseAlertCommand) error {
}) })
} }
func PauseAllAlerts(cmd *models.PauseAllAlertCommand) error { func PauseAllAlerts(ctx context.Context, cmd *models.PauseAllAlertCommand) error {
return inTransaction(func(sess *DBSession) error { return inTransaction(func(sess *DBSession) error {
var newState string var newState string
if cmd.Paused { if cmd.Paused {
@ -390,8 +396,9 @@ func PauseAllAlerts(cmd *models.PauseAllAlertCommand) error {
}) })
} }
func GetAlertStatesForDashboard(query *models.GetAlertStatesForDashboardQuery) error { func (ss *SQLStore) GetAlertStatesForDashboard(ctx context.Context, query *models.GetAlertStatesForDashboardQuery) error {
var rawSQL = `SELECT return ss.WithDbSession(ctx, func(sess *DBSession) error {
var rawSQL = `SELECT
id, id,
dashboard_id, dashboard_id,
panel_id, panel_id,
@ -400,8 +407,9 @@ func GetAlertStatesForDashboard(query *models.GetAlertStatesForDashboardQuery) e
FROM alert FROM alert
WHERE org_id = ? AND dashboard_id = ?` WHERE org_id = ? AND dashboard_id = ?`
query.Result = make([]*models.AlertStateInfoDTO, 0) query.Result = make([]*models.AlertStateInfoDTO, 0)
err := x.SQL(rawSQL, query.OrgId, query.DashboardId).Find(&query.Result) err := sess.SQL(rawSQL, query.OrgId, query.DashboardId).Find(&query.Result)
return err return err
})
} }

View File

@ -63,7 +63,7 @@ func TestAlertingDataAccess(t *testing.T) {
UserId: 1, UserId: 1,
} }
err = SaveAlerts(&cmd) err = SaveAlerts(context.Background(), &cmd)
require.Nil(t, err) require.Nil(t, err)
} }
@ -72,7 +72,7 @@ func TestAlertingDataAccess(t *testing.T) {
// Get alert so we can use its ID in tests // 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}} alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&alertQuery) err2 := sqlStore.HandleAlertsQuery(context.Background(), &alertQuery)
require.Nil(t, err2) require.Nil(t, err2)
insertedAlert := alertQuery.Result[0] insertedAlert := alertQuery.Result[0]
@ -83,11 +83,11 @@ func TestAlertingDataAccess(t *testing.T) {
State: models.AlertStateOK, State: models.AlertStateOK,
} }
err := SetAlertState(cmd) err := SetAlertState(context.Background(), cmd)
require.Nil(t, err) require.Nil(t, err)
}) })
alert, _ := getAlertById(t, insertedAlert.Id) alert, _ := getAlertById(t, insertedAlert.Id, sqlStore)
stateDateBeforePause := alert.NewStateDate stateDateBeforePause := alert.NewStateDate
t.Run("can pause all alerts", func(t *testing.T) { t.Run("can pause all alerts", func(t *testing.T) {
@ -100,18 +100,18 @@ func TestAlertingDataAccess(t *testing.T) {
State: models.AlertStateOK, State: models.AlertStateOK,
} }
err = SetAlertState(cmd) err = SetAlertState(context.Background(), cmd)
require.Error(t, err) require.Error(t, err)
}) })
t.Run("alert is paused", func(t *testing.T) { t.Run("alert is paused", func(t *testing.T) {
alert, _ = getAlertById(t, insertedAlert.Id) alert, _ = getAlertById(t, insertedAlert.Id, sqlStore)
currentState := alert.State currentState := alert.State
require.Equal(t, models.AlertStatePaused, currentState) require.Equal(t, models.AlertStatePaused, currentState)
}) })
t.Run("pausing alerts should update their NewStateDate", func(t *testing.T) { t.Run("pausing alerts should update their NewStateDate", func(t *testing.T) {
alert, _ = getAlertById(t, insertedAlert.Id) alert, _ = getAlertById(t, insertedAlert.Id, sqlStore)
stateDateAfterPause := alert.NewStateDate stateDateAfterPause := alert.NewStateDate
require.True(t, stateDateBeforePause.Before(stateDateAfterPause)) require.True(t, stateDateBeforePause.Before(stateDateAfterPause))
}) })
@ -119,7 +119,7 @@ func TestAlertingDataAccess(t *testing.T) {
t.Run("unpausing alerts should update their NewStateDate again", func(t *testing.T) { t.Run("unpausing alerts should update their NewStateDate again", func(t *testing.T) {
err := pauseAllAlerts(t, false) err := pauseAllAlerts(t, false)
require.Nil(t, err) require.Nil(t, err)
alert, _ = getAlertById(t, insertedAlert.Id) alert, _ = getAlertById(t, insertedAlert.Id, sqlStore)
stateDateAfterUnpause := alert.NewStateDate stateDateAfterUnpause := alert.NewStateDate
require.True(t, stateDateBeforePause.Before(stateDateAfterUnpause)) require.True(t, stateDateBeforePause.Before(stateDateAfterUnpause))
}) })
@ -129,7 +129,7 @@ func TestAlertingDataAccess(t *testing.T) {
t.Run("Can read properties", func(t *testing.T) { t.Run("Can read properties", func(t *testing.T) {
setup(t) setup(t)
alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&alertQuery) err2 := sqlStore.HandleAlertsQuery(context.Background(), &alertQuery)
alert := alertQuery.Result[0] alert := alertQuery.Result[0]
require.Nil(t, err2) require.Nil(t, err2)
@ -151,7 +151,7 @@ func TestAlertingDataAccess(t *testing.T) {
setup(t) setup(t)
viewerUser := &models.SignedInUser{OrgRole: models.ROLE_VIEWER, OrgId: 1} viewerUser := &models.SignedInUser{OrgRole: models.ROLE_VIEWER, OrgId: 1}
alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: viewerUser} alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: viewerUser}
err2 := HandleAlertsQuery(&alertQuery) err2 := sqlStore.HandleAlertsQuery(context.Background(), &alertQuery)
require.Nil(t, err2) require.Nil(t, err2)
require.Equal(t, 1, len(alertQuery.Result)) require.Equal(t, 1, len(alertQuery.Result))
@ -169,7 +169,7 @@ func TestAlertingDataAccess(t *testing.T) {
Alerts: modifiedItems, Alerts: modifiedItems,
} }
err := SaveAlerts(&modifiedCmd) err := SaveAlerts(context.Background(), &modifiedCmd)
t.Run("Can save alerts with same dashboard and panel id", func(t *testing.T) { t.Run("Can save alerts with same dashboard and panel id", func(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
@ -177,7 +177,7 @@ func TestAlertingDataAccess(t *testing.T) {
t.Run("Alerts should be updated", func(t *testing.T) { 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}} query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&query) err2 := sqlStore.HandleAlertsQuery(context.Background(), &query)
require.Nil(t, err2) require.Nil(t, err2)
require.Equal(t, 1, len(query.Result)) require.Equal(t, 1, len(query.Result))
@ -189,7 +189,7 @@ func TestAlertingDataAccess(t *testing.T) {
}) })
t.Run("Updates without changes should be ignored", func(t *testing.T) { t.Run("Updates without changes should be ignored", func(t *testing.T) {
err3 := SaveAlerts(&modifiedCmd) err3 := SaveAlerts(context.Background(), &modifiedCmd)
require.Nil(t, err3) require.Nil(t, err3)
}) })
}) })
@ -221,13 +221,13 @@ func TestAlertingDataAccess(t *testing.T) {
} }
cmd.Alerts = multipleItems cmd.Alerts = multipleItems
err := SaveAlerts(&cmd) err := SaveAlerts(context.Background(), &cmd)
t.Run("Should save 3 dashboards", func(t *testing.T) { t.Run("Should save 3 dashboards", func(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
queryForDashboard := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}} queryForDashboard := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&queryForDashboard) err2 := sqlStore.HandleAlertsQuery(context.Background(), &queryForDashboard)
require.Nil(t, err2) require.Nil(t, err2)
require.Equal(t, 3, len(queryForDashboard.Result)) require.Equal(t, 3, len(queryForDashboard.Result))
@ -237,11 +237,11 @@ func TestAlertingDataAccess(t *testing.T) {
missingOneAlert := multipleItems[:2] missingOneAlert := multipleItems[:2]
cmd.Alerts = missingOneAlert cmd.Alerts = missingOneAlert
err = SaveAlerts(&cmd) err = SaveAlerts(context.Background(), &cmd)
t.Run("should delete the missing alert", func(t *testing.T) { 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}} query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&query) err2 := sqlStore.HandleAlertsQuery(context.Background(), &query)
require.Nil(t, err2) require.Nil(t, err2)
require.Equal(t, 2, len(query.Result)) require.Equal(t, 2, len(query.Result))
}) })
@ -266,7 +266,7 @@ func TestAlertingDataAccess(t *testing.T) {
UserId: 1, UserId: 1,
} }
err := SaveAlerts(&cmd) err := SaveAlerts(context.Background(), &cmd)
require.Nil(t, err) require.Nil(t, err)
err = DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{ err = DeleteDashboard(context.Background(), &models.DeleteDashboardCommand{
@ -277,7 +277,7 @@ func TestAlertingDataAccess(t *testing.T) {
t.Run("Alerts should be removed", func(t *testing.T) { 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}} query := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&query) err2 := sqlStore.HandleAlertsQuery(context.Background(), &query)
require.Nil(t, err2) require.Nil(t, err2)
require.Equal(t, 0, len(query.Result)) require.Equal(t, 0, len(query.Result))
@ -301,7 +301,7 @@ func TestPausingAlerts(t *testing.T) {
// Get alert so we can use its ID in tests // 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}} alertQuery := models.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &models.SignedInUser{OrgRole: models.ROLE_ADMIN}}
err2 := HandleAlertsQuery(&alertQuery) err2 := sqlStore.HandleAlertsQuery(context.Background(), &alertQuery)
require.Nil(t, err2) require.Nil(t, err2)
insertedAlert := alertQuery.Result[0] insertedAlert := alertQuery.Result[0]
@ -311,7 +311,7 @@ func TestPausingAlerts(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
t.Run("the NewStateDate should be updated", func(t *testing.T) { t.Run("the NewStateDate should be updated", func(t *testing.T) {
alert, err := getAlertById(t, insertedAlert.Id) alert, err := getAlertById(t, insertedAlert.Id, sqlStore)
require.Nil(t, err) require.Nil(t, err)
stateDateAfterPause = alert.NewStateDate stateDateAfterPause = alert.NewStateDate
@ -324,7 +324,7 @@ func TestPausingAlerts(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
t.Run("the NewStateDate should be updated again", func(t *testing.T) { t.Run("the NewStateDate should be updated again", func(t *testing.T) {
alert, err := getAlertById(t, insertedAlert.Id) alert, err := getAlertById(t, insertedAlert.Id, sqlStore)
require.Nil(t, err) require.Nil(t, err)
stateDateAfterUnpause := alert.NewStateDate stateDateAfterUnpause := alert.NewStateDate
@ -339,7 +339,7 @@ func pauseAlert(t *testing.T, orgId int64, alertId int64, pauseState bool) (int6
AlertIds: []int64{alertId}, AlertIds: []int64{alertId},
Paused: pauseState, Paused: pauseState,
} }
err := PauseAlert(cmd) err := PauseAlert(context.Background(), cmd)
require.Nil(t, err) require.Nil(t, err)
return cmd.ResultCount, err return cmd.ResultCount, err
} }
@ -363,15 +363,15 @@ func insertTestAlert(title string, message string, orgId int64, dashId int64, se
UserId: 1, UserId: 1,
} }
err := SaveAlerts(&cmd) err := SaveAlerts(context.Background(), &cmd)
return cmd.Alerts[0], err return cmd.Alerts[0], err
} }
func getAlertById(t *testing.T, id int64) (*models.Alert, error) { func getAlertById(t *testing.T, id int64, ss *SQLStore) (*models.Alert, error) {
q := &models.GetAlertByIdQuery{ q := &models.GetAlertByIdQuery{
Id: id, Id: id,
} }
err := GetAlertById(q) err := ss.GetAlertById(context.Background(), q)
require.Nil(t, err) require.Nil(t, err)
return q.Result, err return q.Result, err
} }
@ -380,7 +380,7 @@ func pauseAllAlerts(t *testing.T, pauseState bool) error {
cmd := &models.PauseAllAlertCommand{ cmd := &models.PauseAllAlertCommand{
Paused: pauseState, Paused: pauseState,
} }
err := PauseAllAlerts(cmd) err := PauseAllAlerts(context.Background(), cmd)
require.Nil(t, err) require.Nil(t, err)
return err return err
} }

View File

@ -117,6 +117,7 @@ func newSQLStore(cfg *setting.Cfg, cacheService *localcache.CacheService, bus bu
ss.addQuotaQueryAndCommandHandlers() ss.addQuotaQueryAndCommandHandlers()
ss.addOrgUsersQueryAndCommandHandlers() ss.addOrgUsersQueryAndCommandHandlers()
ss.addStarQueryAndCommandHandlers() ss.addStarQueryAndCommandHandlers()
ss.addAlertQueryAndCommandHandlers()
// if err := ss.Reset(); err != nil { // if err := ss.Reset(); err != nil {
// return nil, err // return nil, err