|
|
|
@@ -12,7 +12,6 @@ import (
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/appcontext"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db/dbtest"
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
@@ -322,7 +321,7 @@ func TestIntegrationFolderService(t *testing.T) {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestIntegrationDeleteNestedFolders(t *testing.T) {
|
|
|
|
|
func TestIntegrationNestedFolderService(t *testing.T) {
|
|
|
|
|
if testing.Short() {
|
|
|
|
|
t.Skip("skipping integration test")
|
|
|
|
|
}
|
|
|
|
@@ -347,6 +346,7 @@ func TestIntegrationDeleteNestedFolders(t *testing.T) {
|
|
|
|
|
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
|
|
|
|
|
db: db,
|
|
|
|
|
accessControl: acimpl.ProvideAccessControl(cfg),
|
|
|
|
|
registry: make(map[string]folder.RegistryService),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{
|
|
|
|
@@ -358,77 +358,170 @@ func TestIntegrationDeleteNestedFolders(t *testing.T) {
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t.Run("With nested folder feature flag on", func(t *testing.T) {
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
t.Run("Should get descendant counts", func(t *testing.T) {
|
|
|
|
|
ac := acmock.New()
|
|
|
|
|
folderPermissions := acmock.NewMockedPermissionsService()
|
|
|
|
|
dashboardPermissions := acmock.NewMockedPermissionsService()
|
|
|
|
|
depth := 5
|
|
|
|
|
t.Run("With nested folder feature flag on", func(t *testing.T) {
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
|
|
|
|
|
serviceWithFlagOn.store = nestedFolderStore
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, 3, "", createCmd)
|
|
|
|
|
_, err := service.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, nil, featuresFlagOn, folderPermissions, dashboardPermissions, ac, serviceWithFlagOn)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
deleteCmd := folder.DeleteFolderCommand{
|
|
|
|
|
UID: ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
err = serviceWithFlagOn.Delete(context.Background(), &deleteCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOn", createCmd)
|
|
|
|
|
|
|
|
|
|
for i, uid := range ancestorUIDs {
|
|
|
|
|
// dashboard table
|
|
|
|
|
_, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, uid)
|
|
|
|
|
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
|
|
|
|
|
// folder table
|
|
|
|
|
_, err = serviceWithFlagOn.store.Get(context.Background(), folder.GetFolderQuery{UID: &ancestorUIDs[i], OrgID: orgID})
|
|
|
|
|
require.ErrorIs(t, err, folder.ErrFolderNotFound)
|
|
|
|
|
}
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorUIDs[0])
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
subfolder, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorUIDs[1])
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in parent", orgID, parent.ID, "prod")
|
|
|
|
|
_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in subfolder", orgID, subfolder.ID, "prod")
|
|
|
|
|
|
|
|
|
|
countCmd := folder.GetDescendantCountsQuery{
|
|
|
|
|
UID: &ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
m, err := serviceWithFlagOn.GetDescendantCounts(context.Background(), &countCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, m["folder"], int64(depth-1))
|
|
|
|
|
require.Equal(t, m["dashboard"], int64(2))
|
|
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
for _, uid := range ancestorUIDs {
|
|
|
|
|
err := serviceWithFlagOn.store.Delete(context.Background(), uid, orgID)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
t.Run("With nested folder feature flag off", func(t *testing.T) {
|
|
|
|
|
featuresFlagOff := featuremgmt.WithFeatures()
|
|
|
|
|
dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOff, tagimpl.ProvideService(db, db.Cfg), quotaService)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
nestedFolderStore := ProvideStore(db, db.Cfg, featuresFlagOff)
|
|
|
|
|
|
|
|
|
|
serviceWithFlagOff := &Service{
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
log: log.New("test-folder-service"),
|
|
|
|
|
dashboardStore: dashStore,
|
|
|
|
|
dashboardFolderStore: folderStore,
|
|
|
|
|
store: nestedFolderStore,
|
|
|
|
|
features: featuresFlagOff,
|
|
|
|
|
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
|
|
|
|
|
db: db,
|
|
|
|
|
registry: make(map[string]folder.RegistryService),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
|
|
|
|
|
_, err = service.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, nil, featuresFlagOff, folderPermissions, dashboardPermissions, ac, serviceWithFlagOff)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOff", createCmd)
|
|
|
|
|
|
|
|
|
|
parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorUIDs[0])
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
subfolder, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorUIDs[1])
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in parent", orgID, parent.ID, "prod")
|
|
|
|
|
_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in subfolder", orgID, subfolder.ID, "prod")
|
|
|
|
|
|
|
|
|
|
countCmd := folder.GetDescendantCountsQuery{
|
|
|
|
|
UID: &ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
m, err := serviceWithFlagOff.GetDescendantCounts(context.Background(), &countCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, m["folder"], int64(0))
|
|
|
|
|
require.Equal(t, m["dashboard"], int64(1))
|
|
|
|
|
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
for _, uid := range ancestorUIDs {
|
|
|
|
|
err := serviceWithFlagOn.store.Delete(context.Background(), uid, orgID)
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
t.Run("With feature flag unset", func(t *testing.T) {
|
|
|
|
|
featuresFlagOff := featuremgmt.WithFeatures()
|
|
|
|
|
dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOff, tagimpl.ProvideService(db, db.Cfg), quotaService)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
nestedFolderStore := ProvideStore(db, db.Cfg, featuresFlagOff)
|
|
|
|
|
|
|
|
|
|
serviceWithFlagOff := &Service{
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
log: log.New("test-folder-service"),
|
|
|
|
|
dashboardStore: dashStore,
|
|
|
|
|
dashboardFolderStore: folderStore,
|
|
|
|
|
store: nestedFolderStore,
|
|
|
|
|
features: featuresFlagOff,
|
|
|
|
|
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
|
|
|
|
|
db: db,
|
|
|
|
|
}
|
|
|
|
|
t.Run("Should delete folders", func(t *testing.T) {
|
|
|
|
|
t.Run("With nested folder feature flag on", func(t *testing.T) {
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, 3, "", createCmd)
|
|
|
|
|
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, 1, "", createCmd)
|
|
|
|
|
|
|
|
|
|
deleteCmd := folder.DeleteFolderCommand{
|
|
|
|
|
UID: ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
err = serviceWithFlagOff.Delete(context.Background(), &deleteCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
for i, uid := range ancestorUIDs {
|
|
|
|
|
// dashboard table
|
|
|
|
|
_, err := serviceWithFlagOff.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, uid)
|
|
|
|
|
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
|
|
|
|
|
// folder table
|
|
|
|
|
_, err = serviceWithFlagOff.store.Get(context.Background(), folder.GetFolderQuery{UID: &ancestorUIDs[i], OrgID: orgID})
|
|
|
|
|
deleteCmd := folder.DeleteFolderCommand{
|
|
|
|
|
UID: ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
err = serviceWithFlagOn.Delete(context.Background(), &deleteCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
for _, uid := range ancestorUIDs {
|
|
|
|
|
err := serviceWithFlagOff.store.Delete(context.Background(), uid, orgID)
|
|
|
|
|
|
|
|
|
|
for i, uid := range ancestorUIDs {
|
|
|
|
|
// dashboard table
|
|
|
|
|
_, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, uid)
|
|
|
|
|
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
|
|
|
|
|
// folder table
|
|
|
|
|
_, err = serviceWithFlagOn.store.Get(context.Background(), folder.GetFolderQuery{UID: &ancestorUIDs[i], OrgID: orgID})
|
|
|
|
|
require.ErrorIs(t, err, folder.ErrFolderNotFound)
|
|
|
|
|
}
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
t.Run("With nested folder feature flag off", func(t *testing.T) {
|
|
|
|
|
featuresFlagOff := featuremgmt.WithFeatures()
|
|
|
|
|
dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOff, tagimpl.ProvideService(db, db.Cfg), quotaService)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
nestedFolderStore := ProvideStore(db, db.Cfg, featuresFlagOff)
|
|
|
|
|
|
|
|
|
|
serviceWithFlagOff := &Service{
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
log: log.New("test-folder-service"),
|
|
|
|
|
dashboardStore: dashStore,
|
|
|
|
|
dashboardFolderStore: folderStore,
|
|
|
|
|
store: nestedFolderStore,
|
|
|
|
|
features: featuresFlagOff,
|
|
|
|
|
bus: bus.ProvideBus(tracing.InitializeTracerForTest()),
|
|
|
|
|
db: db,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
origNewGuardian := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true})
|
|
|
|
|
|
|
|
|
|
ancestorUIDs := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, 1, "", createCmd)
|
|
|
|
|
|
|
|
|
|
deleteCmd := folder.DeleteFolderCommand{
|
|
|
|
|
UID: ancestorUIDs[0],
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
SignedInUser: &signedInUser,
|
|
|
|
|
}
|
|
|
|
|
err = serviceWithFlagOff.Delete(context.Background(), &deleteCmd)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
for i, uid := range ancestorUIDs {
|
|
|
|
|
// dashboard table
|
|
|
|
|
_, err := serviceWithFlagOff.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, uid)
|
|
|
|
|
require.ErrorIs(t, err, dashboards.ErrFolderNotFound)
|
|
|
|
|
// folder table
|
|
|
|
|
_, err = serviceWithFlagOff.store.Get(context.Background(), folder.GetFolderQuery{UID: &ancestorUIDs[i], OrgID: orgID})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = origNewGuardian
|
|
|
|
|
for _, uid := range ancestorUIDs {
|
|
|
|
|
err := serviceWithFlagOff.store.Delete(context.Background(), uid, orgID)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
@@ -930,65 +1023,6 @@ func TestNestedFolderService(t *testing.T) {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestGetChildrenCounts(t *testing.T) {
|
|
|
|
|
g := guardian.New
|
|
|
|
|
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true})
|
|
|
|
|
t.Cleanup(func() {
|
|
|
|
|
guardian.New = g
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
folderId := rand.Int63()
|
|
|
|
|
folderUID := util.GenerateShortUID()
|
|
|
|
|
f := folder.NewFolder("Folder", "")
|
|
|
|
|
f.ID = folderId
|
|
|
|
|
f.UID = folderUID
|
|
|
|
|
f.OrgID = orgID
|
|
|
|
|
|
|
|
|
|
nestedFolderStore := NewFakeStore()
|
|
|
|
|
nestedFolderStore.ExpectedFolder = f
|
|
|
|
|
|
|
|
|
|
dashStore := dashboards.FakeDashboardStore{}
|
|
|
|
|
dashboardCount := int64(2)
|
|
|
|
|
countCmd := dashboards.CountDashboardsInFolderRequest{
|
|
|
|
|
FolderID: f.ID,
|
|
|
|
|
OrgID: f.OrgID,
|
|
|
|
|
}
|
|
|
|
|
dashStore.On("CountDashboardsInFolder", mock.Anything, &countCmd).Return(dashboardCount, nil)
|
|
|
|
|
|
|
|
|
|
dashboardFolderStore := foldertest.NewFakeFolderStore(t)
|
|
|
|
|
dashboardFolderStore.On("GetFolderByUID", mock.Anything, orgID, folderUID).Return(f, nil)
|
|
|
|
|
|
|
|
|
|
cfg := setting.NewCfg()
|
|
|
|
|
cfg.RBACEnabled = false
|
|
|
|
|
features := featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)
|
|
|
|
|
folderService := &Service{
|
|
|
|
|
cfg: cfg,
|
|
|
|
|
store: nestedFolderStore,
|
|
|
|
|
dashboardStore: &dashStore,
|
|
|
|
|
dashboardFolderStore: dashboardFolderStore,
|
|
|
|
|
features: features,
|
|
|
|
|
log: log.New("test-folder-service"),
|
|
|
|
|
accessControl: acimpl.ProvideAccessControl(cfg),
|
|
|
|
|
registry: make(map[string]folder.RegistryService),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ac := acmock.New()
|
|
|
|
|
folderPermissions := acmock.NewMockedPermissionsService()
|
|
|
|
|
dashboardPermissions := acmock.NewMockedPermissionsService()
|
|
|
|
|
_, err := service.ProvideDashboardServiceImpl(cfg, &dashStore, dashboardFolderStore, nil, features, folderPermissions, dashboardPermissions, ac, folderService)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID}
|
|
|
|
|
ctx := appcontext.WithUser(context.Background(), &signedInUser)
|
|
|
|
|
res, err := folderService.GetChildrenCounts(ctx, &folder.GetChildrenCountsQuery{
|
|
|
|
|
SignedInUser: usr,
|
|
|
|
|
UID: &folderUID,
|
|
|
|
|
OrgID: orgID,
|
|
|
|
|
})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Equal(t, res["dashboard"], dashboardCount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func CreateSubtreeInStore(t *testing.T, store *sqlStore, service *Service, depth int, prefix string, cmd folder.CreateFolderCommand) []string {
|
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
|
|