From b07904fe56eb8305b068bb369a2275b9cea17e05 Mon Sep 17 00:00:00 2001 From: idafurjes <36131195+idafurjes@users.noreply.github.com> Date: Wed, 25 May 2022 10:41:51 +0200 Subject: [PATCH] Add store split for Get Dashboard version method (#49138) * Add store split for Get Dashboard version method * Implement dashboard version service * Fix api tests * Remove GetDashboarVersion from sqlstore * Add fakes for Get dashboard version * Fix sqlstore test * Add Get Dashboard store test * Add dashver service test * Remove useless comments --- pkg/api/common_test.go | 26 ++-- pkg/api/dashboard.go | 59 ++++---- pkg/api/dashboard_test.go | 141 ++++++++++++------ pkg/api/http_server.go | 6 +- pkg/server/wire.go | 2 + pkg/services/dashboardversion/dashver.go | 9 ++ .../dashboardversion/dashverimpl/dashver.go | 30 ++++ .../dashverimpl/dashver_test.go | 39 +++++ .../dashboardversion/dashverimpl/store.go | 40 +++++ .../dashverimpl/store_test.go | 131 ++++++++++++++++ .../dashboardversion/dashvertest/fake.go | 26 ++++ pkg/services/dashboardversion/model.go | 27 ++++ pkg/services/sqlstore/dashboard_version.go | 22 --- .../sqlstore/dashboard_version_test.go | 41 ----- pkg/services/sqlstore/mockstore/mockstore.go | 10 -- pkg/services/sqlstore/store.go | 1 - 16 files changed, 447 insertions(+), 163 deletions(-) create mode 100644 pkg/services/dashboardversion/dashver.go create mode 100644 pkg/services/dashboardversion/dashverimpl/dashver.go create mode 100644 pkg/services/dashboardversion/dashverimpl/dashver_test.go create mode 100644 pkg/services/dashboardversion/dashverimpl/store.go create mode 100644 pkg/services/dashboardversion/dashverimpl/store_test.go create mode 100644 pkg/services/dashboardversion/dashvertest/fake.go create mode 100644 pkg/services/dashboardversion/model.go diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index 86243b18d3d..07c90692fc4 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -31,6 +31,7 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/ldap" "github.com/grafana/grafana/pkg/services/login/loginservice" @@ -154,18 +155,19 @@ func (sc *scenarioContext) fakeReqNoAssertionsWithCookie(method, url string, coo } type scenarioContext struct { - t *testing.T - cfg *setting.Cfg - m *web.Mux - context *models.ReqContext - resp *httptest.ResponseRecorder - handlerFunc handlerFunc - defaultHandler web.Handler - req *http.Request - url string - userAuthTokenService *auth.FakeUserAuthTokenService - sqlStore sqlstore.Store - authInfoService *logintest.AuthInfoServiceFake + t *testing.T + cfg *setting.Cfg + m *web.Mux + context *models.ReqContext + resp *httptest.ResponseRecorder + handlerFunc handlerFunc + defaultHandler web.Handler + req *http.Request + url string + userAuthTokenService *auth.FakeUserAuthTokenService + sqlStore sqlstore.Store + authInfoService *logintest.AuthInfoServiceFake + dashboardVersionService dashver.Service } func (sc *scenarioContext) exec() { diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 4fb8202bb71..8ab6fa56a45 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -23,6 +23,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/dashboards" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" pref "github.com/grafana/grafana/pkg/services/preference" @@ -624,31 +625,32 @@ func (hs *HTTPServer) GetDashboardVersion(c *models.ReqContext) response.Respons } version, _ := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 32) - query := models.GetDashboardVersionQuery{ - OrgId: c.OrgId, - DashboardId: dashID, + query := dashver.GetDashboardVersionQuery{ + OrgID: c.OrgId, + DashboardID: dashID, Version: int(version), } - if err := hs.SQLStore.GetDashboardVersion(c.Req.Context(), &query); err != nil { + res, err := hs.dashboardVersionService.Get(c.Req.Context(), &query) + if err != nil { return response.Error(500, fmt.Sprintf("Dashboard version %d not found for dashboardId %d", query.Version, dashID), err) } creator := anonString - if query.Result.CreatedBy > 0 { - creator = hs.getUserLogin(c.Req.Context(), query.Result.CreatedBy) + if res.CreatedBy > 0 { + creator = hs.getUserLogin(c.Req.Context(), res.CreatedBy) } dashVersionMeta := &models.DashboardVersionMeta{ - Id: query.Result.Id, - DashboardId: query.Result.DashboardId, + Id: res.ID, + DashboardId: res.DashboardID, DashboardUID: dashUID, - Data: query.Result.Data, - ParentVersion: query.Result.ParentVersion, - RestoredFrom: query.Result.RestoredFrom, - Version: query.Result.Version, - Created: query.Result.Created, - Message: query.Result.Message, + Data: res.Data, + ParentVersion: res.ParentVersion, + RestoredFrom: res.RestoredFrom, + Version: res.Version, + Created: res.Created, + Message: res.Message, CreatedBy: creator, } @@ -688,34 +690,36 @@ func (hs *HTTPServer) CalculateDashboardDiff(c *models.ReqContext) response.Resp }, } - baseVersionQuery := models.GetDashboardVersionQuery{ - DashboardId: options.Base.DashboardId, + baseVersionQuery := dashver.GetDashboardVersionQuery{ + DashboardID: options.Base.DashboardId, Version: options.Base.Version, - OrgId: options.OrgId, + OrgID: options.OrgId, } - if err := hs.SQLStore.GetDashboardVersion(c.Req.Context(), &baseVersionQuery); err != nil { + baseVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &baseVersionQuery) + if err != nil { if errors.Is(err, models.ErrDashboardVersionNotFound) { return response.Error(404, "Dashboard version not found", err) } return response.Error(500, "Unable to compute diff", err) } - newVersionQuery := models.GetDashboardVersionQuery{ - DashboardId: options.New.DashboardId, + newVersionQuery := dashver.GetDashboardVersionQuery{ + DashboardID: options.New.DashboardId, Version: options.New.Version, - OrgId: options.OrgId, + OrgID: options.OrgId, } - if err := hs.SQLStore.GetDashboardVersion(c.Req.Context(), &newVersionQuery); err != nil { + newVersionRes, err := hs.dashboardVersionService.Get(c.Req.Context(), &newVersionQuery) + if err != nil { if errors.Is(err, models.ErrDashboardVersionNotFound) { return response.Error(404, "Dashboard version not found", err) } return response.Error(500, "Unable to compute diff", err) } - baseData := baseVersionQuery.Result.Data - newData := newVersionQuery.Result.Data + baseData := baseVersionRes.Data + newData := newVersionRes.Data result, err := dashdiffs.CalculateDiff(c.Req.Context(), &options, baseData, newData) @@ -765,13 +769,12 @@ func (hs *HTTPServer) RestoreDashboardVersion(c *models.ReqContext) response.Res return dashboardGuardianResponse(err) } - versionQuery := models.GetDashboardVersionQuery{DashboardId: dashID, Version: apiCmd.Version, OrgId: c.OrgId} - if err := hs.SQLStore.GetDashboardVersion(c.Req.Context(), &versionQuery); err != nil { + versionQuery := dashver.GetDashboardVersionQuery{DashboardID: dashID, Version: apiCmd.Version, OrgID: c.OrgId} + version, err := hs.dashboardVersionService.Get(c.Req.Context(), &versionQuery) + if err != nil { return response.Error(404, "Dashboard version not found", nil) } - version := versionQuery.Result - saveCmd := models.SaveDashboardCommand{} saveCmd.RestoredFrom = version.Version saveCmd.OrgId = c.OrgId diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index 3d9a47a4bb2..b42602197b9 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -27,6 +27,8 @@ import ( "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/service" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/dashboardversion/dashvertest" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/libraryelements" @@ -49,13 +51,15 @@ func TestGetHomeDashboard(t *testing.T) { cfg := setting.NewCfg() cfg.StaticRootPath = "../../public/" prefService := preftest.NewPreferenceServiceFake() + dashboardVersionService := dashvertest.NewDashboardVersionServiceFake() hs := &HTTPServer{ - Cfg: cfg, - pluginStore: &fakePluginStore{}, - SQLStore: mockstore.NewSQLStoreMock(), - CoremodelRegistry: setupDashboardCoremodel(t), - preferenceService: prefService, + Cfg: cfg, + pluginStore: &fakePluginStore{}, + SQLStore: mockstore.NewSQLStoreMock(), + preferenceService: prefService, + dashboardVersionService: dashboardVersionService, + CoremodelRegistry: setupDashboardCoremodel(t), } tests := []struct { @@ -122,6 +126,8 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.Id = 1 fakeDash.FolderId = 1 fakeDash.HasAcl = false + fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() + fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersion{} dashboardService := dashboards.NewFakeDashboardService(t) dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardQuery) @@ -131,13 +137,14 @@ func TestDashboardAPIEndpoint(t *testing.T) { mockSQLStore := mockstore.NewSQLStoreMock() hs := &HTTPServer{ - Cfg: setting.NewCfg(), - pluginStore: &fakePluginStore{}, - SQLStore: mockSQLStore, - CoremodelRegistry: setupDashboardCoremodel(t), - AccessControl: accesscontrolmock.New(), - Features: featuremgmt.WithFeatures(), - dashboardService: dashboardService, + Cfg: setting.NewCfg(), + pluginStore: &fakePluginStore{}, + SQLStore: mockSQLStore, + AccessControl: accesscontrolmock.New(), + Features: featuremgmt.WithFeatures(), + dashboardService: dashboardService, + dashboardVersionService: fakeDashboardVersionService, + CoremodelRegistry: setupDashboardCoremodel(t), } setUp := func() { @@ -225,6 +232,8 @@ func TestDashboardAPIEndpoint(t *testing.T) { fakeDash.Id = 1 fakeDash.FolderId = 1 fakeDash.HasAcl = true + fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() + fakeDashboardVersionService.ExpectedDashboardVersion = &dashver.DashboardVersion{} dashboardService := dashboards.NewFakeDashboardService(t) dashboardService.On("GetDashboard", mock.Anything, mock.AnythingOfType("*models.GetDashboardQuery")).Run(func(args mock.Arguments) { q := args.Get(1).(*models.GetDashboardQuery) @@ -236,14 +245,15 @@ func TestDashboardAPIEndpoint(t *testing.T) { sql := sqlstore.InitTestDB(t) hs := &HTTPServer{ - Cfg: cfg, - Live: newTestLive(t, sql), - LibraryPanelService: &mockLibraryPanelService{}, - LibraryElementService: &mockLibraryElementService{}, - CoremodelRegistry: setupDashboardCoremodel(t), - SQLStore: mockSQLStore, - AccessControl: accesscontrolmock.New(), - dashboardService: dashboardService, + Cfg: cfg, + Live: newTestLive(t, sql), + LibraryPanelService: &mockLibraryPanelService{}, + LibraryElementService: &mockLibraryElementService{}, + SQLStore: mockSQLStore, + AccessControl: accesscontrolmock.New(), + dashboardService: dashboardService, + dashboardVersionService: fakeDashboardVersionService, + CoremodelRegistry: setupDashboardCoremodel(t), } setUp := func() { @@ -389,6 +399,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { setUpInner() sc.sqlStore = mockSQLStore + sc.dashboardVersionService = fakeDashboardVersionService hs.callGetDashboardVersion(sc) assert.Equal(t, 200, sc.resp.Code) @@ -705,6 +716,23 @@ func TestDashboardAPIEndpoint(t *testing.T) { "title": "Dash2", })}, } + fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() + fakeDashboardVersionService.ExpectedDashboardVersions = []*dashver.DashboardVersion{ + { + DashboardID: 1, + Version: 1, + Data: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash1", + }), + }, + { + DashboardID: 2, + Version: 2, + Data: simplejson.NewFromAny(map[string]interface{}{ + "title": "Dash2", + }), + }, + } sqlmock := mockstore.SQLStoreMock{ExpectedDashboardVersions: dashboardvs} setUp := func() { mockResult := []*models.DashboardAclInfoDTO{} @@ -730,7 +758,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { callPostDashboard(sc) assert.Equal(t, 403, sc.resp.Code) - }, &sqlmock) + }, &sqlmock, fakeDashboardVersionService) }) t.Run("when user does have permission", func(t *testing.T) { @@ -739,9 +767,10 @@ func TestDashboardAPIEndpoint(t *testing.T) { postDiffScenario(t, "When calling POST on", "/api/dashboards/calculate-diff", "/api/dashboards/calculate-diff", cmd, role, func(sc *scenarioContext) { setUp() + sc.dashboardVersionService = fakeDashboardVersionService callPostDashboard(sc) assert.Equal(t, 200, sc.resp.Code) - }, &sqlmock) + }, &sqlmock, fakeDashboardVersionService) }) }) @@ -767,16 +796,18 @@ func TestDashboardAPIEndpoint(t *testing.T) { cmd := dtos.RestoreDashboardVersionCommand{ Version: 1, } - mockSQLStore := mockstore.NewSQLStoreMock() - mockSQLStore.ExpectedDashboardVersions = []*models.DashboardVersion{ + fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() + fakeDashboardVersionService.ExpectedDashboardVersions = []*dashver.DashboardVersion{ { - DashboardId: 2, + DashboardID: 2, Version: 1, Data: fakeDash.Data, }} - + mockSQLStore := mockstore.NewSQLStoreMock() restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore", - "/api/dashboards/id/:dashboardId/restore", dashboardService, cmd, func(sc *scenarioContext) { + "/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) { + sc.dashboardVersionService = fakeDashboardVersionService + callRestoreDashboardVersion(sc) assert.Equal(t, 200, sc.resp.Code) }, mockSQLStore) @@ -799,6 +830,14 @@ func TestDashboardAPIEndpoint(t *testing.T) { } }).Return(nil, nil) + fakeDashboardVersionService := dashvertest.NewDashboardVersionServiceFake() + fakeDashboardVersionService.ExpectedDashboardVersions = []*dashver.DashboardVersion{ + { + DashboardID: 2, + Version: 1, + Data: fakeDash.Data, + }} + cmd := dtos.RestoreDashboardVersionCommand{ Version: 1, } @@ -810,7 +849,7 @@ func TestDashboardAPIEndpoint(t *testing.T) { Data: fakeDash.Data, }} restoreDashboardVersionScenario(t, "When calling POST on", "/api/dashboards/id/1/restore", - "/api/dashboards/id/:dashboardId/restore", dashboardService, cmd, func(sc *scenarioContext) { + "/api/dashboards/id/:dashboardId/restore", dashboardService, fakeDashboardVersionService, cmd, func(sc *scenarioContext) { callRestoreDashboardVersion(sc) assert.Equal(t, 200, sc.resp.Code) }, mockSQLStore) @@ -1003,18 +1042,20 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s }) } -func postDiffScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions, role models.RoleType, fn scenarioFunc, sqlmock sqlstore.Store) { +func postDiffScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.CalculateDiffOptions, + role models.RoleType, fn scenarioFunc, sqlmock sqlstore.Store, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { cfg := setting.NewCfg() hs := HTTPServer{ - Cfg: cfg, - ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()), - Live: newTestLive(t, sqlstore.InitTestDB(t)), - QuotaService: "a.QuotaService{Cfg: cfg}, - LibraryPanelService: &mockLibraryPanelService{}, - LibraryElementService: &mockLibraryElementService{}, - CoremodelRegistry: setupDashboardCoremodel(t), - SQLStore: sqlmock, + Cfg: cfg, + ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()), + Live: newTestLive(t, sqlstore.InitTestDB(t)), + QuotaService: "a.QuotaService{Cfg: cfg}, + LibraryPanelService: &mockLibraryPanelService{}, + LibraryElementService: &mockLibraryElementService{}, + SQLStore: sqlmock, + dashboardVersionService: fakeDashboardVersionService, + CoremodelRegistry: setupDashboardCoremodel(t), } sc := setupScenarioContext(t, url) @@ -1037,24 +1078,28 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string }) } -func restoreDashboardVersionScenario(t *testing.T, desc string, url string, routePattern string, mock *dashboards.FakeDashboardService, cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc, sqlStore sqlstore.Store) { +func restoreDashboardVersionScenario(t *testing.T, desc string, url string, routePattern string, + mock *dashboards.FakeDashboardService, fakeDashboardVersionService *dashvertest.FakeDashboardVersionService, + cmd dtos.RestoreDashboardVersionCommand, fn scenarioFunc, sqlStore sqlstore.Store) { t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { cfg := setting.NewCfg() hs := HTTPServer{ - Cfg: cfg, - ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()), - Live: newTestLive(t, sqlstore.InitTestDB(t)), - QuotaService: "a.QuotaService{Cfg: cfg}, - LibraryPanelService: &mockLibraryPanelService{}, - LibraryElementService: &mockLibraryElementService{}, - CoremodelRegistry: setupDashboardCoremodel(t), - dashboardService: mock, - SQLStore: sqlStore, - Features: featuremgmt.WithFeatures(), + Cfg: cfg, + ProvisioningService: provisioning.NewProvisioningServiceMock(context.Background()), + Live: newTestLive(t, sqlstore.InitTestDB(t)), + QuotaService: "a.QuotaService{Cfg: cfg}, + LibraryPanelService: &mockLibraryPanelService{}, + LibraryElementService: &mockLibraryElementService{}, + dashboardService: mock, + SQLStore: sqlStore, + Features: featuremgmt.WithFeatures(), + dashboardVersionService: fakeDashboardVersionService, + CoremodelRegistry: setupDashboardCoremodel(t), } sc := setupScenarioContext(t, url) sc.sqlStore = sqlStore + sc.dashboardVersionService = fakeDashboardVersionService sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { c.Req.Body = mockRequestBody(cmd) c.Req.Header.Add("Content-Type", "application/json") diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 6f0a785bbcc..e5764d5e102 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -35,6 +35,7 @@ import ( "github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboardsnapshots" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources/permissions" @@ -154,6 +155,7 @@ type HTTPServer struct { entityEventsService store.EntityEventsService folderPermissionsService accesscontrol.FolderPermissionsService dashboardPermissionsService accesscontrol.DashboardPermissionsService + dashboardVersionService dashver.Service starService star.Service CoremodelRegistry *coremodel.Registry } @@ -189,7 +191,8 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi dashboardsnapshotsService *dashboardsnapshots.Service, commentsService *comments.Service, pluginSettings *pluginSettings.Service, avatarCacheServer *avatar.AvatarCacheServer, preferenceService pref.Service, entityEventsService store.EntityEventsService, teamsPermissionsService accesscontrol.TeamPermissionsService, folderPermissionsService accesscontrol.FolderPermissionsService, - dashboardPermissionsService accesscontrol.DashboardPermissionsService, starService star.Service, coremodelRegistry *coremodel.Registry, + dashboardPermissionsService accesscontrol.DashboardPermissionsService, dashboardVersionService dashver.Service, + starService star.Service, coremodelRegistry *coremodel.Registry, ) (*HTTPServer, error) { web.Env = cfg.Env m := web.New() @@ -266,6 +269,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi entityEventsService: entityEventsService, folderPermissionsService: folderPermissionsService, dashboardPermissionsService: dashboardPermissionsService, + dashboardVersionService: dashboardVersionService, starService: starService, CoremodelRegistry: coremodelRegistry, } diff --git a/pkg/server/wire.go b/pkg/server/wire.go index f3b2db696bd..db04ba1c04e 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -48,6 +48,7 @@ import ( dashboardstore "github.com/grafana/grafana/pkg/services/dashboards/database" dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" "github.com/grafana/grafana/pkg/services/dashboardsnapshots" + "github.com/grafana/grafana/pkg/services/dashboardversion/dashverimpl" "github.com/grafana/grafana/pkg/services/datasourceproxy" "github.com/grafana/grafana/pkg/services/datasources" datasourceservice "github.com/grafana/grafana/pkg/services/datasources/service" @@ -260,6 +261,7 @@ var wireBasicSet = wire.NewSet( ossaccesscontrol.ProvideDashboardPermissions, wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), starimpl.ProvideService, + dashverimpl.ProvideService, ) var wireSet = wire.NewSet( diff --git a/pkg/services/dashboardversion/dashver.go b/pkg/services/dashboardversion/dashver.go new file mode 100644 index 00000000000..c5a60804eda --- /dev/null +++ b/pkg/services/dashboardversion/dashver.go @@ -0,0 +1,9 @@ +package dashver + +import ( + "context" +) + +type Service interface { + Get(ctx context.Context, query *GetDashboardVersionQuery) (*DashboardVersion, error) +} diff --git a/pkg/services/dashboardversion/dashverimpl/dashver.go b/pkg/services/dashboardversion/dashverimpl/dashver.go new file mode 100644 index 00000000000..aedf947958a --- /dev/null +++ b/pkg/services/dashboardversion/dashverimpl/dashver.go @@ -0,0 +1,30 @@ +package dashverimpl + +import ( + "context" + + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/sqlstore/db" + "github.com/grafana/grafana/pkg/setting" +) + +type Service struct { + store store +} + +func ProvideService(db db.DB, cfg *setting.Cfg) dashver.Service { + return &Service{ + store: &sqlStore{ + db: db, + }, + } +} + +func (s *Service) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) { + version, err := s.store.Get(ctx, query) + if err != nil { + return nil, err + } + version.Data.Set("id", version.DashboardID) + return version, nil +} diff --git a/pkg/services/dashboardversion/dashverimpl/dashver_test.go b/pkg/services/dashboardversion/dashverimpl/dashver_test.go new file mode 100644 index 00000000000..8bf577af8eb --- /dev/null +++ b/pkg/services/dashboardversion/dashverimpl/dashver_test.go @@ -0,0 +1,39 @@ +package dashverimpl + +import ( + "context" + "testing" + + "github.com/grafana/grafana/pkg/components/simplejson" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/stretchr/testify/require" +) + +func TestDashboardVersionService(t *testing.T) { + dashboardVersionStore := newDashboardVersionStoreFake() + dashboardVersionService := Service{store: dashboardVersionStore} + + t.Run("Get dashboard version", func(t *testing.T) { + dashboard := &dashver.DashboardVersion{ + ID: 11, + Data: &simplejson.Json{}, + } + dashboardVersionStore.ExpectedDashboardVersion = dashboard + dashboardVersion, err := dashboardVersionService.Get(context.Background(), &dashver.GetDashboardVersionQuery{}) + require.NoError(t, err) + require.Equal(t, dashboardVersion, dashboard) + }) +} + +type FakeDashboardVersionStroe struct { + ExpectedDashboardVersion *dashver.DashboardVersion + ExpectedError error +} + +func newDashboardVersionStoreFake() *FakeDashboardVersionStroe { + return &FakeDashboardVersionStroe{} +} + +func (f *FakeDashboardVersionStroe) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) { + return f.ExpectedDashboardVersion, f.ExpectedError +} diff --git a/pkg/services/dashboardversion/dashverimpl/store.go b/pkg/services/dashboardversion/dashverimpl/store.go new file mode 100644 index 00000000000..e9558de3613 --- /dev/null +++ b/pkg/services/dashboardversion/dashverimpl/store.go @@ -0,0 +1,40 @@ +package dashverimpl + +import ( + "context" + + "github.com/grafana/grafana/pkg/models" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/services/sqlstore/db" +) + +type store interface { + Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) +} + +type sqlStore struct { + db db.DB +} + +func (s *sqlStore) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) { + var version dashver.DashboardVersion + err := s.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { + has, err := sess.Where("dashboard_version.dashboard_id=? AND dashboard_version.version=? AND dashboard.org_id=?", query.DashboardID, query.Version, query.OrgID). + Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`). + Get(&version) + + if err != nil { + return err + } + + if !has { + return models.ErrDashboardVersionNotFound + } + return nil + }) + if err != nil { + return nil, err + } + return &version, nil +} diff --git a/pkg/services/dashboardversion/dashverimpl/store_test.go b/pkg/services/dashboardversion/dashverimpl/store_test.go new file mode 100644 index 00000000000..2e6f21d4626 --- /dev/null +++ b/pkg/services/dashboardversion/dashverimpl/store_test.go @@ -0,0 +1,131 @@ +//go:build integration +// +build integration + +package dashverimpl + +import ( + "context" + "testing" + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" + "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/util" + + "github.com/stretchr/testify/require" +) + +func TestIntegrationDashboardVersion(t *testing.T) { + ss := sqlstore.InitTestDB(t) + dashVerStore := sqlStore{db: ss} + + t.Run("Get a Dashboard ID and version ID", func(t *testing.T) { + savedDash := insertTestDashboard(t, ss, "test dash 26", 1, 0, false, "diff") + + query := dashver.GetDashboardVersionQuery{ + DashboardID: savedDash.Id, + Version: savedDash.Version, + OrgID: 1, + } + + res, err := dashVerStore.Get(context.Background(), &query) + require.Nil(t, err) + require.Equal(t, query.DashboardID, savedDash.Id) + require.Equal(t, query.Version, savedDash.Version) + + dashCmd := &models.Dashboard{ + Id: res.ID, + Uid: savedDash.Uid, + OrgId: savedDash.OrgId, + } + err = getDashboard(t, ss, dashCmd) + require.Nil(t, err) + + require.EqualValues(t, dashCmd.Data.Get("uid"), res.Data.Get("uid")) + require.EqualValues(t, dashCmd.Data.Get("orgId"), res.Data.Get("orgId")) + }) + + t.Run("Attempt to get a version that doesn't exist", func(t *testing.T) { + query := dashver.GetDashboardVersionQuery{ + DashboardID: int64(999), + Version: 123, + OrgID: 1, + } + + _, err := dashVerStore.Get(context.Background(), &query) + require.Error(t, err) + require.Equal(t, models.ErrDashboardVersionNotFound, err) + }) +} + +func getDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, dashboard *models.Dashboard) error { + t.Helper() + return sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.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 + }) +} +func insertTestDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, title string, orgId int64, + folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard { + t.Helper() + cmd := models.SaveDashboardCommand{ + OrgId: orgId, + FolderId: folderId, + IsFolder: isFolder, + Dashboard: simplejson.NewFromAny(map[string]interface{}{ + "id": nil, + "title": title, + "tags": tags, + }), + } + + var dash *models.Dashboard + err := sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + dash = cmd.GetDashboardModel() + dash.SetVersion(1) + dash.Created = time.Now() + dash.Updated = time.Now() + dash.Uid = util.GenerateShortUID() + _, err := sess.Insert(dash) + return err + }) + + require.NoError(t, err) + require.NotNil(t, dash) + dash.Data.Set("id", dash.Id) + dash.Data.Set("uid", dash.Uid) + + err = sqlStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { + dashVersion := &models.DashboardVersion{ + DashboardId: dash.Id, + ParentVersion: dash.Version, + RestoredFrom: cmd.RestoredFrom, + Version: dash.Version, + Created: time.Now(), + CreatedBy: dash.UpdatedBy, + Message: cmd.Message, + Data: dash.Data, + } + + if affectedRows, err := sess.Insert(dashVersion); err != nil { + return err + } else if affectedRows == 0 { + return models.ErrDashboardNotFound + } + + return nil + }) + + return dash +} diff --git a/pkg/services/dashboardversion/dashvertest/fake.go b/pkg/services/dashboardversion/dashvertest/fake.go new file mode 100644 index 00000000000..ca88347dc91 --- /dev/null +++ b/pkg/services/dashboardversion/dashvertest/fake.go @@ -0,0 +1,26 @@ +package dashvertest + +import ( + "context" + + dashver "github.com/grafana/grafana/pkg/services/dashboardversion" +) + +type FakeDashboardVersionService struct { + ExpectedDashboardVersion *dashver.DashboardVersion + ExpectedDashboardVersions []*dashver.DashboardVersion + counter int + ExpectedError error +} + +func NewDashboardVersionServiceFake() *FakeDashboardVersionService { + return &FakeDashboardVersionService{} +} + +func (f *FakeDashboardVersionService) Get(ctx context.Context, query *dashver.GetDashboardVersionQuery) (*dashver.DashboardVersion, error) { + if len(f.ExpectedDashboardVersions) == 0 { + return f.ExpectedDashboardVersion, f.ExpectedError + } + f.counter++ + return f.ExpectedDashboardVersions[f.counter-1], f.ExpectedError +} diff --git a/pkg/services/dashboardversion/model.go b/pkg/services/dashboardversion/model.go new file mode 100644 index 00000000000..7967fd7a734 --- /dev/null +++ b/pkg/services/dashboardversion/model.go @@ -0,0 +1,27 @@ +package dashver + +import ( + "time" + + "github.com/grafana/grafana/pkg/components/simplejson" +) + +type DashboardVersion struct { + ID int64 `json:"id"` + DashboardID int64 `json:"dashboardId"` + ParentVersion int `json:"parentVersion"` + RestoredFrom int `json:"restoredFrom"` + Version int `json:"version"` + + Created time.Time `json:"created"` + CreatedBy int64 `json:"createdBy"` + + Message string `json:"message"` + Data *simplejson.Json `json:"data"` +} + +type GetDashboardVersionQuery struct { + DashboardID int64 + OrgID int64 + Version int +} diff --git a/pkg/services/sqlstore/dashboard_version.go b/pkg/services/sqlstore/dashboard_version.go index e8bd87b6461..9f55adb9383 100644 --- a/pkg/services/sqlstore/dashboard_version.go +++ b/pkg/services/sqlstore/dashboard_version.go @@ -8,28 +8,6 @@ import ( "github.com/grafana/grafana/pkg/setting" ) -// GetDashboardVersion gets the dashboard version for the given dashboard ID and version number. -func (ss *SQLStore) GetDashboardVersion(ctx context.Context, query *models.GetDashboardVersionQuery) error { - return ss.WithDbSession(ctx, func(sess *DBSession) error { - version := models.DashboardVersion{} - has, err := sess.Where("dashboard_version.dashboard_id=? AND dashboard_version.version=? AND dashboard.org_id=?", query.DashboardId, query.Version, query.OrgId). - Join("LEFT", "dashboard", `dashboard.id = dashboard_version.dashboard_id`). - Get(&version) - - if err != nil { - return err - } - - if !has { - return models.ErrDashboardVersionNotFound - } - - version.Data.Set("id", version.DashboardId) - query.Result = &version - return nil - }) -} - // GetDashboardVersions gets all dashboard versions for the given dashboard ID. func (ss *SQLStore) GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error { return ss.WithDbSession(ctx, func(sess *DBSession) error { diff --git a/pkg/services/sqlstore/dashboard_version_test.go b/pkg/services/sqlstore/dashboard_version_test.go index d68b26c3f5c..9424828a8da 100644 --- a/pkg/services/sqlstore/dashboard_version_test.go +++ b/pkg/services/sqlstore/dashboard_version_test.go @@ -5,7 +5,6 @@ package sqlstore import ( "context" - "reflect" "testing" "time" @@ -78,46 +77,6 @@ func updateTestDashboard(t *testing.T, sqlStore *SQLStore, dashboard *models.Das require.NoError(t, err) } -func TestIntegrationGetDashboardVersion(t *testing.T) { - sqlStore := InitTestDB(t) - - t.Run("Get a Dashboard ID and version ID", func(t *testing.T) { - savedDash := insertTestDashboard(t, sqlStore, "test dash 26", 1, 0, false, "diff") - - query := models.GetDashboardVersionQuery{ - DashboardId: savedDash.Id, - Version: savedDash.Version, - OrgId: 1, - } - - err := sqlStore.GetDashboardVersion(context.Background(), &query) - require.Nil(t, err) - require.Equal(t, query.DashboardId, savedDash.Id) - require.Equal(t, query.Version, savedDash.Version) - - dashCmd := &models.Dashboard{ - Uid: savedDash.Uid, - OrgId: savedDash.OrgId, - } - err = getDashboard(t, sqlStore, dashCmd) - require.Nil(t, err) - eq := reflect.DeepEqual(dashCmd.Data, query.Result.Data) - require.Equal(t, true, eq) - }) - - t.Run("Attempt to get a version that doesn't exist", func(t *testing.T) { - query := models.GetDashboardVersionQuery{ - DashboardId: int64(999), - Version: 123, - OrgId: 1, - } - - err := sqlStore.GetDashboardVersion(context.Background(), &query) - require.Error(t, err) - require.Equal(t, models.ErrDashboardVersionNotFound, err) - }) -} - func TestIntegrationGetDashboardVersions(t *testing.T) { sqlStore := InitTestDB(t) savedDash := insertTestDashboard(t, sqlStore, "test dash 43", 1, 0, false, "diff-all") diff --git a/pkg/services/sqlstore/mockstore/mockstore.go b/pkg/services/sqlstore/mockstore/mockstore.go index 877d54f6830..c56c3626ff8 100644 --- a/pkg/services/sqlstore/mockstore/mockstore.go +++ b/pkg/services/sqlstore/mockstore/mockstore.go @@ -344,16 +344,6 @@ func (m *SQLStoreMock) InTransaction(ctx context.Context, fn func(ctx context.Co return m.ExpectedError } -func (m *SQLStoreMock) GetDashboardVersion(ctx context.Context, query *models.GetDashboardVersionQuery) error { - query.Result = &models.DashboardVersion{} - for _, dashboardversion := range m.ExpectedDashboardVersions { - if dashboardversion.DashboardId == query.DashboardId && dashboardversion.Version == query.Version { - query.Result = dashboardversion - } - } - return m.ExpectedError -} - func (m *SQLStoreMock) GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error { return m.ExpectedError } diff --git a/pkg/services/sqlstore/store.go b/pkg/services/sqlstore/store.go index 531da0f55b0..fb818e9519b 100644 --- a/pkg/services/sqlstore/store.go +++ b/pkg/services/sqlstore/store.go @@ -74,7 +74,6 @@ type Store interface { GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error WithTransactionalDbSession(ctx context.Context, callback DBTransactionFunc) error InTransaction(ctx context.Context, fn func(ctx context.Context) error) error - GetDashboardVersion(ctx context.Context, query *models.GetDashboardVersionQuery) error GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error DeleteExpiredVersions(ctx context.Context, cmd *models.DeleteExpiredVersionsCommand) error GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error