chore(services): replace dependencies on dashboard store with dashboard service (#63937)

* chore(services): replace dependencies on dashboard store with dashboard service

This continues the backend service/store split by replacing dashboard store dependencies with service dependencies. the folder service remains the single exception for now; otherwise we'd have a dependency cycle between the folder and dashboard services. I have some ideas for that, but I'll take care of all the easy parts first.

While doing this, I identified and removed a number of unused arguments from the following functions:

NewFolderNameScopeResolver
NewFolderIDScopeResolver
NewFolderUIDScopeResolver
NewDashboardIDScopeResolver
NewDashboardUIDScopeResolver
resolveDashboardScope

I have a small enterprise PR to support this commit.

* lingering fmt
This commit is contained in:
Kristin Laemmert 2023-03-02 08:09:57 -05:00 committed by GitHub
parent a227f69bed
commit bb798e24f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 120 additions and 170 deletions

View File

@ -47,7 +47,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
SQLStore: mockSQLStore, SQLStore: mockSQLStore,
Features: features, Features: features,
DashboardService: dashboardservice.ProvideDashboardService( DashboardService: dashboardservice.ProvideDashboardService(
settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac, settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
folderSvc, folderSvc,
), ),
AccessControl: accesscontrolmock.New().WithDisabled(), AccessControl: accesscontrolmock.New().WithDisabled(),

View File

@ -982,13 +982,13 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
dashboardPermissions := accesscontrolmock.NewMockedPermissionsService() dashboardPermissions := accesscontrolmock.NewMockedPermissionsService()
features := featuremgmt.WithFeatures() features := featuremgmt.WithFeatures()
folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, dashboardStore, folderStore, db.InitTestDB(t), featuremgmt.WithFeatures()) folderSvc := folderimpl.ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()),
cfg, dashboardStore, folderStore, db.InitTestDB(t), featuremgmt.WithFeatures())
if dashboardService == nil { if dashboardService == nil {
dashboardService = service.ProvideDashboardService( dashboardService = service.ProvideDashboardService(
cfg, dashboardStore, folderStore, nil, features, cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
folderPermissions, dashboardPermissions, ac, ac, folderSvc,
folderSvc,
) )
} }
@ -1000,9 +1000,8 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
ProvisioningService: provisioningService, ProvisioningService: provisioningService,
AccessControl: accesscontrolmock.New(), AccessControl: accesscontrolmock.New(),
dashboardProvisioningService: service.ProvideDashboardService( dashboardProvisioningService: service.ProvideDashboardService(
cfg, dashboardStore, folderStore, nil, features, cfg, dashboardStore, nil, features, folderPermissions, dashboardPermissions,
folderPermissions, dashboardPermissions, ac, ac, folderSvc,
folderSvc,
), ),
DashboardService: dashboardService, DashboardService: dashboardService,
Features: featuremgmt.WithFeatures(), Features: featuremgmt.WithFeatures(),

View File

@ -45,7 +45,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
folderPermissionsService: folderPermissions, folderPermissionsService: folderPermissions,
dashboardPermissionsService: dashboardPermissions, dashboardPermissionsService: dashboardPermissions,
DashboardService: service.ProvideDashboardService( DashboardService: service.ProvideDashboardService(
settings, dashboardStore, foldertest.NewFakeFolderStore(t), nil, features, folderPermissions, dashboardPermissions, ac, settings, dashboardStore, nil, features, folderPermissions, dashboardPermissions, ac,
folderService, folderService,
), ),
AccessControl: accesscontrolmock.New().WithDisabled(), AccessControl: accesscontrolmock.New().WithDisabled(),

View File

@ -39,7 +39,7 @@ var (
) )
// NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope. // NewFolderNameScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:name:" into an uid based scope.
func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { func NewFolderNameScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeFoldersProvider.GetResourceScopeName("") prefix := ScopeFoldersProvider.GetResourceScopeName("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
if !strings.HasPrefix(scope, prefix) { if !strings.HasPrefix(scope, prefix) {
@ -49,7 +49,7 @@ func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc
if len(nsName) == 0 { if len(nsName) == 0 {
return nil, ac.ErrInvalidScope return nil, ac.ErrInvalidScope
} }
folder, err := folderDB.GetFolderByTitle(ctx, orgID, nsName) folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{Title: &nsName})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,7 +65,7 @@ func NewFolderNameScopeResolver(db Store, folderDB folder.FolderStore, folderSvc
} }
// NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope. // NewFolderIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:id:" into an uid based scope.
func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { func NewFolderIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeFoldersProvider.GetResourceScope("") prefix := ScopeFoldersProvider.GetResourceScope("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
if !strings.HasPrefix(scope, prefix) { if !strings.HasPrefix(scope, prefix) {
@ -81,7 +81,7 @@ func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc f
return []string{ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID)}, nil return []string{ScopeFoldersProvider.GetResourceScopeUID(ac.GeneralFolderUID)}, nil
} }
folder, err := folderDB.GetFolderByID(ctx, orgID, id) folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &id})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -98,7 +98,7 @@ func NewFolderIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc f
// NewFolderUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:uid:" // NewFolderUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "folders:uid:"
// into uid based scopes for folder and its parents // into uid based scopes for folder and its parents
func NewFolderUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { func NewFolderUIDScopeResolver(folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeFoldersProvider.GetResourceScopeUID("") prefix := ScopeFoldersProvider.GetResourceScopeUID("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
if !strings.HasPrefix(scope, prefix) { if !strings.HasPrefix(scope, prefix) {
@ -120,7 +120,7 @@ func NewFolderUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc
// NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:" // NewDashboardIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:id:"
// into uid based scopes for both dashboard and folder // into uid based scopes for both dashboard and folder
func NewDashboardIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { func NewDashboardIDScopeResolver(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeDashboardsProvider.GetResourceScope("") prefix := ScopeDashboardsProvider.GetResourceScope("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
if !strings.HasPrefix(scope, prefix) { if !strings.HasPrefix(scope, prefix) {
@ -132,18 +132,18 @@ func NewDashboardIDScopeResolver(db Store, folderDB folder.FolderStore, folderSv
return nil, err return nil, err
} }
dashboard, err := db.GetDashboard(ctx, &GetDashboardQuery{ID: id, OrgID: orgID}) dashboard, err := ds.GetDashboard(ctx, &GetDashboardQuery{ID: id, OrgID: orgID})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc) return resolveDashboardScope(ctx, orgID, dashboard, folderSvc)
}) })
} }
// NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:" // NewDashboardUIDScopeResolver provides an ScopeAttributeResolver that is able to convert a scope prefixed with "dashboards:uid:"
// into uid based scopes for both dashboard and folder // into uid based scopes for both dashboard and folder
func NewDashboardUIDScopeResolver(db Store, folderDB folder.FolderStore, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) { func NewDashboardUIDScopeResolver(ds DashboardService, folderSvc folder.Service) (string, ac.ScopeAttributeResolver) {
prefix := ScopeDashboardsProvider.GetResourceScopeUID("") prefix := ScopeDashboardsProvider.GetResourceScopeUID("")
return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) { return prefix, ac.ScopeAttributeResolverFunc(func(ctx context.Context, orgID int64, scope string) ([]string, error) {
if !strings.HasPrefix(scope, prefix) { if !strings.HasPrefix(scope, prefix) {
@ -155,16 +155,16 @@ func NewDashboardUIDScopeResolver(db Store, folderDB folder.FolderStore, folderS
return nil, err return nil, err
} }
dashboard, err := db.GetDashboard(ctx, &GetDashboardQuery{UID: uid, OrgID: orgID}) dashboard, err := ds.GetDashboard(ctx, &GetDashboardQuery{UID: uid, OrgID: orgID})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return resolveDashboardScope(ctx, db, folderDB, orgID, dashboard, folderSvc) return resolveDashboardScope(ctx, orgID, dashboard, folderSvc)
}) })
} }
func resolveDashboardScope(ctx context.Context, db Store, folderDB folder.FolderStore, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) { func resolveDashboardScope(ctx context.Context, orgID int64, dashboard *Dashboard, folderSvc folder.Service) ([]string, error) {
var folderUID string var folderUID string
if dashboard.FolderID < 0 { if dashboard.FolderID < 0 {
return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil return []string{ScopeDashboardsProvider.GetResourceScopeUID(dashboard.UID)}, nil
@ -173,7 +173,7 @@ func resolveDashboardScope(ctx context.Context, db Store, folderDB folder.Folder
if dashboard.FolderID == 0 { if dashboard.FolderID == 0 {
folderUID = ac.GeneralFolderUID folderUID = ac.GeneralFolderUID
} else { } else {
folder, err := folderDB.GetFolderByID(ctx, orgID, dashboard.FolderID) folder, err := folderSvc.Get(ctx, &folder.GetFolderQuery{OrgID: orgID, ID: &dashboard.FolderID})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,43 +19,30 @@ import (
func TestNewFolderNameScopeResolver(t *testing.T) { func TestNewFolderNameScopeResolver(t *testing.T) {
t.Run("prefix should be expected", func(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) {
prefix, _ := NewFolderNameScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) prefix, _ := NewFolderNameScopeResolver(foldertest.NewFakeService())
require.Equal(t, "folders:name:", prefix) require.Equal(t, "folders:name:", prefix)
}) })
t.Run("resolver should convert to uid scope", func(t *testing.T) { t.Run("resolver should convert to uid scope", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} folderService := foldertest.NewFakeService()
orgId := rand.Int63() orgId := rand.Int63()
title := "Very complex :title with: and /" + util.GenerateShortUID() title := "Very complex :title with: and /" + util.GenerateShortUID()
db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()} db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()}
folderService.ExpectedFolder = db
folderStore := foldertest.NewFakeFolderStore(t)
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
scope := "folders:name:" + title scope := "folders:name:" + title
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService()) _, resolver := NewFolderNameScopeResolver(folderService)
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, resolvedScopes, 1) require.Len(t, resolvedScopes, 1)
require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0]) require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0])
folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title)
}) })
t.Run("resolver should include inherited scopes if any", func(t *testing.T) { t.Run("resolver should include inherited scopes if any", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{}
orgId := rand.Int63() orgId := rand.Int63()
title := "Very complex :title with: and /" + util.GenerateShortUID() title := "Very complex :title with: and /" + util.GenerateShortUID()
db := &folder.Folder{Title: title, ID: rand.Int63(), UID: util.GenerateShortUID()}
folderStore := foldertest.NewFakeFolderStore(t)
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once()
scope := "folders:name:" + title scope := "folders:name:" + title
uid := util.GenerateShortUID()
folderSvc := foldertest.NewFakeService() folderSvc := foldertest.NewFakeService()
folderSvc.ExpectedFolders = []*folder.Folder{ folderSvc.ExpectedFolders = []*folder.Folder{
@ -66,44 +53,39 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
UID: "grandparent", UID: "grandparent",
}, },
} }
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, folderSvc) folderSvc.ExpectedFolder = &folder.Folder{Title: title, ID: rand.Int63(), UID: uid}
_, resolver := NewFolderNameScopeResolver(folderSvc)
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, resolvedScopes, 3) require.Len(t, resolvedScopes, 3)
if diff := cmp.Diff([]string{ if diff := cmp.Diff([]string{
fmt.Sprintf("folders:uid:%v", db.UID), fmt.Sprintf("folders:uid:%v", uid),
"folders:uid:parent", "folders:uid:parent",
"folders:uid:grandparent", "folders:uid:grandparent",
}, resolvedScopes); diff != "" { }, resolvedScopes); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff) t.Errorf("Result mismatch (-want +got):\n%s", diff)
} }
folderStore.AssertCalled(t, "GetFolderByTitle", mock.Anything, orgId, title)
}) })
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeService())
_, resolver := NewFolderNameScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123") _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:123")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
}) })
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} _, resolver := NewFolderNameScopeResolver(foldertest.NewFakeService())
_, resolver := NewFolderNameScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:") _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:name:")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
}) })
t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { t.Run("returns 'not found' if folder does not exist", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} folderService := foldertest.NewFakeService()
_, resolver := NewFolderNameScopeResolver(folderService)
folderStore := foldertest.NewFakeFolderStore(t)
_, resolver := NewFolderNameScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
orgId := rand.Int63() orgId := rand.Int63()
folderStore.On("GetFolderByTitle", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once() folderService.ExpectedError = ErrDashboardNotFound
scope := "folders:name:" + util.GenerateShortUID() scope := "folders:name:" + util.GenerateShortUID()
@ -115,35 +97,26 @@ func TestNewFolderNameScopeResolver(t *testing.T) {
func TestNewFolderIDScopeResolver(t *testing.T) { func TestNewFolderIDScopeResolver(t *testing.T) {
t.Run("prefix should be expected", func(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) {
prefix, _ := NewFolderIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) prefix, _ := NewFolderIDScopeResolver(foldertest.NewFakeService())
require.Equal(t, "folders:id:", prefix) require.Equal(t, "folders:id:", prefix)
}) })
t.Run("resolver should convert to uid scope", func(t *testing.T) { t.Run("resolver should convert to uid scope", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} folderSvc := foldertest.NewFakeService()
folderStore := foldertest.NewFakeFolderStore(t)
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
orgId := rand.Int63() orgId := rand.Int63()
uid := util.GenerateShortUID() uid := util.GenerateShortUID()
db := &folder.Folder{ID: rand.Int63(), UID: uid} db := &folder.Folder{ID: rand.Int63(), UID: uid}
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() folderSvc.ExpectedFolder = db
_, resolver := NewFolderIDScopeResolver(folderSvc)
scope := "folders:id:" + strconv.FormatInt(db.ID, 10) scope := "folders:id:" + strconv.FormatInt(db.ID, 10)
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, resolvedScopes, 1) require.Len(t, resolvedScopes, 1)
require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0]) require.Equal(t, fmt.Sprintf("folders:uid:%v", db.UID), resolvedScopes[0])
folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID)
}) })
t.Run("resolver should should include inherited scopes if any", func(t *testing.T) { t.Run("resolver should should include inherited scopes if any", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{}
folderStore := foldertest.NewFakeFolderStore(t)
folderSvc := foldertest.NewFakeService() folderSvc := foldertest.NewFakeService()
folderSvc.ExpectedFolders = []*folder.Folder{ folderSvc.ExpectedFolders = []*folder.Folder{
{ {
@ -153,13 +126,12 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
UID: "grandparent", UID: "grandparent",
}, },
} }
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, folderSvc) _, resolver := NewFolderIDScopeResolver(folderSvc)
orgId := rand.Int63() orgId := rand.Int63()
uid := util.GenerateShortUID() uid := util.GenerateShortUID()
db := &folder.Folder{ID: rand.Int63(), UID: uid} db := &folder.Folder{ID: rand.Int63(), UID: uid}
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(db, nil).Once() folderSvc.ExpectedFolder = db
scope := "folders:id:" + strconv.FormatInt(db.ID, 10) scope := "folders:id:" + strconv.FormatInt(db.ID, 10)
@ -174,12 +146,9 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
}, resolvedScopes); diff != "" { }, resolvedScopes); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff) t.Errorf("Result mismatch (-want +got):\n%s", diff)
} }
folderStore.AssertCalled(t, "GetFolderByID", mock.Anything, orgId, db.ID)
}) })
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService())
_, resolver := NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123") _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:uid:123")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
@ -187,10 +156,9 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
t.Run("resolver should convert id 0 to general uid scope", func(t *testing.T) { t.Run("resolver should convert id 0 to general uid scope", func(t *testing.T) {
var ( var (
dashboardStore = &FakeDashboardStore{} orgId = rand.Int63()
orgId = rand.Int63() scope = "folders:id:0"
scope = "folders:id:0" _, resolver = NewFolderIDScopeResolver(foldertest.NewFakeService())
_, resolver = NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
) )
resolved, err := resolver.Resolve(context.Background(), orgId, scope) resolved, err := resolver.Resolve(context.Background(), orgId, scope)
@ -201,20 +169,17 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
}) })
t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) { t.Run("resolver should fail if resource of input scope is empty", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} _, resolver := NewFolderIDScopeResolver(foldertest.NewFakeService())
_, resolver := NewFolderIDScopeResolver(dashboardStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:") _, err := resolver.Resolve(context.Background(), rand.Int63(), "folders:id:")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
}) })
t.Run("returns 'not found' if folder does not exist", func(t *testing.T) { t.Run("returns 'not found' if folder does not exist", func(t *testing.T) {
dashboardStore := &FakeDashboardStore{} svc := foldertest.NewFakeService()
folderStore := foldertest.NewFakeFolderStore(t) svc.ExpectedError = ErrDashboardNotFound
_, resolver := NewFolderIDScopeResolver(svc)
_, resolver := NewFolderIDScopeResolver(dashboardStore, folderStore, foldertest.NewFakeService())
orgId := rand.Int63() orgId := rand.Int63()
folderStore.On("GetFolderByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, ErrDashboardNotFound).Once()
scope := "folders:id:10" scope := "folders:id:10"
resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgId, scope)
@ -225,22 +190,21 @@ func TestNewFolderIDScopeResolver(t *testing.T) {
func TestNewDashboardIDScopeResolver(t *testing.T) { func TestNewDashboardIDScopeResolver(t *testing.T) {
t.Run("prefix should be expected", func(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) {
prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) prefix, _ := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
require.Equal(t, "dashboards:id:", prefix) require.Equal(t, "dashboards:id:", prefix)
}) })
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) { t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
store := &FakeDashboardStore{} dashSvc := NewFakeDashboardService(t)
folderStore := foldertest.NewFakeFolderStore(t) folderService := foldertest.NewFakeService()
_, resolver := NewDashboardIDScopeResolver(dashSvc, folderService)
_, resolver := NewDashboardIDScopeResolver(store, folderStore, foldertest.NewFakeService())
orgID := rand.Int63() orgID := rand.Int63()
folder := &folder.Folder{ID: 2, UID: "2"} folder := &folder.Folder{ID: 2, UID: "2"}
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once() folderService.ExpectedFolder = folder
scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10)) scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10))
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
@ -251,9 +215,7 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
}) })
t.Run("resolver should inlude inherited scopes if any", func(t *testing.T) { t.Run("resolver should inlude inherited scopes if any", func(t *testing.T) {
store := &FakeDashboardStore{} dashSvc := &FakeDashboardService{}
folderStore := foldertest.NewFakeFolderStore(t)
folderSvc := foldertest.NewFakeService() folderSvc := foldertest.NewFakeService()
folderSvc.ExpectedFolders = []*folder.Folder{ folderSvc.ExpectedFolders = []*folder.Folder{
{ {
@ -263,14 +225,13 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
UID: "grandparent", UID: "grandparent",
}, },
} }
_, resolver := NewDashboardIDScopeResolver(store, folderStore, folderSvc) _, resolver := NewDashboardIDScopeResolver(dashSvc, folderSvc)
orgID := rand.Int63() orgID := rand.Int63()
folder := &folder.Folder{ID: 2, UID: "2"} folder := &folder.Folder{ID: 2, UID: "2"}
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
folderSvc.ExpectedFolder = folder
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once() dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10)) scope := ac.Scope("dashboards", "id", strconv.FormatInt(dashboard.ID, 10))
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
@ -288,17 +249,17 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
}) })
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
_, resolver := NewDashboardIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) _, resolver := NewDashboardIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123") _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:uid:123")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
}) })
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) { t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
store := &FakeDashboardStore{} dashSvc := &FakeDashboardService{}
_, resolver := NewDashboardIDScopeResolver(store, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) _, resolver := NewDashboardIDScopeResolver(dashSvc, foldertest.NewFakeService())
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) dashSvc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "id", "1")) resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "id", "1"))
require.NoError(t, err) require.NoError(t, err)
@ -310,21 +271,20 @@ func TestNewDashboardIDScopeResolver(t *testing.T) {
func TestNewDashboardUIDScopeResolver(t *testing.T) { func TestNewDashboardUIDScopeResolver(t *testing.T) {
t.Run("prefix should be expected", func(t *testing.T) { t.Run("prefix should be expected", func(t *testing.T) {
prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) prefix, _ := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
require.Equal(t, "dashboards:uid:", prefix) require.Equal(t, "dashboards:uid:", prefix)
}) })
t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) { t.Run("resolver should convert to uid dashboard and folder scope", func(t *testing.T) {
store := &FakeDashboardStore{} service := &FakeDashboardService{}
folderStore := foldertest.NewFakeFolderStore(t) folderSvc := foldertest.NewFakeService()
_, resolver := NewDashboardUIDScopeResolver(store, folderStore, foldertest.NewFakeService()) _, resolver := NewDashboardUIDScopeResolver(service, folderSvc)
orgID := rand.Int63() orgID := rand.Int63()
folder := &folder.Folder{ID: 2, UID: "2"} folder := &folder.Folder{ID: 2, UID: "2"}
folderSvc.ExpectedFolder = folder
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
scope := ac.Scope("dashboards", "uid", dashboard.UID) scope := ac.Scope("dashboards", "uid", dashboard.UID)
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
@ -335,9 +295,7 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
}) })
t.Run("resolver should include inherited scopes if any", func(t *testing.T) { t.Run("resolver should include inherited scopes if any", func(t *testing.T) {
store := &FakeDashboardStore{} svc := &FakeDashboardService{}
folderStore := foldertest.NewFakeFolderStore(t)
folderSvc := foldertest.NewFakeService() folderSvc := foldertest.NewFakeService()
folderSvc.ExpectedFolders = []*folder.Folder{ folderSvc.ExpectedFolders = []*folder.Folder{
{ {
@ -348,14 +306,13 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
}, },
} }
_, resolver := NewDashboardUIDScopeResolver(store, folderStore, folderSvc) _, resolver := NewDashboardUIDScopeResolver(svc, folderSvc)
orgID := rand.Int63() orgID := rand.Int63()
folder := &folder.Folder{ID: 2, UID: "2"} folder := &folder.Folder{ID: 2, UID: "2"}
folderSvc.ExpectedFolder = folder
dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: folder.ID, UID: "1"}
svc.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil).Once()
folderStore.On("GetFolderByID", mock.Anything, orgID, folder.ID).Return(folder, nil).Once()
scope := ac.Scope("dashboards", "uid", dashboard.UID) scope := ac.Scope("dashboards", "uid", dashboard.UID)
resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope) resolvedScopes, err := resolver.Resolve(context.Background(), orgID, scope)
@ -373,17 +330,17 @@ func TestNewDashboardUIDScopeResolver(t *testing.T) {
}) })
t.Run("resolver should fail if input scope is not expected", func(t *testing.T) { t.Run("resolver should fail if input scope is not expected", func(t *testing.T) {
_, resolver := NewDashboardUIDScopeResolver(&FakeDashboardStore{}, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) _, resolver := NewDashboardUIDScopeResolver(&FakeDashboardService{}, foldertest.NewFakeService())
_, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123") _, err := resolver.Resolve(context.Background(), rand.Int63(), "dashboards:id:123")
require.ErrorIs(t, err, ac.ErrInvalidScope) require.ErrorIs(t, err, ac.ErrInvalidScope)
}) })
t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) { t.Run("resolver should convert folderID 0 to general uid scope for the folder scope", func(t *testing.T) {
store := &FakeDashboardStore{} service := &FakeDashboardService{}
_, resolver := NewDashboardUIDScopeResolver(store, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()) _, resolver := NewDashboardUIDScopeResolver(service, foldertest.NewFakeService())
dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"} dashboard := &Dashboard{ID: 1, FolderID: 0, UID: "1"}
store.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil) service.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "uid", "1")) resolved, err := resolver.Resolve(context.Background(), 1, ac.Scope("dashboards", "uid", "1"))
require.NoError(t, err) require.NoError(t, err)

View File

@ -40,7 +40,7 @@ type DashboardServiceImpl struct {
cfg *setting.Cfg cfg *setting.Cfg
log log.Logger log log.Logger
dashboardStore dashboards.Store dashboardStore dashboards.Store
folderStore folder.FolderStore folderService folder.Service
dashAlertExtractor alerting.DashAlertExtractor dashAlertExtractor alerting.DashAlertExtractor
features featuremgmt.FeatureToggles features featuremgmt.FeatureToggles
folderPermissions accesscontrol.FolderPermissionsService folderPermissions accesscontrol.FolderPermissionsService
@ -50,15 +50,12 @@ type DashboardServiceImpl struct {
// This is the uber service that implements a three smaller services // This is the uber service that implements a three smaller services
func ProvideDashboardService( func ProvideDashboardService(
cfg *setting.Cfg, dashboardStore dashboards.Store, folderStore folder.FolderStore, dashAlertExtractor alerting.DashAlertExtractor, cfg *setting.Cfg, dashboardStore dashboards.Store, dashAlertExtractor alerting.DashAlertExtractor,
features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService, features featuremgmt.FeatureToggles, folderPermissionsService accesscontrol.FolderPermissionsService,
dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl, dashboardPermissionsService accesscontrol.DashboardPermissionsService, ac accesscontrol.AccessControl,
folderSvc folder.Service, folderSvc folder.Service,
) *DashboardServiceImpl { ) *DashboardServiceImpl {
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashboardStore, folderStore, folderSvc)) dashSvc := &DashboardServiceImpl{
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardStore, folderStore, folderSvc))
return &DashboardServiceImpl{
cfg: cfg, cfg: cfg,
log: log.New("dashboard-service"), log: log.New("dashboard-service"),
dashboardStore: dashboardStore, dashboardStore: dashboardStore,
@ -67,7 +64,13 @@ func ProvideDashboardService(
folderPermissions: folderPermissionsService, folderPermissions: folderPermissionsService,
dashboardPermissions: dashboardPermissionsService, dashboardPermissions: dashboardPermissionsService,
ac: ac, ac: ac,
folderService: folderSvc,
} }
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardIDScopeResolver(dashSvc, folderSvc))
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashSvc, folderSvc))
return dashSvc
} }
func (dr *DashboardServiceImpl) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) { func (dr *DashboardServiceImpl) GetProvisionedDashboardData(ctx context.Context, name string) ([]*dashboards.DashboardProvisioning, error) {
@ -628,7 +631,7 @@ func (dr DashboardServiceImpl) CountDashboardsInFolder(ctx context.Context, quer
return 0, err return 0, err
} }
folder, err := dr.folderStore.GetFolderByUID(ctx, u.OrgID, query.FolderUID) folder, err := dr.folderService.Get(ctx, &folder.GetFolderQuery{UID: &query.FolderUID, OrgID: u.OrgID})
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -15,7 +15,6 @@ import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database" "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
"github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/org"
@ -827,9 +826,8 @@ func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionSc
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err) require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := ProvideDashboardService( service := ProvideDashboardService(
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, cfg, dashboardStore, &dummyDashAlertExtractor{},
featuremgmt.WithFeatures(), featuremgmt.WithFeatures(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
@ -888,9 +886,8 @@ func callSaveWithResult(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSt
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err) require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := ProvideDashboardService( service := ProvideDashboardService(
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, cfg, dashboardStore, &dummyDashAlertExtractor{},
featuremgmt.WithFeatures(), featuremgmt.WithFeatures(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
@ -911,9 +908,8 @@ func callSaveWithError(t *testing.T, cmd dashboards.SaveDashboardCommand, sqlSto
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err) require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := ProvideDashboardService( service := ProvideDashboardService(
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, cfg, dashboardStore, &dummyDashAlertExtractor{},
featuremgmt.WithFeatures(), featuremgmt.WithFeatures(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
@ -952,9 +948,8 @@ func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlSto
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err) require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := ProvideDashboardService( service := ProvideDashboardService(
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, cfg, dashboardStore, &dummyDashAlertExtractor{},
featuremgmt.WithFeatures(), featuremgmt.WithFeatures(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
@ -994,9 +989,8 @@ func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore db.DB) *da
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService) dashboardStore, err := database.ProvideDashboardStore(sqlStore, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, cfg), quotaService)
require.NoError(t, err) require.NoError(t, err)
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := ProvideDashboardService( service := ProvideDashboardService(
cfg, dashboardStore, folderStore, &dummyDashAlertExtractor{}, cfg, dashboardStore, &dummyDashAlertExtractor{},
featuremgmt.WithFeatures(), featuremgmt.WithFeatures(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),
accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(),

View File

@ -25,13 +25,13 @@ func TestDashboardService(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{} fakeStore := dashboards.FakeDashboardStore{}
defer fakeStore.AssertExpectations(t) defer fakeStore.AssertExpectations(t)
folderStore := foldertest.NewFakeFolderStore(t) folderSvc := foldertest.NewFakeService()
service := &DashboardServiceImpl{ service := &DashboardServiceImpl{
cfg: setting.NewCfg(), cfg: setting.NewCfg(),
log: log.New("test.logger"), log: log.New("test.logger"),
dashboardStore: &fakeStore, dashboardStore: &fakeStore,
folderStore: folderStore, folderService: folderSvc,
dashAlertExtractor: &dummyDashAlertExtractor{}, dashAlertExtractor: &dummyDashAlertExtractor{},
} }
@ -230,13 +230,11 @@ func TestDashboardService(t *testing.T) {
}) })
t.Run("Count dashboards in folder", func(t *testing.T) { t.Run("Count dashboards in folder", func(t *testing.T) {
folderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil)
fakeStore.On("CountDashboardsInFolder", mock.Anything, mock.AnythingOfType("*dashboards.CountDashboardsInFolderRequest")).Return(int64(3), nil) fakeStore.On("CountDashboardsInFolder", mock.Anything, mock.AnythingOfType("*dashboards.CountDashboardsInFolderRequest")).Return(int64(3), nil)
folderSvc.ExpectedFolder = &folder.Folder{ID: 1}
// set up a ctx with signed in user // set up a ctx with signed in user
ctx := context.Background()
usr := &user.SignedInUser{UserID: 1} usr := &user.SignedInUser{UserID: 1}
ctx = appcontext.WithUser(ctx, usr) ctx := appcontext.WithUser(context.Background(), usr)
count, err := service.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderQuery{FolderUID: "i am a folder"}) count, err := service.CountDashboardsInFolder(ctx, &dashboards.CountDashboardsInFolderQuery{FolderUID: "i am a folder"})
require.NoError(t, err) require.NoError(t, err)

View File

@ -62,9 +62,9 @@ func ProvideService(
srv.DBMigration(db) srv.DBMigration(db)
} }
ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(dashboardStore, folderStore, srv)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderNameScopeResolver(srv))
ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(dashboardStore, folderStore, srv)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderIDScopeResolver(srv))
ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(dashboardStore, folderStore, srv)) ac.RegisterScopeAttributeResolver(dashboards.NewFolderUIDScopeResolver(srv))
return srv return srv
} }

View File

@ -602,21 +602,6 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
OrgID: 1, OrgID: 1,
}) })
require.NoError(t, err) require.NoError(t, err)
ac := accesscontrolmock.New().WithPermissions(permissions)
// TODO replace with actual folder store implementation after resolving import cycles
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashStore, foldertest.NewFakeFolderStore(t), foldertest.NewFakeService()))
license := licensingtest.NewFakeLicensing()
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
teamSvc := teamimpl.ProvideService(store, store.Cfg)
userSvc, err := userimpl.ProvideService(store, nil, store.Cfg, nil, nil, quotatest.New(false, nil), supportbundlestest.NewFakeBundleService())
require.NoError(t, err)
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
require.NoError(t, err)
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
require.NoError(t, err)
if dashboardSvc == nil { if dashboardSvc == nil {
fakeDashboardService := dashboards.NewFakeDashboardService(t) fakeDashboardService := dashboards.NewFakeDashboardService(t)
qResult := &dashboards.Dashboard{} qResult := &dashboards.Dashboard{}
@ -631,6 +616,22 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
dashboardSvc = fakeDashboardService dashboardSvc = fakeDashboardService
} }
ac := accesscontrolmock.New().WithPermissions(permissions)
// TODO replace with actual folder store implementation after resolving import cycles
ac.RegisterScopeAttributeResolver(dashboards.NewDashboardUIDScopeResolver(dashboardSvc, foldertest.NewFakeService()))
license := licensingtest.NewFakeLicensing()
license.On("FeatureEnabled", "accesscontrol.enforcement").Return(true).Maybe()
teamSvc := teamimpl.ProvideService(store, store.Cfg)
userSvc, err := userimpl.ProvideService(store, nil, store.Cfg, nil, nil, quotatest.New(false, nil), supportbundlestest.NewFakeBundleService())
require.NoError(t, err)
folderPermissions, err := ossaccesscontrol.ProvideFolderPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
require.NoError(t, err)
dashboardPermissions, err := ossaccesscontrol.ProvideDashboardPermissions(
setting.NewCfg(), routing.NewRouteRegister(), store, ac, license, &dashboards.FakeDashboardStore{}, foldertest.NewFakeService(), ac, teamSvc, userSvc)
require.NoError(t, err)
g, err := NewAccessControlDashboardGuardian(context.Background(), dash.ID, &user.SignedInUser{OrgID: 1}, store, ac, folderPermissions, dashboardPermissions, dashboardSvc) g, err := NewAccessControlDashboardGuardian(context.Background(), dash.ID, &user.SignedInUser{OrgID: 1}, store, ac, folderPermissions, dashboardPermissions, dashboardSvc)
require.NoError(t, err) require.NoError(t, err)
g.dashboard = dash g.dashboard = dash
@ -639,7 +640,7 @@ func setupAccessControlGuardianTest(t *testing.T, uid string, permissions []acce
func testDashSvc(t *testing.T) dashboards.DashboardService { func testDashSvc(t *testing.T) dashboards.DashboardService {
dashSvc := dashboards.NewFakeDashboardService(t) dashSvc := dashboards.NewFakeDashboardService(t)
var d *dashboards.Dashboard d := &dashboards.Dashboard{}
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Run(func(args mock.Arguments) { dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Run(func(args mock.Arguments) {
d := dashboards.NewDashboard("mocked") d := dashboards.NewDashboard("mocked")
d.ID = 1 d.ID = 1

View File

@ -294,9 +294,8 @@ func createDashboard(t *testing.T, sqlStore db.DB, user user.SignedInUser, dash
ac := acmock.New() ac := acmock.New()
folderPermissions := acmock.NewMockedPermissionsService() folderPermissions := acmock.NewMockedPermissionsService()
dashboardPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService()
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := dashboardservice.ProvideDashboardService( service := dashboardservice.ProvideDashboardService(
cfg, dashboardStore, folderStore, dashAlertExtractor, cfg, dashboardStore, dashAlertExtractor,
features, folderPermissions, dashboardPermissions, ac, features, folderPermissions, dashboardPermissions, ac,
foldertest.NewFakeService(), foldertest.NewFakeService(),
) )
@ -442,7 +441,7 @@ func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioCo
dashboardPermissions := acmock.NewMockedPermissionsService() dashboardPermissions := acmock.NewMockedPermissionsService()
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
dashboardService := dashboardservice.ProvideDashboardService( dashboardService := dashboardservice.ProvideDashboardService(
sqlStore.Cfg, dashboardStore, folderStore, nil, sqlStore.Cfg, dashboardStore, nil,
features, folderPermissions, dashboardPermissions, ac, features, folderPermissions, dashboardPermissions, ac,
foldertest.NewFakeService(), foldertest.NewFakeService(),
) )

View File

@ -706,9 +706,8 @@ func createDashboard(t *testing.T, sqlStore db.DB, user *user.SignedInUser, dash
require.NoError(t, err) require.NoError(t, err)
dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil) dashAlertService := alerting.ProvideDashAlertExtractorService(nil, nil, nil)
ac := acmock.New() ac := acmock.New()
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
service := dashboardservice.ProvideDashboardService( service := dashboardservice.ProvideDashboardService(
cfg, dashboardStore, folderStore, dashAlertService, cfg, dashboardStore, dashAlertService,
featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac, featuremgmt.WithFeatures(), acmock.NewMockedPermissionsService(), acmock.NewMockedPermissionsService(), ac,
foldertest.NewFakeService(), foldertest.NewFakeService(),
) )

View File

@ -82,7 +82,7 @@ func SetupTestEnv(tb testing.TB, baseInterval time.Duration) (*ngalert.AlertNG,
folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore) folderStore := folderimpl.ProvideDashboardFolderStore(sqlStore)
dashboardService := dashboardservice.ProvideDashboardService( dashboardService := dashboardservice.ProvideDashboardService(
cfg, dashboardStore, folderStore, nil, cfg, dashboardStore, nil,
features, folderPermissions, dashboardPermissions, ac, features, folderPermissions, dashboardPermissions, ac,
foldertest.NewFakeService(), foldertest.NewFakeService(),
) )