Nested Folders: Support getting of nested folder in folder service wh… (#58597)

* Nested Folders: Support getting of nested folder in folder service when feature flag is set

* Fix lint

* Fix some tests

* Fix ngalert test

* ngalert fix

* Fix API tests

* Fix some tests and lint

* Fix lint 2

* Fix library elements and panels

* Add access control to get folder

* Cleanup and minor test change
This commit is contained in:
idafurjes
2022-11-11 14:28:24 +01:00
committed by GitHub
parent 88a829e103
commit 080ea88af7
39 changed files with 372 additions and 420 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardsvc "github.com/grafana/grafana/pkg/services/dashboards/service"
@ -79,26 +80,26 @@ func TestIntegrationFolderService(t *testing.T) {
folderId := rand.Int63()
folderUID := util.GenerateShortUID()
f := models.NewFolder("Folder")
f.Id = folderId
f.Uid = folderUID
f := folder.NewFolder("Folder", "")
f.ID = folderId
f.UID = folderUID
dashStore.On("GetFolderByID", mock.Anything, orgID, folderId).Return(f, nil)
dashStore.On("GetFolderByUID", mock.Anything, orgID, folderUID).Return(f, nil)
t.Run("When get folder by id should return access denied error", func(t *testing.T) {
_, err := service.GetFolderByID(context.Background(), usr, folderId, orgID)
_, err := service.getFolderByID(context.Background(), usr, folderId, orgID)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
t.Run("When get folder by id, with id = 0 should return default folder", func(t *testing.T) {
folder, err := service.GetFolderByID(context.Background(), usr, 0, orgID)
foldr, err := service.getFolderByID(context.Background(), usr, 0, orgID)
require.NoError(t, err)
require.Equal(t, folder, &models.Folder{Id: 0, Title: "General"})
require.Equal(t, foldr, &folder.Folder{ID: 0, Title: "General"})
})
t.Run("When get folder by uid should return access denied error", func(t *testing.T) {
_, err := service.GetFolderByUID(context.Background(), usr, orgID, folderUID)
_, err := service.getFolderByUID(context.Background(), usr, orgID, folderUID)
require.Equal(t, err, dashboards.ErrFolderAccessDenied)
})
@ -157,7 +158,7 @@ func TestIntegrationFolderService(t *testing.T) {
t.Run("When creating folder should not return access denied error", func(t *testing.T) {
dash := models.NewDashboardFolder("Test-Folder")
dash.Id = rand.Int63()
f := models.DashboardToFolder(dash)
f := folder.FromDashboard(dash)
dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*models.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil)
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(dash, nil).Once()
@ -170,7 +171,7 @@ func TestIntegrationFolderService(t *testing.T) {
UID: "someuid",
})
require.NoError(t, err)
require.Equal(t, f, actualFolder.ToLegacyModel())
require.Equal(t, f, actualFolder)
})
t.Run("When creating folder should return error if uid is general", func(t *testing.T) {
@ -190,7 +191,7 @@ func TestIntegrationFolderService(t *testing.T) {
dashboardFolder := models.NewDashboardFolder("Folder")
dashboardFolder.Id = rand.Int63()
dashboardFolder.Uid = util.GenerateShortUID()
f := models.DashboardToFolder(dashboardFolder)
f := folder.FromDashboard(dashboardFolder)
dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*models.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil)
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(dashboardFolder, nil)
@ -207,10 +208,10 @@ func TestIntegrationFolderService(t *testing.T) {
})
t.Run("When deleting folder by uid should not return access denied error", func(t *testing.T) {
f := models.NewFolder(util.GenerateShortUID())
f.Id = rand.Int63()
f.Uid = util.GenerateShortUID()
dashStore.On("GetFolderByUID", mock.Anything, orgID, f.Uid).Return(f, nil)
f := folder.NewFolder(util.GenerateShortUID(), "")
f.ID = rand.Int63()
f.UID = util.GenerateShortUID()
dashStore.On("GetFolderByUID", mock.Anything, orgID, f.UID).Return(f, nil)
var actualCmd *models.DeleteDashboardCommand
dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
@ -221,13 +222,13 @@ func TestIntegrationFolderService(t *testing.T) {
ctx := context.Background()
ctx = appcontext.WithUser(ctx, usr)
err := service.DeleteFolder(ctx, &folder.DeleteFolderCommand{
UID: f.Uid,
UID: f.UID,
OrgID: orgID,
ForceDeleteRules: expectedForceDeleteRules,
})
require.NoError(t, err)
require.NotNil(t, actualCmd)
require.Equal(t, f.Id, actualCmd.Id)
require.Equal(t, f.ID, actualCmd.Id)
require.Equal(t, orgID, actualCmd.OrgId)
require.Equal(t, expectedForceDeleteRules, actualCmd.ForceDeleteFolderRules)
})
@ -242,33 +243,33 @@ func TestIntegrationFolderService(t *testing.T) {
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true})
t.Run("When get folder by id should return folder", func(t *testing.T) {
expected := models.NewFolder(util.GenerateShortUID())
expected.Id = rand.Int63()
expected := folder.NewFolder(util.GenerateShortUID(), "")
expected.ID = rand.Int63()
dashStore.On("GetFolderByID", mock.Anything, orgID, expected.Id).Return(expected, nil)
dashStore.On("GetFolderByID", mock.Anything, orgID, expected.ID).Return(expected, nil)
actual, err := service.GetFolderByID(context.Background(), usr, expected.Id, orgID)
actual, err := service.getFolderByID(context.Background(), usr, expected.ID, orgID)
require.Equal(t, expected, actual)
require.NoError(t, err)
})
t.Run("When get folder by uid should return folder", func(t *testing.T) {
expected := models.NewFolder(util.GenerateShortUID())
expected.Uid = util.GenerateShortUID()
expected := folder.NewFolder(util.GenerateShortUID(), "")
expected.UID = util.GenerateShortUID()
dashStore.On("GetFolderByUID", mock.Anything, orgID, expected.Uid).Return(expected, nil)
dashStore.On("GetFolderByUID", mock.Anything, orgID, expected.UID).Return(expected, nil)
actual, err := service.GetFolderByUID(context.Background(), usr, orgID, expected.Uid)
actual, err := service.getFolderByUID(context.Background(), usr, orgID, expected.UID)
require.Equal(t, expected, actual)
require.NoError(t, err)
})
t.Run("When get folder by title should return folder", func(t *testing.T) {
expected := models.NewFolder("TEST-" + util.GenerateShortUID())
expected := folder.NewFolder("TEST-"+util.GenerateShortUID(), "")
dashStore.On("GetFolderByTitle", mock.Anything, orgID, expected.Title).Return(expected, nil)
actual, err := service.GetFolderByTitle(context.Background(), usr, orgID, expected.Title)
actual, err := service.getFolderByTitle(context.Background(), usr, orgID, expected.Title)
require.Equal(t, expected, actual)
require.NoError(t, err)
})
@ -311,7 +312,7 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) {
mock.AnythingOfType("bool"), mock.AnythingOfType("bool")).Return(&models.SaveDashboardCommand{}, nil)
dashStore := dashboards.FakeDashboardStore{}
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(&models.Dashboard{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&folder.Folder{}, nil)
cfg := setting.NewCfg()
cfg.RBACEnabled = false
nestedFoldersEnabled := true
@ -338,18 +339,6 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) {
require.NotNil(t, res.UID)
})
t.Run("delete folder", func(t *testing.T) {
folderStore.ExpectedFolder = &folder.Folder{}
err := folderService.Delete(context.Background(), &folder.DeleteFolderCommand{})
require.NoError(t, err)
})
t.Run("get folder", func(t *testing.T) {
folderStore.ExpectedFolder = &folder.Folder{}
_, err := folderService.Get(context.Background(), &folder.GetFolderQuery{})
require.NoError(t, err)
})
t.Run("get parents folder", func(t *testing.T) {
folderStore.ExpectedFolder = &folder.Folder{}
_, err := folderService.GetParents(context.Background(), &folder.GetParentsQuery{})
@ -378,12 +367,6 @@ func TestNestedFolderServiceFeatureToggle(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 4, len(res))
})
t.Run("move folder", func(t *testing.T) {
folderStore.ExpectedFolder = &folder.Folder{}
_, err := folderService.Move(context.Background(), &folder.MoveFolderCommand{})
require.NoError(t, err)
})
}
func TestNestedFolderService(t *testing.T) {
@ -412,7 +395,7 @@ func TestNestedFolderService(t *testing.T) {
mock.Anything, mock.AnythingOfType("*dashboards.SaveDashboardDTO"),
mock.AnythingOfType("bool"), mock.AnythingOfType("bool")).Return(&models.SaveDashboardCommand{}, nil)
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(&models.Dashboard{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&folder.Folder{}, nil)
ctx = appcontext.WithUser(ctx, usr)
_, err := foldersvc.Create(ctx, &folder.CreateFolderCommand{
@ -430,7 +413,7 @@ func TestNestedFolderService(t *testing.T) {
dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
actualCmd = args.Get(1).(*models.DeleteDashboardCommand)
}).Return(nil).Once()
dashStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil)
g := guardian.New
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true})
@ -463,6 +446,9 @@ func TestNestedFolderService(t *testing.T) {
dashboardStore: dashStore,
store: store,
features: features,
accessControl: actest.FakeAccessControl{
ExpectedEvaluate: true,
},
}
t.Run("create, no error", func(t *testing.T) {
@ -471,7 +457,7 @@ func TestNestedFolderService(t *testing.T) {
mock.Anything, mock.AnythingOfType("*dashboards.SaveDashboardDTO"),
mock.AnythingOfType("bool"), mock.AnythingOfType("bool")).Return(&models.SaveDashboardCommand{}, nil)
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(&models.Dashboard{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&folder.Folder{}, nil)
ctx = appcontext.WithUser(ctx, usr)
_, err := foldersvc.Create(ctx, &folder.CreateFolderCommand{
OrgID: orgID,
@ -493,8 +479,8 @@ func TestNestedFolderService(t *testing.T) {
mock.Anything, mock.AnythingOfType("*dashboards.SaveDashboardDTO"),
mock.AnythingOfType("bool"), mock.AnythingOfType("bool")).Return(&models.SaveDashboardCommand{}, nil)
dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("models.SaveDashboardCommand")).Return(&models.Dashboard{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&models.Folder{}, nil)
dashStore.On("GetFolderByID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("int64")).Return(&folder.Folder{}, nil)
dashStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil)
// return an error from the folder store
store.ExpectedError = errors.New("FAILED")