From 1df340ff28b72d5bee63c3276ce8b2cdb9363352 Mon Sep 17 00:00:00 2001 From: Kristin Laemmert Date: Tue, 17 May 2022 14:52:22 -0400 Subject: [PATCH] backend/services: Move GetDashboard from sqlstore to dashboard service (#48971) * rename folder to match package name * backend/sqlstore: move GetDashboard into DashboardService This is a stepping-stone commit which copies the GetDashboard function - which lets us remove the sqlstore from the interfaces in dashboards - without changing any other callers. * checkpoint: moving GetDashboard calls into dashboard service * finish refactoring api tests for dashboardService.GetDashboard --- pkg/api/annotations.go | 6 +- pkg/api/annotations_test.go | 7 +- pkg/api/common_test.go | 5 +- pkg/api/dashboard.go | 8 +- pkg/api/dashboard_permission_test.go | 3 +- pkg/api/dashboard_test.go | 117 ++++++++++-------- pkg/api/folder_permission_test.go | 2 +- pkg/api/metrics.go | 1 + pkg/api/metrics_test.go | 9 +- pkg/api/preferences.go | 8 +- pkg/api/preferences_test.go | 38 +++--- pkg/api/stars.go | 2 +- pkg/api/team_test.go | 4 - pkg/server/wire.go | 2 +- .../ossaccesscontrol/permissions_services.go | 8 +- .../comments/commentmodel/permissions.go | 16 ++- pkg/services/comments/service.go | 7 +- pkg/services/dashboards/dashboard.go | 2 + .../dashboards/dashboard_service_mock.go | 14 +++ pkg/services/dashboards/database/database.go | 25 ++++ .../database/database_dashboard_test.go | 10 +- pkg/services/dashboards/database_mock.go | 28 ++++- .../{manager => service}/dashboard_service.go | 4 + .../dashboard_service_integration_test.go | 35 +++--- .../dashboard_service_test.go | 0 .../{manager => service}/folder_service.go | 7 +- .../folder_service_test.go | 13 +- .../guardian/accesscontrol_guardian.go | 7 +- .../guardian/accesscontrol_guardian_test.go | 8 +- pkg/services/guardian/guardian_util_test.go | 3 +- pkg/services/guardian/provider.go | 8 +- .../libraryelements/libraryelements_test.go | 6 +- .../librarypanels/librarypanels_test.go | 6 +- pkg/services/live/features/dashboard.go | 12 +- pkg/services/live/live.go | 12 +- pkg/services/ngalert/ngalert.go | 5 +- .../ngalert/schedule/schedule_test.go | 5 +- .../ngalert/schedule/schedule_unit_test.go | 3 +- pkg/services/ngalert/state/manager.go | 32 ++--- pkg/services/ngalert/state/manager_test.go | 7 +- pkg/services/ngalert/tests/util.go | 9 +- pkg/services/provisioning/provisioning.go | 69 ++++++----- pkg/services/sqlstore/dashboard.go | 22 ---- .../sqlstore/dashboard_version_test.go | 29 ++++- pkg/services/sqlstore/mockstore/mockstore.go | 6 - pkg/services/sqlstore/store.go | 1 - pkg/services/thumbs/service.go | 14 ++- 47 files changed, 376 insertions(+), 269 deletions(-) rename pkg/services/dashboards/{manager => service}/dashboard_service.go (98%) rename pkg/services/dashboards/{manager => service}/dashboard_service_integration_test.go (95%) rename pkg/services/dashboards/{manager => service}/dashboard_service_test.go (100%) rename pkg/services/dashboards/{manager => service}/folder_service.go (97%) rename pkg/services/dashboards/{manager => service}/folder_service_test.go (96%) diff --git a/pkg/api/annotations.go b/pkg/api/annotations.go index d697fa3a2aa..492b87af29b 100644 --- a/pkg/api/annotations.go +++ b/pkg/api/annotations.go @@ -53,7 +53,7 @@ func (hs *HTTPServer) GetAnnotations(c *models.ReqContext) response.Response { item.DashboardUID = val } else { query := models.GetDashboardQuery{Id: item.DashboardId, OrgId: c.OrgId} - err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) + err := hs.dashboardService.GetDashboard(c.Req.Context(), &query) if err == nil && query.Result != nil { item.DashboardUID = &query.Result.Uid dashboardCache[item.DashboardId] = &query.Result.Uid @@ -82,7 +82,7 @@ func (hs *HTTPServer) PostAnnotation(c *models.ReqContext) response.Response { // overwrite dashboardId when dashboardUID is not empty if cmd.DashboardUID != "" { query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID} - err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) + err := hs.dashboardService.GetDashboard(c.Req.Context(), &query) if err == nil { cmd.DashboardId = query.Result.Id } @@ -291,7 +291,7 @@ func (hs *HTTPServer) MassDeleteAnnotations(c *models.ReqContext) response.Respo if cmd.DashboardUID != "" { query := models.GetDashboardQuery{OrgId: c.OrgId, Uid: cmd.DashboardUID} - err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) + err := hs.dashboardService.GetDashboard(c.Req.Context(), &query) if err == nil { cmd.DashboardId = query.Result.Id } diff --git a/pkg/api/annotations_test.go b/pkg/api/annotations_test.go index 74f4659c616..f14a97b2319 100644 --- a/pkg/api/annotations_test.go +++ b/pkg/api/annotations_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" @@ -221,10 +222,6 @@ func TestAnnotationsAPIEndpoint(t *testing.T) { role := models.ROLE_ADMIN mock := mockstore.NewSQLStoreMock() - mock.ExpectedDashboard = &models.Dashboard{ - Id: 1, - Uid: "home", - } t.Run("Should be able to do anything", func(t *testing.T) { postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, store, func(sc *scenarioContext) { @@ -327,6 +324,7 @@ func postAnnotationScenario(t *testing.T, desc string, url string, routePattern t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { hs := setupSimpleHTTPServer(nil) hs.SQLStore = store + hs.dashboardService = &dashboards.FakeDashboardService{} sc := setupScenarioContext(t, url) sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { @@ -411,6 +409,7 @@ func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePatte t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { hs := setupSimpleHTTPServer(nil) hs.SQLStore = store + hs.dashboardService = &dashboards.FakeDashboardService{} sc := setupScenarioContext(t, url) sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index 990612ec2b4..8af7c6a2830 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -11,6 +11,8 @@ import ( "path/filepath" "testing" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/infra/fs" @@ -27,7 +29,7 @@ import ( "github.com/grafana/grafana/pkg/services/contexthandler/authproxy" "github.com/grafana/grafana/pkg/services/dashboards" dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/login/loginservice" @@ -41,7 +43,6 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web/webtest" - "github.com/stretchr/testify/require" ) func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) { diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index e08c49b89c4..e5bdbc1f86c 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -151,7 +151,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response { // lookup folder title if dash.FolderId > 0 { query := models.GetDashboardQuery{Id: dash.FolderId, OrgId: c.OrgId} - if err := hs.SQLStore.GetDashboard(c.Req.Context(), &query); err != nil { + if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil { if errors.Is(err, models.ErrFolderNotFound) { return response.Error(404, "Folder not found", err) } @@ -242,7 +242,7 @@ func (hs *HTTPServer) getDashboardHelper(ctx context.Context, orgID int64, id in query = models.GetDashboardQuery{Id: id, OrgId: orgID} } - if err := hs.SQLStore.GetDashboard(ctx, &query); err != nil { + if err := hs.dashboardService.GetDashboard(ctx, &query); err != nil { return nil, response.Error(404, "Dashboard not found", err) } @@ -531,7 +531,7 @@ func (hs *HTTPServer) GetDashboardVersions(c *models.ReqContext) response.Respon OrgId: c.SignedInUser.OrgId, Uid: dashUID, } - if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil { + if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil { return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err) } dashID = q.Result.Id @@ -589,7 +589,7 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons OrgId: c.SignedInUser.OrgId, Uid: dashUID, } - if err := hs.SQLStore.GetDashboard(c.Req.Context(), &q); err != nil { + if err := hs.dashboardService.GetDashboard(c.Req.Context(), &q); err != nil { return response.Error(http.StatusBadRequest, "failed to get dashboard by UID", err) } dashID = q.Result.Id diff --git a/pkg/api/dashboard_permission_test.go b/pkg/api/dashboard_permission_test.go index 2d89109aa49..648e44331b5 100644 --- a/pkg/api/dashboard_permission_test.go +++ b/pkg/api/dashboard_permission_test.go @@ -15,7 +15,7 @@ import ( "github.com/grafana/grafana/pkg/models" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/dashboards" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" @@ -26,6 +26,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) { t.Run("Dashboard permissions test", func(t *testing.T) { settings := setting.NewCfg() dashboardStore := &dashboards.FakeDashboardStore{} + dashboardStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Return(nil) defer dashboardStore.AssertExpectations(t) features := featuremgmt.WithFeatures() diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 95e9ffd24ae..7084a15b404 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -23,7 +23,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" - service "github.com/grafana/grafana/pkg/services/dashboards/manager" + service "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -101,7 +101,7 @@ func newTestLive(t *testing.T, store *sqlstore.SQLStore) *live.GrafanaLive { nil, &usagestats.UsageStatsMock{T: t}, nil, - features, accesscontrolmock.New()) + features, accesscontrolmock.New(), &dashboards.FakeDashboardService{}) require.NoError(t, err) return gLive } @@ -118,18 +118,22 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.Id = 1 fakeDash.FolderId = 1 fakeDash.HasAcl = false + dashboardService := &dashboards.FakeDashboardService{} + dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = fakeDash + return nil + } mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDashboard = fakeDash hs := &HTTPServer{ - Cfg: setting.NewCfg(), - pluginStore: &fakePluginStore{}, - SQLStore: mockSQLStore, - AccessControl: accesscontrolmock.New(), - Features: featuremgmt.WithFeatures(), + Cfg: setting.NewCfg(), + pluginStore: &fakePluginStore{}, + SQLStore: mockSQLStore, + AccessControl: accesscontrolmock.New(), + Features: featuremgmt.WithFeatures(), + dashboardService: dashboardService, } - hs.SQLStore = mockSQLStore setUp := func() { viewerRole := models.ROLE_VIEWER @@ -153,7 +157,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUp() sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanSave) @@ -185,7 +189,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUp() sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanSave) @@ -216,14 +220,16 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.Id = 1 fakeDash.FolderId = 1 fakeDash.HasAcl = true + dashboardService := &dashboards.FakeDashboardService{} + dashboardService.GetDashboardFn = func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = fakeDash + return nil + } mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDashboard = fakeDash - cfg := setting.NewCfg() - features := featuremgmt.WithFeatures() sql := sqlstore.InitTestDB(t) - dashboardStore := database.ProvideDashboardStore(sql) + hs := &HTTPServer{ Cfg: cfg, Live: newTestLive(t, sql), @@ -231,12 +237,8 @@ func TestDashboardAPIEndpoint(t *testing.T) { LibraryElementService: &mockLibraryElementService{}, SQLStore: mockSQLStore, AccessControl: accesscontrolmock.New(), - dashboardService: service.ProvideDashboardService( - cfg, dashboardStore, nil, features, - accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), - ), + dashboardService: dashboardService, } - hs.SQLStore = mockSQLStore setUp := func() { origCanEdit := setting.ViewersCanEdit @@ -281,7 +283,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUp() sc.sqlStore = mockSQLStore - hs.callDeleteDashboardByUID(t, sc, nil) + hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{}) assert.Equal(t, 403, sc.resp.Code) }, mockSQLStore) @@ -319,7 +321,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUp() - hs.callDeleteDashboardByUID(t, sc, nil) + hs.callDeleteDashboardByUID(t, sc, &dashboards.FakeDashboardService{}) assert.Equal(t, 403, sc.resp.Code) }, mockSQLStore) @@ -357,7 +359,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUpInner() sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanSave) @@ -420,7 +422,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { require.True(t, setting.ViewersCanEdit) sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.True(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanSave) @@ -430,7 +432,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUpInner() - hs.callDeleteDashboardByUID(t, sc, nil) + hs.callDeleteDashboardByUID(t, sc, dashboardService) assert.Equal(t, 403, sc.resp.Code) }, mockSQLStore) }) @@ -450,7 +452,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUpInner() sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanSave) @@ -495,7 +497,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUpInner() sc.sqlStore = mockSQLStore - dash := getDashboardShouldReturn200(t, sc) + dash := getDashboardShouldReturn200WithConfig(t, sc, nil, nil, dashboardService) assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanSave) @@ -503,7 +505,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { setUpInner() - hs.callDeleteDashboardByUID(t, sc, nil) + hs.callDeleteDashboardByUID(t, sc, dashboardService) assert.Equal(t, 403, sc.resp.Code) }, mockSQLStore) @@ -780,13 +782,19 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.FolderId = folderID fakeDash.HasAcl = false + saved := &models.Dashboard{ + Id: 2, + Uid: "uid", + Title: "Dash", + Slug: "dash", + Version: 1, + } + mock := &dashboards.FakeDashboardService{ - SaveDashboardResult: &models.Dashboard{ - Id: 2, - Uid: "uid", - Title: "Dash", - Slug: "dash", - Version: 1, + SaveDashboardResult: saved, + GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = fakeDash + return nil }, } @@ -794,7 +802,6 @@ func TestDashboardAPIEndpoint(t *testing.T) { Version: 1, } mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDashboard = fakeDash mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{ { DashboardId: 2, @@ -818,13 +825,19 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.Id = 2 fakeDash.HasAcl = false + saved := &models.Dashboard{ + Id: 2, + Uid: "uid", + Title: "Dash", + Slug: "dash", + Version: 1, + } + mock := &dashboards.FakeDashboardService{ - SaveDashboardResult: &models.Dashboard{ - Id: 2, - Uid: "uid", - Title: "Dash", - Slug: "dash", - Version: 1, + SaveDashboardResult: saved, + GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = fakeDash + return nil }, } @@ -832,7 +845,6 @@ func TestDashboardAPIEndpoint(t *testing.T) { Version: 1, } mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDashboard = fakeDash mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{ { DashboardId: 2, @@ -861,7 +873,12 @@ func TestDashboardAPIEndpoint(t *testing.T) { dataValue, err := simplejson.NewJson([]byte(`{"id": 1, "editable": true, "style": "dark"}`)) require.NoError(t, err) - mockSQLStore.ExpectedDashboard = &models.Dashboard{Id: 1, Data: dataValue} + dashboardService := &dashboards.FakeDashboardService{ + GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = &models.Dashboard{Id: 1, Data: dataValue} + return nil + }, + } loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) { setUp() @@ -875,7 +892,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { dashboardStore.On("GetProvisionedDataByDashboardID", mock.Anything).Return(&models.DashboardProvisioning{ExternalId: "/dashboard1.json"}, nil).Once() - dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore) + dash := getDashboardShouldReturn200WithConfig(t, sc, fakeProvisioningService, dashboardStore, dashboardService) assert.Equal(t, "../../../dashboard1.json", dash.Meta.ProvisionedExternalId, mockSQLStore) }, mockSQLStore) @@ -899,6 +916,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { dashboardProvisioningService: mockDashboardProvisioningService{}, SQLStore: mockSQLStore, AccessControl: accesscontrolmock.New(), + dashboardService: dashboardService, } hs.callGetDashboard(sc) @@ -913,7 +931,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { }) } -func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store) dtos.DashboardFullWithMeta { +func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, provisioningService provisioning.ProvisioningService, dashboardStore dashboards.Store, dashboardService dashboards.DashboardService) dtos.DashboardFullWithMeta { t.Helper() if provisioningService == nil { @@ -925,6 +943,10 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr dashboardStore = database.ProvideDashboardStore(sql) } + if dashboardService == nil { + dashboardService = &dashboards.FakeDashboardService{} + } + libraryPanelsService := mockLibraryPanelService{} libraryElementsService := mockLibraryElementService{} cfg := setting.NewCfg() @@ -941,6 +963,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr cfg, dashboardStore, nil, features, accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), ), + dashboardService: dashboardService, } hs.callGetDashboard(sc) @@ -954,10 +977,6 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr return dash } -func getDashboardShouldReturn200(t *testing.T, sc *scenarioContext) dtos.DashboardFullWithMeta { - return getDashboardShouldReturn200WithConfig(t, sc, nil, nil) -} - func (hs *HTTPServer) callGetDashboard(sc *scenarioContext) { sc.handlerFunc = hs.GetDashboard sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() diff --git a/pkg/api/folder_permission_test.go b/pkg/api/folder_permission_test.go index 4ca3aea5f72..90267c970f1 100644 --- a/pkg/api/folder_permission_test.go +++ b/pkg/api/folder_permission_test.go @@ -15,7 +15,7 @@ import ( "github.com/grafana/grafana/pkg/models" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/dashboards" - service "github.com/grafana/grafana/pkg/services/dashboards/manager" + service "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index aa6a6a8a170..3b6649ba7c8 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/models" diff --git a/pkg/api/metrics_test.go b/pkg/api/metrics_test.go index ce37e0f328c..e61a36fe8ff 100644 --- a/pkg/api/metrics_test.go +++ b/pkg/api/metrics_test.go @@ -7,16 +7,15 @@ import ( "strings" "testing" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/web/webtest" - + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/stretchr/testify/require" "golang.org/x/oauth2" - "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/models" fakeDatasources "github.com/grafana/grafana/pkg/services/datasources/fakes" + "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/query" - "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/web/webtest" ) var queryDatasourceInput = `{ diff --git a/pkg/api/preferences.go b/pkg/api/preferences.go index 1beb04aba0c..483de3408af 100644 --- a/pkg/api/preferences.go +++ b/pkg/api/preferences.go @@ -31,7 +31,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *models.ReqContext) response.Response { dashboardID := cmd.HomeDashboardID if cmd.HomeDashboardUID != nil { query := models.GetDashboardQuery{Uid: *cmd.HomeDashboardUID} - err := hs.SQLStore.GetDashboard(c.Req.Context(), &query) + err := hs.dashboardService.GetDashboard(c.Req.Context(), &query) if err != nil { return response.Error(404, "Dashboard not found", err) } @@ -65,7 +65,7 @@ func (hs *HTTPServer) getPreferencesFor(ctx context.Context, orgID, userID, team // when homedashboardID is 0, that means it is the default home dashboard, no UID would be returned in the response if preference.HomeDashboardID != 0 { query := models.GetDashboardQuery{Id: preference.HomeDashboardID, OrgId: orgID} - err = hs.SQLStore.GetDashboard(ctx, &query) + err = hs.dashboardService.GetDashboard(ctx, &query) if err == nil { dashboardUID = query.Result.Uid } @@ -104,7 +104,7 @@ func (hs *HTTPServer) updatePreferencesFor(ctx context.Context, orgID, userID, t dashboardID := dtoCmd.HomeDashboardID if dtoCmd.HomeDashboardUID != nil { query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID} - err := hs.SQLStore.GetDashboard(ctx, &query) + err := hs.dashboardService.GetDashboard(ctx, &query) if err != nil { return response.Error(404, "Dashboard not found", err) } @@ -147,7 +147,7 @@ func (hs *HTTPServer) patchPreferencesFor(ctx context.Context, orgID, userID, te dashboardID := dtoCmd.HomeDashboardID if dtoCmd.HomeDashboardUID != nil { query := models.GetDashboardQuery{Uid: *dtoCmd.HomeDashboardUID, OrgId: orgID} - err := hs.SQLStore.GetDashboard(ctx, &query) + err := hs.dashboardService.GetDashboard(ctx, &query) if err != nil { return response.Error(404, "Dashboard not found", err) } diff --git a/pkg/api/preferences_test.go b/pkg/api/preferences_test.go index b204bcb83f5..a8178fa385f 100644 --- a/pkg/api/preferences_test.go +++ b/pkg/api/preferences_test.go @@ -1,19 +1,21 @@ package api import ( + "context" "encoding/json" "io/ioutil" "net/http" "strings" "testing" - "github.com/grafana/grafana/pkg/models" - "github.com/grafana/grafana/pkg/services/accesscontrol" - pref "github.com/grafana/grafana/pkg/services/preference" - "github.com/grafana/grafana/pkg/services/preference/preftest" - "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/dashboards" + pref "github.com/grafana/grafana/pkg/services/preference" + "github.com/grafana/grafana/pkg/services/preference/preftest" ) var ( @@ -32,12 +34,13 @@ var ( func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) { sc := setupHTTPServer(t, true, false) - sqlstore := mockstore.NewSQLStoreMock() - sqlstore.ExpectedDashboard = &models.Dashboard{ - Uid: "home", - Id: 1, + dashSvc := &dashboards.FakeDashboardService{ + GetDashboardFn: func(ctx context.Context, cmd *models.GetDashboardQuery) error { + cmd.Result = &models.Dashboard{Uid: "home", Id: 1} + return nil + }, } - sc.hs.SQLStore = sqlstore + sc.hs.dashboardService = dashSvc prefService := preftest.NewPreferenceServiceFake() prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"} @@ -68,13 +71,6 @@ func TestAPIEndpoint_GetCurrentOrgPreferences_AccessControl(t *testing.T) { sc := setupHTTPServer(t, true, true) setInitCtxSignedInViewer(sc.initCtx) - sqlstore := mockstore.NewSQLStoreMock() - sqlstore.ExpectedDashboard = &models.Dashboard{ - Uid: "home", - Id: 1, - } - sc.hs.SQLStore = sqlstore - prefService := preftest.NewPreferenceServiceFake() prefService.ExpectedPreference = &pref.Preference{HomeDashboardID: 1, Theme: "dark"} sc.hs.preferenceService = prefService @@ -168,12 +164,8 @@ func TestAPIEndpoint_PatchUserPreferences(t *testing.T) { assert.Equal(t, http.StatusBadRequest, response.Code) }) input = strings.NewReader(testUpdateOrgPreferencesWithHomeDashboardUIDCmd) - sqlstore := mockstore.NewSQLStoreMock() - sqlstore.ExpectedDashboard = &models.Dashboard{ - Uid: "home", - Id: 1, - } - sc.hs.SQLStore = sqlstore + dashSvc := &dashboards.FakeDashboardService{} + sc.hs.dashboardService = dashSvc t.Run("Returns 200 on success", func(t *testing.T) { response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t) assert.Equal(t, http.StatusOK, response.Code) diff --git a/pkg/api/stars.go b/pkg/api/stars.go index fde1af2d4ab..80868c31de7 100644 --- a/pkg/api/stars.go +++ b/pkg/api/stars.go @@ -26,7 +26,7 @@ func (hs *HTTPServer) GetStars(c *models.ReqContext) response.Response { Id: dashboardId, OrgId: c.OrgId, } - err := hs.SQLStore.GetDashboard(c.Req.Context(), query) + err := hs.dashboardService.GetDashboard(c.Req.Context(), query) if err != nil { return response.Error(500, "Failed to get dashboard", err) } diff --git a/pkg/api/team_test.go b/pkg/api/team_test.go index dd4c463d858..d4f31b37635 100644 --- a/pkg/api/team_test.go +++ b/pkg/api/team_test.go @@ -369,10 +369,6 @@ func TestTeamAPIEndpoint_GetTeamPreferences_RBAC(t *testing.T) { _, err := sc.db.CreateTeam("team1", "", 1) sqlstore := mockstore.NewSQLStoreMock() - sqlstore.ExpectedDashboard = &models.Dashboard{ - Uid: "home", - Id: 1, - } sc.hs.SQLStore = sqlstore prefService := preftest.NewPreferenceServiceFake() diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 0fbb0d19949..f3b2db696bd 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -46,7 +46,7 @@ import ( dashboardimportservice "github.com/grafana/grafana/pkg/services/dashboardimport/service" "github.com/grafana/grafana/pkg/services/dashboards" dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/dashboardsnapshots" "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" diff --git a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go index 6bfecbee92f..65f4621bb7f 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/permissions_services.go @@ -109,10 +109,11 @@ var DashboardAdminActions = append(DashboardEditActions, []string{dashboards.Act func ProvideDashboardPermissions( cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, ac accesscontrol.AccessControl, store resourcepermissions.Store, + dashboardStore dashboards.Store, ) (*DashboardPermissionsService, error) { getDashboard := func(ctx context.Context, orgID int64, resourceID string) (*models.Dashboard, error) { query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID} - if err := sql.GetDashboard(ctx, query); err != nil { + if err := dashboardStore.GetDashboard(ctx, query); err != nil { return nil, err } return query.Result, nil @@ -141,7 +142,7 @@ func ProvideDashboardPermissions( } if dashboard.FolderId > 0 { query := &models.GetDashboardQuery{Id: dashboard.FolderId, OrgId: orgID} - if err := sql.GetDashboard(ctx, query); err != nil { + if err := dashboardStore.GetDashboard(ctx, query); err != nil { return nil, err } return []string{dashboards.ScopeFoldersProvider.GetResourceScopeUID(query.Result.Uid)}, nil @@ -181,13 +182,14 @@ var FolderAdminActions = append(FolderEditActions, []string{dashboards.ActionFol func ProvideFolderPermissions( cfg *setting.Cfg, router routing.RouteRegister, sql *sqlstore.SQLStore, accesscontrol accesscontrol.AccessControl, store resourcepermissions.Store, + dashboardStore dashboards.Store, ) (*FolderPermissionsService, error) { options := resourcepermissions.Options{ Resource: "folders", ResourceAttribute: "uid", ResourceValidator: func(ctx context.Context, orgID int64, resourceID string) error { query := &models.GetDashboardQuery{Uid: resourceID, OrgId: orgID} - if err := sql.GetDashboard(ctx, query); err != nil { + if err := dashboardStore.GetDashboard(ctx, query); err != nil { return err } diff --git a/pkg/services/comments/commentmodel/permissions.go b/pkg/services/comments/commentmodel/permissions.go index 33c17b3eca4..8b0ea7af4b0 100644 --- a/pkg/services/comments/commentmodel/permissions.go +++ b/pkg/services/comments/commentmodel/permissions.go @@ -7,24 +7,28 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" ) type PermissionChecker struct { - sqlStore *sqlstore.SQLStore - features featuremgmt.FeatureToggles - accessControl accesscontrol.AccessControl + sqlStore *sqlstore.SQLStore + features featuremgmt.FeatureToggles + accessControl accesscontrol.AccessControl + dashboardService dashboards.DashboardService } -func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *PermissionChecker { +func NewPermissionChecker(sqlStore *sqlstore.SQLStore, features featuremgmt.FeatureToggles, + accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService, +) *PermissionChecker { return &PermissionChecker{sqlStore: sqlStore, features: features, accessControl: accessControl} } func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64, uid string) (*models.Dashboard, error) { query := models.GetDashboardQuery{Uid: uid, OrgId: orgID} - if err := c.sqlStore.GetDashboard(ctx, &query); err != nil { + if err := c.dashboardService.GetDashboard(ctx, &query); err != nil { return nil, err } return query.Result, nil @@ -32,7 +36,7 @@ func (c *PermissionChecker) getDashboardByUid(ctx context.Context, orgID int64, func (c *PermissionChecker) getDashboardById(ctx context.Context, orgID int64, id int64) (*models.Dashboard, error) { query := models.GetDashboardQuery{Id: id, OrgId: orgID} - if err := c.sqlStore.GetDashboard(ctx, &query); err != nil { + if err := c.dashboardService.GetDashboard(ctx, &query); err != nil { return nil, err } return query.Result, nil diff --git a/pkg/services/comments/service.go b/pkg/services/comments/service.go index a899af106ef..085da02c120 100644 --- a/pkg/services/comments/service.go +++ b/pkg/services/comments/service.go @@ -5,6 +5,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/comments/commentmodel" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/live" "github.com/grafana/grafana/pkg/services/sqlstore" @@ -19,7 +20,9 @@ type Service struct { permissions *commentmodel.PermissionChecker } -func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive, features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl) *Service { +func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.GrafanaLive, + features featuremgmt.FeatureToggles, accessControl accesscontrol.AccessControl, + dashboardService dashboards.DashboardService) *Service { s := &Service{ cfg: cfg, live: live, @@ -27,7 +30,7 @@ func ProvideService(cfg *setting.Cfg, store *sqlstore.SQLStore, live *live.Grafa storage: &sqlStorage{ sql: store, }, - permissions: commentmodel.NewPermissionChecker(store, features, accessControl), + permissions: commentmodel.NewPermissionChecker(store, features, accessControl, dashboardService), } return s } diff --git a/pkg/services/dashboards/dashboard.go b/pkg/services/dashboards/dashboard.go index 93716c52713..24c07ddcdd2 100644 --- a/pkg/services/dashboards/dashboard.go +++ b/pkg/services/dashboards/dashboard.go @@ -14,6 +14,7 @@ type DashboardService interface { MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error BuildSaveDashboardCommand(ctx context.Context, dto *SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*models.SaveDashboardCommand, error) UpdateDashboardACL(ctx context.Context, uid int64, items []*models.DashboardAcl) error + GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error } // PluginService is a service for operating on plugin dashboards. @@ -51,6 +52,7 @@ type Store interface { UnprovisionDashboard(ctx context.Context, id int64) error // GetDashboardsByPluginID retrieves dashboards identified by plugin. GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error + GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error FolderStore } diff --git a/pkg/services/dashboards/dashboard_service_mock.go b/pkg/services/dashboards/dashboard_service_mock.go index 307641e981e..1975a16bba5 100644 --- a/pkg/services/dashboards/dashboard_service_mock.go +++ b/pkg/services/dashboards/dashboard_service_mock.go @@ -13,6 +13,8 @@ type FakeDashboardService struct { SaveDashboardError error SavedDashboards []*SaveDashboardDTO ProvisionedDashData *models.DashboardProvisioning + + GetDashboardFn func(ctx context.Context, cmd *models.GetDashboardQuery) error } func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) { @@ -45,3 +47,15 @@ func (s *FakeDashboardService) GetProvisionedDashboardDataByDashboardID(id int64 func (s *FakeDashboardService) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error { return nil } + +func (s *FakeDashboardService) GetDashboard(ctx context.Context, cmd *models.GetDashboardQuery) error { + if s.GetDashboardFn != nil { + return s.GetDashboardFn(ctx, cmd) + } + // A minimal result for tests that need a valid result, but don't care what's in it. + d := models.NewDashboard("mocked") + d.Id = 1 + d.Uid = "1" + cmd.Result = d + return nil +} diff --git a/pkg/services/dashboards/database/database.go b/pkg/services/dashboards/database/database.go index 2935e536a83..456ae79b2d6 100644 --- a/pkg/services/dashboards/database/database.go +++ b/pkg/services/dashboards/database/database.go @@ -21,6 +21,9 @@ type DashboardStore struct { log log.Logger } +// DashboardStore implements the Store interface +var _ dashboards.Store = (*DashboardStore)(nil) + func ProvideDashboardStore(sqlStore *sqlstore.SQLStore) *DashboardStore { return &DashboardStore{sqlStore: sqlStore, log: log.New("dashboard-store")} } @@ -823,3 +826,25 @@ func (d *DashboardStore) deleteAlertDefinition(dashboardId int64, sess *sqlstore return nil } + +func (d *DashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error { + return d.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 { + return models.ErrDashboardIdentifierNotSet + } + + dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid} + has, err := sess.Get(&dashboard) + + if err != nil { + return err + } else if !has { + return models.ErrDashboardNotFound + } + + dashboard.SetId(dashboard.Id) + dashboard.SetUid(dashboard.Uid) + query.Result = &dashboard + return nil + }) +} diff --git a/pkg/services/dashboards/database/database_dashboard_test.go b/pkg/services/dashboards/database/database_dashboard_test.go index 86462ab9546..28c69b3288a 100644 --- a/pkg/services/dashboards/database/database_dashboard_test.go +++ b/pkg/services/dashboards/database/database_dashboard_test.go @@ -61,7 +61,7 @@ func TestDashboardDataAccess(t *testing.T) { OrgId: 1, } - err := sqlStore.GetDashboard(context.Background(), &query) + err := dashboardStore.GetDashboard(context.Background(), &query) require.NoError(t, err) require.Equal(t, query.Result.Title, "test dash 23") @@ -78,7 +78,7 @@ func TestDashboardDataAccess(t *testing.T) { OrgId: 1, } - err := sqlStore.GetDashboard(context.Background(), &query) + err := dashboardStore.GetDashboard(context.Background(), &query) require.NoError(t, err) require.Equal(t, query.Result.Title, "test dash 23") @@ -95,7 +95,7 @@ func TestDashboardDataAccess(t *testing.T) { OrgId: 1, } - err := sqlStore.GetDashboard(context.Background(), &query) + err := dashboardStore.GetDashboard(context.Background(), &query) require.NoError(t, err) require.Equal(t, query.Result.Title, "test dash 23") @@ -111,7 +111,7 @@ func TestDashboardDataAccess(t *testing.T) { OrgId: 1, } - err := sqlStore.GetDashboard(context.Background(), &query) + err := dashboardStore.GetDashboard(context.Background(), &query) require.Equal(t, err, models.ErrDashboardIdentifierNotSet) }) @@ -180,7 +180,7 @@ func TestDashboardDataAccess(t *testing.T) { OrgId: 1, } - err = sqlStore.GetDashboard(context.Background(), &query) + err = dashboardStore.GetDashboard(context.Background(), &query) require.NoError(t, err) require.Equal(t, query.Result.FolderId, int64(0)) require.Equal(t, query.Result.CreatedBy, savedDash.CreatedBy) diff --git a/pkg/services/dashboards/database_mock.go b/pkg/services/dashboards/database_mock.go index 5e5e3d53d1b..7402570ed14 100644 --- a/pkg/services/dashboards/database_mock.go +++ b/pkg/services/dashboards/database_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.12.2. DO NOT EDIT. package dashboards @@ -7,6 +7,8 @@ import ( models "github.com/grafana/grafana/pkg/models" mock "github.com/stretchr/testify/mock" + + testing "testing" ) // FakeDashboardStore is an autogenerated mock type for the Store type @@ -42,6 +44,20 @@ func (_m *FakeDashboardStore) DeleteOrphanedProvisionedDashboards(ctx context.Co return r0 } +// GetDashboard provides a mock function with given fields: ctx, query +func (_m *FakeDashboardStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error { + ret := _m.Called(ctx, query) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, *models.GetDashboardQuery) error); ok { + r0 = rf(ctx, query) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // GetDashboardsByPluginID provides a mock function with given fields: ctx, query func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *models.GetDashboardsByPluginIdQuery) error { ret := _m.Called(ctx, query) @@ -302,3 +318,13 @@ func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(dashboard *models.Dash return r0, r1 } + +// NewFakeDashboardStore creates a new instance of FakeDashboardStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations. +func NewFakeDashboardStore(t testing.TB) *FakeDashboardStore { + mock := &FakeDashboardStore{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/services/dashboards/manager/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go similarity index 98% rename from pkg/services/dashboards/manager/dashboard_service.go rename to pkg/services/dashboards/service/dashboard_service.go index 619b4b909df..7dd281a9f80 100644 --- a/pkg/services/dashboards/manager/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -481,3 +481,7 @@ func (dr *DashboardServiceImpl) setDefaultPermissions(ctx context.Context, dto * return nil } + +func (dr *DashboardServiceImpl) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error { + return dr.dashboardStore.GetDashboard(ctx, query) +} diff --git a/pkg/services/dashboards/manager/dashboard_service_integration_test.go b/pkg/services/dashboards/service/dashboard_service_integration_test.go similarity index 95% rename from pkg/services/dashboards/manager/dashboard_service_integration_test.go rename to pkg/services/dashboards/service/dashboard_service_integration_test.go index 3fc3662bd48..4f4b651ab0b 100644 --- a/pkg/services/dashboards/manager/dashboard_service_integration_test.go +++ b/pkg/services/dashboards/service/dashboard_service_integration_test.go @@ -7,18 +7,20 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" "github.com/grafana/grafana/pkg/services/alerting" + "github.com/grafana/grafana/pkg/services/dashboards" dashbboardservice "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const testOrgID int64 = 1 @@ -76,7 +78,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ OrgId: otherOrgId, Uid: sc.savedDashInFolder.Uid, }) @@ -316,7 +318,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -341,7 +343,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -366,7 +368,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id) assert.True(t, res.IsFolder) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -388,7 +390,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.Greater(t, res.Id, int64(0)) assert.NotEmpty(t, res.Uid) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -409,7 +411,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -463,7 +465,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: sc.savedDashInGeneralFolder.Id, OrgId: cmd.OrgId, }) @@ -503,7 +505,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: sc.savedDashInFolder.Id, OrgId: cmd.OrgId, }) @@ -577,7 +579,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: sc.savedDashInGeneralFolder.Id, OrgId: cmd.OrgId, }) @@ -599,7 +601,7 @@ func TestIntegratedDashboardService(t *testing.T) { res := callSaveWithResult(t, cmd, sc.sqlStore) require.NotNil(t, res) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: sc.savedDashInFolder.Id, OrgId: cmd.OrgId, }) @@ -623,7 +625,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.Equal(t, sc.savedDashInFolder.Id, res.Id) assert.Equal(t, "new-uid", res.Uid) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: sc.savedDashInFolder.Id, OrgId: cmd.OrgId, }) @@ -663,7 +665,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.Equal(t, sc.savedDashInFolder.Id, res.Id) assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -687,7 +689,7 @@ func TestIntegratedDashboardService(t *testing.T) { assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id) assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid) - err := sc.sqlStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ + err := sc.dashboardStore.GetDashboard(context.Background(), &models.GetDashboardQuery{ Id: res.Id, OrgId: cmd.OrgId, }) @@ -795,6 +797,7 @@ func TestIntegratedDashboardService(t *testing.T) { type permissionScenarioContext struct { dashboardGuardianMock *guardian.FakeDashboardGuardian sqlStore *sqlstore.SQLStore + dashboardStore dashboards.Store savedFolder *models.Dashboard savedDashInFolder *models.Dashboard otherSavedFolder *models.Dashboard @@ -813,6 +816,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc t.Run(desc, func(t *testing.T) { sqlStore := sqlstore.InitTestDB(t) guardian.InitLegacyGuardian(sqlStore) + dashboardStore := database.ProvideDashboardStore(sqlStore) savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore) savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore) @@ -847,6 +851,7 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc otherSavedFolder: otherSavedFolder, savedDashInGeneralFolder: savedDashInGeneralFolder, savedFolder: savedFolder, + dashboardStore: dashboardStore, } fn(t, sc) diff --git a/pkg/services/dashboards/manager/dashboard_service_test.go b/pkg/services/dashboards/service/dashboard_service_test.go similarity index 100% rename from pkg/services/dashboards/manager/dashboard_service_test.go rename to pkg/services/dashboards/service/dashboard_service_test.go diff --git a/pkg/services/dashboards/manager/folder_service.go b/pkg/services/dashboards/service/folder_service.go similarity index 97% rename from pkg/services/dashboards/manager/folder_service.go rename to pkg/services/dashboards/service/folder_service.go index 3e517d3bf73..44f21d30d14 100644 --- a/pkg/services/dashboards/manager/folder_service.go +++ b/pkg/services/dashboards/service/folder_service.go @@ -12,7 +12,6 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/search" - "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" ) @@ -24,13 +23,12 @@ type FolderServiceImpl struct { searchService *search.SearchService features featuremgmt.FeatureToggles permissions accesscontrol.FolderPermissionsService - sqlStore sqlstore.Store } func ProvideFolderService( cfg *setting.Cfg, dashboardService dashboards.DashboardService, dashboardStore dashboards.Store, searchService *search.SearchService, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService, - ac accesscontrol.AccessControl, sqlStore sqlstore.Store, + ac accesscontrol.AccessControl, ) *FolderServiceImpl { ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore)) @@ -43,7 +41,6 @@ func ProvideFolderService( searchService: searchService, features: features, permissions: folderPermissionsService, - sqlStore: sqlStore, } } @@ -190,7 +187,7 @@ func (f *FolderServiceImpl) CreateFolder(ctx context.Context, user *models.Signe func (f *FolderServiceImpl) UpdateFolder(ctx context.Context, user *models.SignedInUser, orgID int64, existingUid string, cmd *models.UpdateFolderCommand) error { query := models.GetDashboardQuery{OrgId: orgID, Uid: existingUid} - if err := f.sqlStore.GetDashboard(ctx, &query); err != nil { + if err := f.dashboardStore.GetDashboard(ctx, &query); err != nil { return toFolderError(err) } diff --git a/pkg/services/dashboards/manager/folder_service_test.go b/pkg/services/dashboards/service/folder_service_test.go similarity index 96% rename from pkg/services/dashboards/manager/folder_service_test.go rename to pkg/services/dashboards/service/folder_service_test.go index a65c488df29..aa025444a7e 100644 --- a/pkg/services/dashboards/manager/folder_service_test.go +++ b/pkg/services/dashboards/service/folder_service_test.go @@ -18,7 +18,6 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" - "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" ) @@ -39,7 +38,7 @@ func TestProvideFolderService(t *testing.T) { ProvideFolderService( cfg, &dashboards.FakeDashboardService{DashboardService: dashboardService}, - store, nil, features, folderPermissions, ac, mockstore.NewSQLStoreMock(), + store, nil, features, folderPermissions, ac, ) require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 2) @@ -55,7 +54,6 @@ func TestFolderService(t *testing.T) { folderPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService() dashboardService := ProvideDashboardService(cfg, store, nil, features, folderPermissions, dashboardPermissions) - mockStore := mockstore.NewSQLStoreMock() service := FolderServiceImpl{ cfg: cfg, @@ -65,7 +63,6 @@ func TestFolderService(t *testing.T) { searchService: nil, features: features, permissions: folderPermissions, - sqlStore: mockStore, } t.Run("Given user has no permissions", func(t *testing.T) { @@ -105,7 +102,11 @@ func TestFolderService(t *testing.T) { }) t.Run("When updating folder should return access denied error", func(t *testing.T) { - mockStore.ExpectedDashboard = models.NewDashboardFolder("Folder") + store.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) { + folder := args.Get(1).(*models.GetDashboardQuery) + folder.Result = models.NewDashboard("dashboard-test") + folder.Result.IsFolder = true + }).Return(nil) err := service.UpdateFolder(context.Background(), user, orgID, folderUID, &models.UpdateFolderCommand{ Uid: folderUID, Title: "Folder-TEST", @@ -156,8 +157,6 @@ func TestFolderService(t *testing.T) { dashboardFolder.Uid = util.GenerateShortUID() f := models.DashboardToFolder(dashboardFolder) - mockStore.ExpectedDashboard = dashboardFolder - store.On("ValidateDashboardBeforeSave", mock.Anything, mock.Anything).Return(true, nil) store.On("SaveDashboard", mock.Anything).Return(dashboardFolder, nil) store.On("GetFolderByID", mock.Anything, orgID, dashboardFolder.Id).Return(f, nil) diff --git a/pkg/services/guardian/accesscontrol_guardian.go b/pkg/services/guardian/accesscontrol_guardian.go index 6c2b7f2b046..7b455ef9b18 100644 --- a/pkg/services/guardian/accesscontrol_guardian.go +++ b/pkg/services/guardian/accesscontrol_guardian.go @@ -25,6 +25,7 @@ func NewAccessControlDashboardGuardian( store sqlstore.Store, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, + dashboardService dashboards.DashboardService, ) *AccessControlDashboardGuardian { return &AccessControlDashboardGuardian{ ctx: ctx, @@ -35,6 +36,7 @@ func NewAccessControlDashboardGuardian( ac: ac, folderPermissionsService: folderPermissionsService, dashboardPermissionsService: dashboardPermissionsService, + dashboardService: dashboardService, } } @@ -49,6 +51,7 @@ type AccessControlDashboardGuardian struct { ac accesscontrol.AccessControl folderPermissionsService accesscontrol.FolderPermissionsService dashboardPermissionsService accesscontrol.DashboardPermissionsService + dashboardService dashboards.DashboardService } func (a *AccessControlDashboardGuardian) CanSave() (bool, error) { @@ -264,7 +267,7 @@ func (a *AccessControlDashboardGuardian) GetHiddenACL(cfg *setting.Cfg) ([]*mode func (a *AccessControlDashboardGuardian) loadDashboard() error { if a.dashboard == nil { query := &models.GetDashboardQuery{Id: a.dashboardID, OrgId: a.user.OrgId} - if err := a.store.GetDashboard(a.ctx, query); err != nil { + if err := a.dashboardService.GetDashboard(a.ctx, query); err != nil { return err } if !query.Result.IsFolder { @@ -284,7 +287,7 @@ func (a *AccessControlDashboardGuardian) loadParentFolder(folderID int64) (*mode return &models.Dashboard{Uid: accesscontrol.GeneralFolderUID}, nil } folderQuery := &models.GetDashboardQuery{Id: folderID, OrgId: a.user.OrgId} - if err := a.store.GetDashboard(a.ctx, folderQuery); err != nil { + if err := a.dashboardService.GetDashboard(a.ctx, folderQuery); err != nil { return nil, err } return folderQuery.Result, nil diff --git a/pkg/services/guardian/accesscontrol_guardian_test.go b/pkg/services/guardian/accesscontrol_guardian_test.go index ef0ffadba26..cd07d18a44b 100644 --- a/pkg/services/guardian/accesscontrol_guardian_test.go +++ b/pkg/services/guardian/accesscontrol_guardian_test.go @@ -595,10 +595,12 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []*acc }) require.NoError(t, err) ac := accesscontrolmock.New().WithPermissions(permissions) - folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store)) + folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions( + setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{}) require.NoError(t, err) - dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store)) + dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions( + setting.NewCfg(), routing.NewRouteRegister(), store, ac, database.ProvideService(store), &dashboards.FakeDashboardStore{}) require.NoError(t, err) - return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions), dash + return NewAccessControlDashboardGuardian(context.Background(), dash.Id, &models.SignedInUser{OrgId: 1}, store, ac, folderPermissions, dashboardPermissions, &dashboards.FakeDashboardService{}), dash } diff --git a/pkg/services/guardian/guardian_util_test.go b/pkg/services/guardian/guardian_util_test.go index 8ff76b40c06..de8717ac134 100644 --- a/pkg/services/guardian/guardian_util_test.go +++ b/pkg/services/guardian/guardian_util_test.go @@ -7,9 +7,10 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" - "github.com/stretchr/testify/assert" ) type scenarioContext struct { diff --git a/pkg/services/guardian/provider.go b/pkg/services/guardian/provider.go index f026e923b4b..935a8362821 100644 --- a/pkg/services/guardian/provider.go +++ b/pkg/services/guardian/provider.go @@ -5,6 +5,7 @@ import ( "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/sqlstore" ) @@ -13,10 +14,11 @@ type Provider struct{} func ProvideService( store *sqlstore.SQLStore, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService, dashboardPermissionsService accesscontrol.DashboardPermissionsService, + dashboardService dashboards.DashboardService, ) *Provider { if !ac.IsDisabled() { // TODO: Fix this hack, see https://github.com/grafana/grafana-enterprise/issues/2935 - InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService) + InitAccessControlGuardian(store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService) } else { InitLegacyGuardian(store) } @@ -31,9 +33,9 @@ func InitLegacyGuardian(store sqlstore.Store) { func InitAccessControlGuardian( store sqlstore.Store, ac accesscontrol.AccessControl, folderPermissionsService accesscontrol.FolderPermissionsService, - dashboardPermissionsService accesscontrol.DashboardPermissionsService, + dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardService dashboards.DashboardService, ) { New = func(ctx context.Context, dashId int64, orgId int64, user *models.SignedInUser) DashboardGuardian { - return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService) + return NewAccessControlDashboardGuardian(ctx, dashId, user, store, ac, folderPermissionsService, dashboardPermissionsService, dashboardService) } } diff --git a/pkg/services/libraryelements/libraryelements_test.go b/pkg/services/libraryelements/libraryelements_test.go index be150681140..741767997be 100644 --- a/pkg/services/libraryelements/libraryelements_test.go +++ b/pkg/services/libraryelements/libraryelements_test.go @@ -19,7 +19,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" @@ -235,7 +235,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string ac := acmock.New() s := dashboardservice.ProvideFolderService( cfg, d, dashboardStore, nil, - features, folderPermissions, ac, nil, + features, folderPermissions, ac, ) t.Logf("Creating folder with title and UID %q", title) folder, err := s.CreateFolder(context.Background(), &user, user.OrgId, title, title) @@ -340,7 +340,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo SQLStore: sqlStore, folderService: dashboardservice.ProvideFolderService( cfg, dashboardService, dashboardStore, nil, - features, folderPermissions, ac, nil, + features, folderPermissions, ac, ), } diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index f87fe357ceb..d2a66ce69ac 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -17,7 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -1392,7 +1392,7 @@ func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string dashboardPermissions := acmock.NewMockedPermissionsService() dashboardStore := database.ProvideDashboardStore(sqlStore) d := dashboardservice.ProvideDashboardService(cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions) - s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac, nil) + s := dashboardservice.ProvideFolderService(cfg, d, dashboardStore, nil, features, folderPermissions, ac) t.Logf("Creating folder with title and UID %q", title) folder, err := s.CreateFolder(context.Background(), user, user.OrgId, title, title) @@ -1496,7 +1496,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo folderService := dashboardservice.ProvideFolderService( cfg, dashboardService, dashboardStore, nil, - features, folderPermissions, ac, nil, + features, folderPermissions, ac, ) elementService := libraryelements.ProvideService(cfg, sqlStore, routing.NewRouteRegister(), folderService) diff --git a/pkg/services/live/features/dashboard.go b/pkg/services/live/features/dashboard.go index 7a2d76b384d..2b7af053507 100644 --- a/pkg/services/live/features/dashboard.go +++ b/pkg/services/live/features/dashboard.go @@ -9,6 +9,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/sqlstore" ) @@ -37,9 +38,10 @@ type dashboardEvent struct { // DashboardHandler manages all the `grafana/dashboard/*` channels type DashboardHandler struct { - Publisher models.ChannelPublisher - ClientCount models.ChannelClientCount - Store sqlstore.Store + Publisher models.ChannelPublisher + ClientCount models.ChannelClientCount + Store sqlstore.Store + DashboardService dashboards.DashboardService } // GetHandlerForPath called on init @@ -63,7 +65,7 @@ func (h *DashboardHandler) OnSubscribe(ctx context.Context, user *models.SignedI // make sure can view this dashboard if len(parts) == 2 && parts[0] == "uid" { query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId} - if err := h.Store.GetDashboard(ctx, &query); err != nil { + if err := h.DashboardService.GetDashboard(ctx, &query); err != nil { logger.Error("Error getting dashboard", "query", query, "error", err) return models.SubscribeReply{}, backend.SubscribeStreamStatusNotFound, nil } @@ -110,7 +112,7 @@ func (h *DashboardHandler) OnPublish(ctx context.Context, user *models.SignedInU return models.PublishReply{}, backend.PublishStreamStatusNotFound, fmt.Errorf("ignore???") } query := models.GetDashboardQuery{Uid: parts[1], OrgId: user.OrgId} - if err := h.Store.GetDashboard(ctx, &query); err != nil { + if err := h.DashboardService.GetDashboard(ctx, &query); err != nil { logger.Error("Unknown dashboard", "query", query) return models.PublishReply{}, backend.PublishStreamStatusNotFound, nil } diff --git a/pkg/services/live/live.go b/pkg/services/live/live.go index 21bce2f69ee..321f701b775 100644 --- a/pkg/services/live/live.go +++ b/pkg/services/live/live.go @@ -26,6 +26,7 @@ import ( "github.com/grafana/grafana/pkg/plugins/plugincontext" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/comments/commentmodel" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/live/database" @@ -71,7 +72,7 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r pluginStore plugins.Store, cacheService *localcache.CacheService, dataSourceCache datasources.CacheService, sqlStore *sqlstore.SQLStore, secretsService secrets.Service, usageStatsService usagestats.Service, queryDataService *query.Service, toggles featuremgmt.FeatureToggles, - accessControl accesscontrol.AccessControl) (*GrafanaLive, error) { + accessControl accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*GrafanaLive, error) { g := &GrafanaLive{ Cfg: cfg, Features: toggles, @@ -234,15 +235,16 @@ func ProvideService(plugCtxProvider *plugincontext.Provider, cfg *setting.Cfg, r // Initialize the main features dash := &features.DashboardHandler{ - Publisher: g.Publish, - ClientCount: g.ClientCount, - Store: sqlStore, + Publisher: g.Publish, + ClientCount: g.ClientCount, + Store: sqlStore, + DashboardService: dashboardService, } g.storage = database.NewStorage(g.SQLStore, g.CacheService) g.GrafanaScope.Dashboards = dash g.GrafanaScope.Features["dashboard"] = dash g.GrafanaScope.Features["broadcast"] = features.NewBroadcastRunner(g.storage) - g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl)) + g.GrafanaScope.Features["comment"] = features.NewCommentHandler(commentmodel.NewPermissionChecker(g.SQLStore, g.Features, accessControl, dashboardService)) g.surveyCaller = survey.NewCaller(managedStreamRunner, node) err = g.surveyCaller.SetupHandlers() diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index dcb38a17ced..92206205810 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -33,7 +33,7 @@ import ( func ProvideService(cfg *setting.Cfg, dataSourceCache datasources.CacheService, routeRegister routing.RouteRegister, sqlStore *sqlstore.SQLStore, kvStore kvstore.KVStore, expressionService *expr.Service, dataProxy *datasourceproxy.DataSourceProxyService, quotaService *quota.QuotaService, secretsService secrets.Service, notificationService notifications.Service, m *metrics.NGAlert, - folderService dashboards.FolderService, ac accesscontrol.AccessControl) (*AlertNG, error) { + folderService dashboards.FolderService, ac accesscontrol.AccessControl, dashboardService dashboards.DashboardService) (*AlertNG, error) { ng := &AlertNG{ Cfg: cfg, DataSourceCache: dataSourceCache, @@ -79,6 +79,7 @@ type AlertNG struct { schedule schedule.ScheduleService stateManager *state.Manager folderService dashboards.FolderService + dashboardService dashboards.DashboardService // Alerting notification services MultiOrgAlertmanager *notifier.MultiOrgAlertmanager @@ -131,7 +132,7 @@ func (ng *AlertNG) init() error { ng.Log.Error("Failed to parse application URL. Continue without it.", "error", err) appUrl = nil } - stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore) + stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.SQLStore, ng.dashboardService) scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager) ng.stateManager = stateManager diff --git a/pkg/services/ngalert/schedule/schedule_test.go b/pkg/services/ngalert/schedule/schedule_test.go index e8b754e56b0..a9e5be41f55 100644 --- a/pkg/services/ngalert/schedule/schedule_test.go +++ b/pkg/services/ngalert/schedule/schedule_test.go @@ -12,6 +12,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -106,7 +107,7 @@ func TestWarmStateCache(t *testing.T) { Metrics: testMetrics.GetSchedulerMetrics(), AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. } - st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore) + st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{}) st.Warm(ctx) t.Run("instance cache has expected entries", func(t *testing.T) { @@ -158,7 +159,7 @@ func TestAlertingTicker(t *testing.T) { disabledOrgID: {}, }, } - st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore) + st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, ng.SQLStore, &dashboards.FakeDashboardService{}) appUrl := &url.URL{ Scheme: "http", Host: "localhost", diff --git a/pkg/services/ngalert/schedule/schedule_unit_test.go b/pkg/services/ngalert/schedule/schedule_unit_test.go index 5935921a9d0..86754392a06 100644 --- a/pkg/services/ngalert/schedule/schedule_unit_test.go +++ b/pkg/services/ngalert/schedule/schedule_unit_test.go @@ -21,6 +21,7 @@ import ( "github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -925,7 +926,7 @@ func setupScheduler(t *testing.T, rs store.RuleStore, is store.InstanceStore, ac Metrics: m.GetSchedulerMetrics(), AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. } - st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock()) + st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, mockstore.NewSQLStoreMock(), &dashboards.FakeDashboardService{}) appUrl := &url.URL{ Scheme: "http", Host: "localhost", diff --git a/pkg/services/ngalert/state/manager.go b/pkg/services/ngalert/state/manager.go index 5deb39d2555..863abd67901 100644 --- a/pkg/services/ngalert/state/manager.go +++ b/pkg/services/ngalert/state/manager.go @@ -13,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/metrics" ngModels "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -36,22 +37,25 @@ type Manager struct { quit chan struct{} ResendDelay time.Duration - ruleStore store.RuleStore - instanceStore store.InstanceStore - sqlStore sqlstore.Store + ruleStore store.RuleStore + instanceStore store.InstanceStore + sqlStore sqlstore.Store + dashboardService dashboards.DashboardService } -func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL, ruleStore store.RuleStore, - instanceStore store.InstanceStore, sqlStore sqlstore.Store) *Manager { +func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL, + ruleStore store.RuleStore, instanceStore store.InstanceStore, sqlStore sqlstore.Store, + dashboardService dashboards.DashboardService) *Manager { manager := &Manager{ - cache: newCache(logger, metrics, externalURL), - quit: make(chan struct{}), - ResendDelay: ResendDelay, // TODO: make this configurable - log: logger, - metrics: metrics, - ruleStore: ruleStore, - instanceStore: instanceStore, - sqlStore: sqlStore, + cache: newCache(logger, metrics, externalURL), + quit: make(chan struct{}), + ResendDelay: ResendDelay, // TODO: make this configurable + log: logger, + metrics: metrics, + ruleStore: ruleStore, + instanceStore: instanceStore, + sqlStore: sqlStore, + dashboardService: dashboardService, } go manager.recordMetrics() return manager @@ -274,7 +278,7 @@ func (st *Manager) annotateState(ctx context.Context, alertRule *ngModels.AlertR OrgId: alertRule.OrgID, } - err = st.sqlStore.GetDashboard(ctx, query) + err = st.dashboardService.GetDashboard(ctx, query) if err != nil { st.log.Error("error getting dashboard for alert annotation", "dashboardUID", dashUid, "alertRuleUID", alertRule.UID, "error", err.Error()) return diff --git a/pkg/services/ngalert/state/manager_test.go b/pkg/services/ngalert/state/manager_test.go index 7ef5a293282..69dc18d5f82 100644 --- a/pkg/services/ngalert/state/manager_test.go +++ b/pkg/services/ngalert/state/manager_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/grafana/grafana/pkg/services/annotations" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/sqlstore/mockstore" @@ -37,7 +38,7 @@ func TestDashboardAnnotations(t *testing.T) { _, dbstore := tests.SetupTestEnv(t, 1) sqlStore := mockstore.NewSQLStoreMock() - st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore) + st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{}) fakeAnnoRepo := store.NewFakeAnnotationsRepo() annotations.SetRepository(fakeAnnoRepo) @@ -1770,7 +1771,7 @@ func TestProcessEvalResults(t *testing.T) { for _, tc := range testCases { ss := mockstore.NewSQLStoreMock() - st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss) + st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, ss, &dashboards.FakeDashboardService{}) t.Run(tc.desc, func(t *testing.T) { fakeAnnoRepo := store.NewFakeAnnotationsRepo() annotations.SetRepository(fakeAnnoRepo) @@ -1881,7 +1882,7 @@ func TestStaleResultsHandler(t *testing.T) { for _, tc := range testCases { ctx := context.Background() sqlStore := mockstore.NewSQLStoreMock() - st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore) + st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, sqlStore, &dashboards.FakeDashboardService{}) st.Warm(ctx) existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID) diff --git a/pkg/services/ngalert/tests/util.go b/pkg/services/ngalert/tests/util.go index ed5915fa071..85c5f2f13cf 100644 --- a/pkg/services/ngalert/tests/util.go +++ b/pkg/services/ngalert/tests/util.go @@ -10,8 +10,9 @@ import ( "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/infra/log" acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" + "github.com/grafana/grafana/pkg/services/dashboards" databasestore "github.com/grafana/grafana/pkg/services/dashboards/database" - dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/manager" + dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/ngalert" "github.com/grafana/grafana/pkg/services/ngalert/metrics" @@ -60,12 +61,12 @@ func SetupTestEnv(t *testing.T, baseInterval time.Duration) (*ngalert.AlertNG, * ) folderService := dashboardservice.ProvideFolderService( cfg, dashboardService, dashboardStore, nil, - features, folderPermissions, ac, nil, + features, folderPermissions, ac, ) ng, err := ngalert.ProvideService( - cfg, nil, routing.NewRouteRegister(), sqlStore, - nil, nil, nil, nil, secretsService, nil, m, folderService, ac, + cfg, nil, routing.NewRouteRegister(), sqlStore, nil, nil, nil, nil, + secretsService, nil, m, folderService, ac, &dashboards.FakeDashboardService{}, ) require.NoError(t, err) return ng, &store.DBstore{ diff --git a/pkg/services/provisioning/provisioning.go b/pkg/services/provisioning/provisioning.go index 091d3329aed..9ac8ed651f7 100644 --- a/pkg/services/provisioning/provisioning.go +++ b/pkg/services/provisioning/provisioning.go @@ -26,25 +26,27 @@ import ( func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore plugifaces.Store, encryptionService encryption.Internal, notificatonService *notifications.NotificationService, - dashboardService dashboardservice.DashboardProvisioningService, + dashboardProvisioningService dashboardservice.DashboardProvisioningService, datasourceService datasourceservice.DataSourceService, + dashboardService dashboardservice.DashboardService, alertingService *alerting.AlertNotificationService, pluginSettings pluginsettings.Service, ) (*ProvisioningServiceImpl, error) { s := &ProvisioningServiceImpl{ - Cfg: cfg, - SQLStore: sqlStore, - pluginStore: pluginStore, - EncryptionService: encryptionService, - NotificationService: notificatonService, - log: log.New("provisioning"), - newDashboardProvisioner: dashboards.New, - provisionNotifiers: notifiers.Provision, - provisionDatasources: datasources.Provision, - provisionPlugins: plugins.Provision, - dashboardService: dashboardService, - datasourceService: datasourceService, - alertingService: alertingService, - pluginsSettings: pluginSettings, + Cfg: cfg, + SQLStore: sqlStore, + pluginStore: pluginStore, + EncryptionService: encryptionService, + NotificationService: notificatonService, + log: log.New("provisioning"), + newDashboardProvisioner: dashboards.New, + provisionNotifiers: notifiers.Provision, + provisionDatasources: datasources.Provision, + provisionPlugins: plugins.Provision, + dashboardProvisioningService: dashboardProvisioningService, + dashboardService: dashboardService, + datasourceService: datasourceService, + alertingService: alertingService, + pluginsSettings: pluginSettings, } return s, nil } @@ -88,23 +90,24 @@ func newProvisioningServiceImpl( } type ProvisioningServiceImpl struct { - Cfg *setting.Cfg - SQLStore *sqlstore.SQLStore - pluginStore plugifaces.Store - EncryptionService encryption.Internal - NotificationService *notifications.NotificationService - log log.Logger - pollingCtxCancel context.CancelFunc - newDashboardProvisioner dashboards.DashboardProvisionerFactory - dashboardProvisioner dashboards.DashboardProvisioner - provisionNotifiers func(context.Context, string, notifiers.Manager, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error - provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error - provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error - mutex sync.Mutex - dashboardService dashboardservice.DashboardProvisioningService - datasourceService datasourceservice.DataSourceService - alertingService *alerting.AlertNotificationService - pluginsSettings pluginsettings.Service + Cfg *setting.Cfg + SQLStore *sqlstore.SQLStore + pluginStore plugifaces.Store + EncryptionService encryption.Internal + NotificationService *notifications.NotificationService + log log.Logger + pollingCtxCancel context.CancelFunc + newDashboardProvisioner dashboards.DashboardProvisionerFactory + dashboardProvisioner dashboards.DashboardProvisioner + provisionNotifiers func(context.Context, string, notifiers.Manager, notifiers.SQLStore, encryption.Internal, *notifications.NotificationService) error + provisionDatasources func(context.Context, string, datasources.Store, utils.OrgStore) error + provisionPlugins func(context.Context, string, plugins.Store, plugifaces.Store, pluginsettings.Service) error + mutex sync.Mutex + dashboardProvisioningService dashboardservice.DashboardProvisioningService + dashboardService dashboardservice.DashboardService + datasourceService datasourceservice.DataSourceService + alertingService *alerting.AlertNotificationService + pluginsSettings pluginsettings.Service } func (ps *ProvisioningServiceImpl) RunInitProvisioners(ctx context.Context) error { @@ -187,7 +190,7 @@ func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) e func (ps *ProvisioningServiceImpl) ProvisionDashboards(ctx context.Context) error { dashboardPath := filepath.Join(ps.Cfg.ProvisioningPath, "dashboards") - dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardService, ps.SQLStore, ps.SQLStore) + dashProvisioner, err := ps.newDashboardProvisioner(ctx, dashboardPath, ps.dashboardProvisioningService, ps.SQLStore, ps.dashboardService) if err != nil { return errutil.Wrap("Failed to create provisioner", err) } diff --git a/pkg/services/sqlstore/dashboard.go b/pkg/services/sqlstore/dashboard.go index 4ef72b2daf0..34d453e94c3 100644 --- a/pkg/services/sqlstore/dashboard.go +++ b/pkg/services/sqlstore/dashboard.go @@ -29,28 +29,6 @@ func init() { var generateNewUid func() string = util.GenerateShortUID -func (ss *SQLStore) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error { - return ss.WithDbSession(ctx, func(dbSession *DBSession) error { - if query.Id == 0 && len(query.Slug) == 0 && len(query.Uid) == 0 { - return models.ErrDashboardIdentifierNotSet - } - - dashboard := models.Dashboard{Slug: query.Slug, OrgId: query.OrgId, Id: query.Id, Uid: query.Uid} - has, err := dbSession.Get(&dashboard) - - if err != nil { - return err - } else if !has { - return models.ErrDashboardNotFound - } - - dashboard.SetId(dashboard.Id) - dashboard.SetUid(dashboard.Uid) - query.Result = &dashboard - return nil - }) -} - type DashboardSearchProjection struct { ID int64 `xorm:"id"` UID string `xorm:"uid"` diff --git a/pkg/services/sqlstore/dashboard_version_test.go b/pkg/services/sqlstore/dashboard_version_test.go index 07adedc92ab..55cac4e816a 100644 --- a/pkg/services/sqlstore/dashboard_version_test.go +++ b/pkg/services/sqlstore/dashboard_version_test.go @@ -9,11 +9,12 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/util" - "github.com/stretchr/testify/require" ) func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard, data map[string]interface{}) { @@ -94,14 +95,13 @@ func TestGetDashboardVersion(t *testing.T) { require.Equal(t, query.DashboardId, savedDash.Id) require.Equal(t, query.Version, savedDash.Version) - dashCmd := models.GetDashboardQuery{ - OrgId: savedDash.OrgId, + dashCmd := &models.Dashboard{ Uid: savedDash.Uid, + OrgId: savedDash.OrgId, } - - err = sqlStore.GetDashboard(context.Background(), &dashCmd) + err = getDashboard(t, sqlStore, dashCmd) require.Nil(t, err) - eq := reflect.DeepEqual(dashCmd.Result.Data, query.Result.Data) + eq := reflect.DeepEqual(dashCmd.Data, query.Result.Data) require.Equal(t, true, eq) }) @@ -222,3 +222,20 @@ func TestDeleteExpiredVersions(t *testing.T) { require.LessOrEqual(t, versionsToWriteBigNumber-len(query.Result), perBatch*maxBatches) }) } + +func getDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Dashboard) error { + t.Helper() + return sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error { + has, err := sess.Get(dashboard) + + if err != nil { + return err + } else if !has { + return models.ErrDashboardNotFound + } + + dashboard.SetId(dashboard.Id) + dashboard.SetUid(dashboard.Uid) + return nil + }) +} diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 6a1c9a56651..e6b102b0f9c 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -20,7 +20,6 @@ type SQLStoreMock struct { ExpectedDatasource *models.DataSource ExpectedAlert *models.Alert ExpectedPluginSetting *models.PluginSetting - ExpectedDashboard *models.Dashboard ExpectedDashboards []*models.Dashboard ExpectedDashboardVersion *models.DashboardVersion ExpectedDashboardVersions []*models.DashboardVersion @@ -466,11 +465,6 @@ func (m *SQLStoreMock) SaveDashboard(cmd models.SaveDashboardCommand) (*models.D return nil, m.ExpectedError } -func (m *SQLStoreMock) GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error { - query.Result = m.ExpectedDashboard - return m.ExpectedError -} - func (m SQLStoreMock) SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error { query.Result = m.ExpectedPersistedDashboards return m.ExpectedError diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index 1de411c4bc0..a654be35be4 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -100,7 +100,6 @@ type Store interface { GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error - GetDashboard(ctx context.Context, query *models.GetDashboardQuery) error GetDashboardTags(ctx context.Context, query *models.GetDashboardTagsQuery) error SearchDashboards(ctx context.Context, query *models.FindPersistedDashboardsQuery) error GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error diff --git a/pkg/services/thumbs/service.go b/pkg/services/thumbs/service.go index b1c72334bbd..f3b1e2a84ac 100644 --- a/pkg/services/thumbs/service.go +++ b/pkg/services/thumbs/service.go @@ -9,11 +9,14 @@ import ( "net/http" "time" + "github.com/segmentio/encoding/json" + "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/serverlock" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/registry" + "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/live" @@ -21,7 +24,6 @@ import ( "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/web" - "github.com/segmentio/encoding/json" ) type Service interface { @@ -53,6 +55,7 @@ type thumbService struct { log log.Logger canRunCrawler bool settings setting.DashboardPreviewsSettings + dashboardService dashboards.DashboardService } type crawlerScheduleOptions struct { @@ -65,7 +68,10 @@ type crawlerScheduleOptions struct { auth CrawlerAuth } -func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockService *serverlock.ServerLockService, renderService rendering.Service, gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService) Service { +func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, + lockService *serverlock.ServerLockService, renderService rendering.Service, + gl *live.GrafanaLive, store *sqlstore.SQLStore, authSetupService CrawlerAuthSetupService, + dashboardService dashboards.DashboardService) Service { if !features.IsEnabled(featuremgmt.FlagDashboardPreviews) { return &dummyService{} } @@ -96,7 +102,6 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS log: logger, canRunCrawler: canRunCrawler, settings: cfg.DashboardPreviews, - scheduleOptions: crawlerScheduleOptions{ tickerInterval: 5 * time.Minute, crawlInterval: cfg.DashboardPreviews.SchedulerInterval, @@ -106,6 +111,7 @@ func ProvideService(cfg *setting.Cfg, features featuremgmt.FeatureToggles, lockS themes: []models.Theme{models.ThemeDark, models.ThemeLight}, auth: crawlerAuth, }, + dashboardService: dashboardService, } return t @@ -400,7 +406,7 @@ func (hs *thumbService) getStatus(c *models.ReqContext, uid string, checkSave bo func (hs *thumbService) getDashboardId(c *models.ReqContext, uid string) (int64, error) { query := models.GetDashboardQuery{Uid: uid, OrgId: c.OrgId} - if err := hs.store.GetDashboard(c.Req.Context(), &query); err != nil { + if err := hs.dashboardService.GetDashboard(c.Req.Context(), &query); err != nil { return 0, err }