| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | package folderimpl | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-09-14 22:08:04 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-11 01:19:50 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/mock" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/routing" | 
					
						
							| 
									
										
										
										
											2022-10-18 21:31:56 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/bus" | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/db" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/db/dbtest" | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2022-10-18 21:31:56 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol/actest" | 
					
						
							| 
									
										
										
										
											2022-03-10 19:58:18 +08:00
										 |  |  | 	acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/alerting" | 
					
						
							|  |  |  | 	alertmodels "github.com/grafana/grafana/pkg/services/alerting/models" | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards" | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards/database" | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 	dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" | 
					
						
							| 
									
										
										
										
											2022-03-10 19:58:18 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/folder" | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/folder/foldertest" | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/guardian" | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/libraryelements" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/libraryelements/model" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/librarypanels" | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/ngalert/models" | 
					
						
							|  |  |  | 	ngstore "github.com/grafana/grafana/pkg/services/ngalert/store" | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota/quotatest" | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/sqlstore" | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/store/entity" | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/tag/tagimpl" | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2022-03-10 19:58:18 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util" | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | var orgID = int64(1) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | var usr = &user.SignedInUser{UserID: 1, OrgID: orgID} | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-24 17:04:03 +08:00
										 |  |  | func TestIntegrationProvideFolderService(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-06-10 23:46:21 +08:00
										 |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	t.Run("should register scope resolvers", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-03-10 19:58:18 +08:00
										 |  |  | 		cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-03-11 01:19:50 +08:00
										 |  |  | 		ac := acmock.New() | 
					
						
							| 
									
										
										
										
											2023-08-01 15:36:37 +08:00
										 |  |  | 		db := sqlstore.InitTestDB(t) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		ProvideService(ac, bus.ProvideBus(tracing.InitializeTracerForTest()), cfg, nil, nil, db, &featuremgmt.FeatureManager{}, nil) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-08 00:27:20 +08:00
										 |  |  | 		require.Len(t, ac.Calls.RegisterAttributeScopeResolver, 3) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-24 17:04:03 +08:00
										 |  |  | func TestIntegrationFolderService(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-06-10 23:46:21 +08:00
										 |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 	t.Run("Folder service tests", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 		dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							|  |  |  | 		db := sqlstore.InitTestDB(t) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 		nestedFolderStore := ProvideStore(db, db.Cfg) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 		folderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 		cfg := setting.NewCfg() | 
					
						
							|  |  |  | 		features := featuremgmt.WithFeatures() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 		ac := acmock.New().WithPermissions([]accesscontrol.Permission{ | 
					
						
							|  |  |  | 			{Action: accesscontrol.ActionAlertingRuleDelete, Scope: dashboards.ScopeFoldersAll}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		alertingStore := ngstore.DBstore{ | 
					
						
							|  |  |  | 			SQLStore:      db, | 
					
						
							|  |  |  | 			Cfg:           cfg.UnifiedAlerting, | 
					
						
							|  |  |  | 			Logger:        log.New("test-alerting-store"), | 
					
						
							|  |  |  | 			AccessControl: ac, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-11 03:47:53 +08:00
										 |  |  | 		service := &Service{ | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			cfg:                  cfg, | 
					
						
							|  |  |  | 			log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 			dashboardStore:       dashStore, | 
					
						
							|  |  |  | 			dashboardFolderStore: folderStore, | 
					
						
							|  |  |  | 			store:                nestedFolderStore, | 
					
						
							|  |  |  | 			features:             features, | 
					
						
							|  |  |  | 			bus:                  bus.ProvideBus(tracing.InitializeTracerForTest()), | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 			db:                   db, | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			accessControl:        acimpl.ProvideAccessControl(cfg), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 			registry:             make(map[string]folder.RegistryService), | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-03-11 01:19:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 		require.NoError(t, service.RegisterService(alertingStore)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 		t.Run("Given user has no permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			origNewGuardian := guardian.New | 
					
						
							| 
									
										
										
										
											2018-02-21 01:08:19 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{}) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 			folderUID := util.GenerateShortUID() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 			f := folder.NewFolder("Folder", "") | 
					
						
							|  |  |  | 			f.UID = folderUID | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderStore.On("GetFolderByUID", mock.Anything, orgID, folderUID).Return(f, nil) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When get folder by id should return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				_, err := service.Get(context.Background(), &folder.GetFolderQuery{ | 
					
						
							| 
									
										
										
										
											2024-01-12 23:43:39 +08:00
										 |  |  | 					UID:          &folderUID, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.Equal(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			t.Run("When get folder by uid should return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				_, err := service.Get(context.Background(), &folder.GetFolderQuery{ | 
					
						
							|  |  |  | 					UID:          &folderUID, | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.Equal(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When creating folder should return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil).Times(2) | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 				_, err := service.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					Title:        f.Title, | 
					
						
							|  |  |  | 					UID:          folderUID, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.Equal(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 			title := "Folder-TEST" | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When updating folder should return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-25 17:36:26 +08:00
										 |  |  | 				folderResult := dashboards.NewDashboard("dashboard-test") | 
					
						
							|  |  |  | 				folderResult.IsFolder = true | 
					
						
							|  |  |  | 				dashStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(folderResult, nil) | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 				_, err := service.Update(context.Background(), &folder.UpdateFolderCommand{ | 
					
						
							|  |  |  | 					UID:          folderUID, | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					NewTitle:     &title, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.Equal(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When deleting folder by uid should return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-25 16:14:32 +08:00
										 |  |  | 				newFolder := folder.NewFolder("Folder", "") | 
					
						
							|  |  |  | 				newFolder.UID = folderUID | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 				folderStore.On("GetFolderByUID", mock.Anything, orgID, folderUID).Return(newFolder, nil) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-20 23:38:09 +08:00
										 |  |  | 				err := service.Delete(context.Background(), &folder.DeleteFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 					UID:              folderUID, | 
					
						
							|  |  |  | 					OrgID:            orgID, | 
					
						
							|  |  |  | 					ForceDeleteRules: false, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					SignedInUser:     usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 				require.Error(t, err) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.Equal(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Cleanup(func() { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 				guardian.New = origNewGuardian | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 		t.Run("Given user has permission to save", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			origNewGuardian := guardian.New | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true}) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			service.features = featuremgmt.WithFeatures() | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 			t.Run("When creating folder should not return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dash := dashboards.NewDashboardFolder("Test-Folder") | 
					
						
							|  |  |  | 				dash.ID = rand.Int63() | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 				dash.UID = util.GenerateShortUID() | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				f := dashboards.FromDashboard(dash) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							|  |  |  | 				dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(dash, nil).Once() | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 				actualFolder, err := service.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					Title:        dash.Title, | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 					UID:          dash.UID, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 				require.Equal(t, f, actualFolder) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-30 21:14:26 +08:00
										 |  |  | 			t.Run("When creating folder should return error if uid is general", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dash := dashboards.NewDashboardFolder("Test-Folder") | 
					
						
							|  |  |  | 				dash.ID = rand.Int63() | 
					
						
							| 
									
										
										
										
											2022-03-30 21:14:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 				_, err := service.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					Title:        dash.Title, | 
					
						
							|  |  |  | 					UID:          "general", | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				require.ErrorIs(t, err, dashboards.ErrFolderInvalidUID) | 
					
						
							| 
									
										
										
										
											2022-03-30 21:14:26 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When updating folder should not return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dashboardFolder := dashboards.NewDashboardFolder("Folder") | 
					
						
							|  |  |  | 				dashboardFolder.ID = rand.Int63() | 
					
						
							|  |  |  | 				dashboardFolder.UID = util.GenerateShortUID() | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 				dashboardFolder.OrgID = orgID | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 				f, err := service.store.Create(context.Background(), folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					Title:        dashboardFolder.Title, | 
					
						
							|  |  |  | 					UID:          dashboardFolder.UID, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 				assert.Equal(t, "Folder", f.Title) | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 				dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 				title := "TEST-Folder" | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 				updatedDashboardFolder := *dashboardFolder | 
					
						
							|  |  |  | 				updatedDashboardFolder.Title = title | 
					
						
							|  |  |  | 				dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&updatedDashboardFolder, nil) | 
					
						
							|  |  |  | 				dashStore.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Return(&updatedDashboardFolder, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				folderStore.On("GetFolderByID", mock.Anything, orgID, dashboardFolder.ID).Return(&folder.Folder{ | 
					
						
							|  |  |  | 					OrgID: orgID, | 
					
						
							|  |  |  | 					ID:    dashboardFolder.ID, | 
					
						
							|  |  |  | 					UID:   dashboardFolder.UID, | 
					
						
							|  |  |  | 					Title: title, | 
					
						
							|  |  |  | 				}, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 				req := &folder.UpdateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 					UID:          dashboardFolder.UID, | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					NewTitle:     &title, | 
					
						
							|  |  |  | 					SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 				reqResult, err := service.Update(context.Background(), req) | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 				assert.Equal(t, title, reqResult.Title) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Run("When deleting folder by uid should not return access denied error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 				f := folder.NewFolder(util.GenerateShortUID(), "") | 
					
						
							|  |  |  | 				f.UID = util.GenerateShortUID() | 
					
						
							| 
									
										
										
										
											2023-08-01 16:04:44 +08:00
										 |  |  | 				folderStore.On("GetFolders", mock.Anything, orgID, []string{f.UID}).Return(map[string]*folder.Folder{f.UID: f}, nil) | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 				folderStore.On("GetFolderByUID", mock.Anything, orgID, f.UID).Return(f, nil) | 
					
						
							| 
									
										
										
										
											2022-03-22 21:36:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 20:52:41 +08:00
										 |  |  | 				var actualCmd *dashboards.DeleteDashboardCommand | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 				dashStore.On("DeleteDashboard", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { | 
					
						
							| 
									
										
										
										
											2023-01-18 20:52:41 +08:00
										 |  |  | 					actualCmd = args.Get(1).(*dashboards.DeleteDashboardCommand) | 
					
						
							| 
									
										
										
										
											2022-03-22 21:36:50 +08:00
										 |  |  | 				}).Return(nil).Once() | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				expectedForceDeleteRules := rand.Int63()%2 == 0 | 
					
						
							| 
									
										
										
										
											2022-12-20 23:38:09 +08:00
										 |  |  | 				err := service.Delete(context.Background(), &folder.DeleteFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 					UID:              f.UID, | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 					OrgID:            orgID, | 
					
						
							|  |  |  | 					ForceDeleteRules: expectedForceDeleteRules, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 					SignedInUser:     usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 				require.NotNil(t, actualCmd) | 
					
						
							| 
									
										
										
										
											2023-01-18 20:52:41 +08:00
										 |  |  | 				require.Equal(t, orgID, actualCmd.OrgID) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 				require.Equal(t, expectedForceDeleteRules, actualCmd.ForceDeleteFolderRules) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Cleanup(func() { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 				guardian.New = origNewGuardian | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 		t.Run("Given user has permission to view", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			origNewGuardian := guardian.New | 
					
						
							| 
									
										
										
										
											2018-02-21 01:08:19 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanViewValue: true}) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 			t.Run("When get folder by uid should return folder", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 				expected := folder.NewFolder(util.GenerateShortUID(), "") | 
					
						
							|  |  |  | 				expected.UID = util.GenerateShortUID() | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 				folderStore.On("GetFolderByUID", mock.Anything, orgID, expected.UID).Return(expected, nil) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 20:19:08 +08:00
										 |  |  | 				actual, err := service.getFolderByUID(context.Background(), orgID, expected.UID) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 				require.Equal(t, expected, actual) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 			t.Run("When get folder by title should return folder", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-11 21:28:24 +08:00
										 |  |  | 				expected := folder.NewFolder("TEST-"+util.GenerateShortUID(), "") | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 				folderStore.On("GetFolderByTitle", mock.Anything, orgID, expected.Title).Return(expected, nil) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-09 20:19:08 +08:00
										 |  |  | 				actual, err := service.getFolderByTitle(context.Background(), orgID, expected.Title) | 
					
						
							| 
									
										
										
										
											2022-03-14 23:21:42 +08:00
										 |  |  | 				require.Equal(t, expected, actual) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 			t.Cleanup(func() { | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 				guardian.New = origNewGuardian | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:25:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 16:40:38 +08:00
										 |  |  | 		t.Run("Should map errors correct", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2018-02-21 18:25:21 +08:00
										 |  |  | 			testCases := []struct { | 
					
						
							|  |  |  | 				ActualError   error | 
					
						
							|  |  |  | 				ExpectedError error | 
					
						
							|  |  |  | 			}{ | 
					
						
							| 
									
										
										
										
											2022-06-30 21:31:54 +08:00
										 |  |  | 				{ActualError: dashboards.ErrDashboardTitleEmpty, ExpectedError: dashboards.ErrFolderTitleEmpty}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardUpdateAccessDenied, ExpectedError: dashboards.ErrFolderAccessDenied}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardWithSameNameInFolderExists, ExpectedError: dashboards.ErrFolderSameNameExists}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardWithSameUIDExists, ExpectedError: dashboards.ErrFolderWithSameUIDExists}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardVersionMismatch, ExpectedError: dashboards.ErrFolderVersionMismatch}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardNotFound, ExpectedError: dashboards.ErrFolderNotFound}, | 
					
						
							|  |  |  | 				{ActualError: dashboards.ErrDashboardInvalidUid, ExpectedError: dashboards.ErrDashboardInvalidUid}, | 
					
						
							| 
									
										
										
										
											2018-02-21 18:25:21 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for _, tc := range testCases { | 
					
						
							|  |  |  | 				actualError := toFolderError(tc.ActualError) | 
					
						
							| 
									
										
										
										
											2020-11-19 21:47:17 +08:00
										 |  |  | 				assert.EqualErrorf(t, actualError, tc.ExpectedError.Error(), | 
					
						
							|  |  |  | 					"For error '%s' expected error '%s', actual '%s'", tc.ActualError, tc.ExpectedError, actualError) | 
					
						
							| 
									
										
										
										
											2018-02-21 18:25:21 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2018-02-20 20:55:43 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | func TestIntegrationNestedFolderService(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	db := sqlstore.InitTestDB(t) | 
					
						
							|  |  |  | 	quotaService := quotatest.New(false, nil) | 
					
						
							|  |  |  | 	folderStore := ProvideDashboardFolderStore(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	featuresFlagOn := featuremgmt.WithFeatures("nestedFolders") | 
					
						
							| 
									
										
										
										
											2023-11-13 23:55:15 +08:00
										 |  |  | 	dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOn, tagimpl.ProvideService(db), quotaService) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 	nestedFolderStore := ProvideStore(db, db.Cfg) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 	b := bus.ProvideBus(tracing.InitializeTracerForTest()) | 
					
						
							|  |  |  | 	ac := acimpl.ProvideAccessControl(cfg) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	serviceWithFlagOn := &Service{ | 
					
						
							|  |  |  | 		cfg:                  cfg, | 
					
						
							|  |  |  | 		log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 		dashboardStore:       dashStore, | 
					
						
							|  |  |  | 		dashboardFolderStore: folderStore, | 
					
						
							|  |  |  | 		store:                nestedFolderStore, | 
					
						
							|  |  |  | 		features:             featuresFlagOn, | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 		bus:                  b, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 		db:                   db, | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 		accessControl:        ac, | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 		registry:             make(map[string]folder.RegistryService), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{ | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		orgID: { | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 			dashboards.ActionFoldersCreate:         {}, | 
					
						
							|  |  |  | 			dashboards.ActionFoldersWrite:          {dashboards.ScopeFoldersAll}, | 
					
						
							|  |  |  | 			accesscontrol.ActionAlertingRuleDelete: {dashboards.ScopeFoldersAll}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 	}} | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	createCmd := folder.CreateFolderCommand{ | 
					
						
							|  |  |  | 		OrgID:        orgID, | 
					
						
							|  |  |  | 		ParentUID:    "", | 
					
						
							|  |  |  | 		SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 	libraryElementCmd := model.CreateLibraryElementCommand{ | 
					
						
							|  |  |  | 		Model: []byte(` | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  "datasource": "${DS_GDEV-TESTDATA}", | 
					
						
							|  |  |  | 		  "id": 1, | 
					
						
							|  |  |  | 		  "title": "Text - Library Panel", | 
					
						
							|  |  |  | 		  "type": "text", | 
					
						
							|  |  |  | 		  "description": "A description" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	`), | 
					
						
							|  |  |  | 		Kind: int64(model.PanelElement), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	routeRegister := routing.NewRouteRegister() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 	folderPermissions := acmock.NewMockedPermissionsService() | 
					
						
							|  |  |  | 	dashboardPermissions := acmock.NewMockedPermissionsService() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 	t.Run("Should get descendant counts", func(t *testing.T) { | 
					
						
							|  |  |  | 		depth := 5 | 
					
						
							|  |  |  | 		t.Run("With nested folder feature flag on", func(t *testing.T) { | 
					
						
							|  |  |  | 			origNewGuardian := guardian.New | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 				CanSaveValue: true, | 
					
						
							|  |  |  | 				CanViewValue: true, | 
					
						
							|  |  |  | 				// CanEditValue is required to create library elements
 | 
					
						
							|  |  |  | 				CanEditValue: true, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, nil, featuresFlagOn, folderPermissions, dashboardPermissions, ac, serviceWithFlagOn, nil) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 			alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOn, db, serviceWithFlagOn, dashSrv, ac) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 07:30:50 +08:00
										 |  |  | 			elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOn, featuresFlagOn, ac) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOn) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOn", createCmd) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			subfolder, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[1].UID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-21 04:44:51 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in parent", orgID, parent.ID, parent.UID, "prod") | 
					
						
							| 
									
										
										
										
											2023-11-21 04:44:51 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in subfolder", orgID, subfolder.ID, subfolder.UID, "prod") | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 			_ = createRule(t, alertStore, parent.UID, "parent alert") | 
					
						
							|  |  |  | 			_ = createRule(t, alertStore, subfolder.UID, "sub alert") | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			libraryElementCmd.FolderID = parent.ID | 
					
						
							|  |  |  | 			_, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			libraryElementCmd.FolderID = subfolder.ID | 
					
						
							|  |  |  | 			_, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			countCmd := folder.GetDescendantCountsQuery{ | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				UID:          &ancestors[0].UID, | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			m, err := serviceWithFlagOn.GetDescendantCounts(context.Background(), &countCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			require.Equal(t, int64(depth-1), m[entity.StandardKindFolder]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(2), m[entity.StandardKindDashboard]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(2), m[entity.StandardKindAlertRule]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(2), m[entity.StandardKindLibraryPanel]) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = origNewGuardian | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				for _, ancestor := range ancestors { | 
					
						
							|  |  |  | 					err := serviceWithFlagOn.store.Delete(context.Background(), ancestor.UID, orgID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 					assert.NoError(t, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		t.Run("With nested folder feature flag off", func(t *testing.T) { | 
					
						
							|  |  |  | 			featuresFlagOff := featuremgmt.WithFeatures() | 
					
						
							| 
									
										
										
										
											2023-11-13 23:55:15 +08:00
										 |  |  | 			dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOff, tagimpl.ProvideService(db), quotaService) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 			nestedFolderStore := ProvideStore(db, db.Cfg) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			serviceWithFlagOff := &Service{ | 
					
						
							|  |  |  | 				cfg:                  cfg, | 
					
						
							|  |  |  | 				log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 				dashboardStore:       dashStore, | 
					
						
							|  |  |  | 				dashboardFolderStore: folderStore, | 
					
						
							|  |  |  | 				store:                nestedFolderStore, | 
					
						
							|  |  |  | 				features:             featuresFlagOff, | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				bus:                  b, | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 				db:                   db, | 
					
						
							|  |  |  | 				registry:             make(map[string]folder.RegistryService), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 				metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			origNewGuardian := guardian.New | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 				CanSaveValue: true, | 
					
						
							|  |  |  | 				CanViewValue: true, | 
					
						
							|  |  |  | 				// CanEditValue is required to create library elements
 | 
					
						
							|  |  |  | 				CanEditValue: true, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, nil, featuresFlagOff, | 
					
						
							|  |  |  | 				folderPermissions, dashboardPermissions, ac, serviceWithFlagOff, nil) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 			alertStore, err := ngstore.ProvideDBStore(cfg, featuresFlagOff, db, serviceWithFlagOff, dashSrv, ac) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 07:30:50 +08:00
										 |  |  | 			elementService := libraryelements.ProvideService(cfg, db, routeRegister, serviceWithFlagOff, featuresFlagOff, ac) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, serviceWithFlagOff) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "getDescendantCountsOff", createCmd) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			subfolder, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[1].UID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-21 04:44:51 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in parent", orgID, parent.ID, parent.UID, "prod") | 
					
						
							| 
									
										
										
										
											2023-11-21 04:44:51 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_ = insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in subfolder", orgID, subfolder.ID, subfolder.UID, "prod") | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 			_ = createRule(t, alertStore, parent.UID, "parent alert") | 
					
						
							|  |  |  | 			_ = createRule(t, alertStore, subfolder.UID, "sub alert") | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			libraryElementCmd.FolderID = parent.ID | 
					
						
							|  |  |  | 			_, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 			// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			libraryElementCmd.FolderID = subfolder.ID | 
					
						
							|  |  |  | 			_, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			countCmd := folder.GetDescendantCountsQuery{ | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				UID:          &ancestors[0].UID, | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			m, err := serviceWithFlagOff.GetDescendantCounts(context.Background(), &countCmd) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			require.Equal(t, int64(0), m[entity.StandardKindFolder]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(1), m[entity.StandardKindDashboard]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(1), m[entity.StandardKindAlertRule]) | 
					
						
							|  |  |  | 			require.Equal(t, int64(1), m[entity.StandardKindLibraryPanel]) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = origNewGuardian | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				for _, ancestor := range ancestors { | 
					
						
							|  |  |  | 					err := serviceWithFlagOn.store.Delete(context.Background(), ancestor.UID, orgID) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 					assert.NoError(t, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 	t.Run("Should delete folders", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		featuresFlagOff := featuremgmt.WithFeatures() | 
					
						
							|  |  |  | 		serviceWithFlagOff := &Service{ | 
					
						
							|  |  |  | 			cfg:                  cfg, | 
					
						
							|  |  |  | 			log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 			dashboardFolderStore: folderStore, | 
					
						
							|  |  |  | 			features:             featuresFlagOff, | 
					
						
							|  |  |  | 			bus:                  b, | 
					
						
							|  |  |  | 			db:                   db, | 
					
						
							|  |  |  | 			registry:             make(map[string]folder.RegistryService), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		testCases := []struct { | 
					
						
							|  |  |  | 			service           *Service | 
					
						
							| 
									
										
										
										
											2024-01-10 02:38:06 +08:00
										 |  |  | 			featuresFlag      featuremgmt.FeatureToggles | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 			prefix            string | 
					
						
							|  |  |  | 			depth             int | 
					
						
							|  |  |  | 			forceDelete       bool | 
					
						
							|  |  |  | 			deletionErr       error | 
					
						
							|  |  |  | 			dashboardErr      error | 
					
						
							|  |  |  | 			folderErr         error | 
					
						
							|  |  |  | 			libPanelParentErr error | 
					
						
							|  |  |  | 			libPanelSubErr    error | 
					
						
							|  |  |  | 			desc              string | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				service:           serviceWithFlagOn, | 
					
						
							|  |  |  | 				featuresFlag:      featuresFlagOn, | 
					
						
							|  |  |  | 				prefix:            "flagon-force", | 
					
						
							|  |  |  | 				depth:             3, | 
					
						
							|  |  |  | 				forceDelete:       true, | 
					
						
							|  |  |  | 				dashboardErr:      dashboards.ErrFolderNotFound, | 
					
						
							|  |  |  | 				folderErr:         folder.ErrFolderNotFound, | 
					
						
							|  |  |  | 				libPanelParentErr: model.ErrLibraryElementNotFound, | 
					
						
							|  |  |  | 				libPanelSubErr:    model.ErrLibraryElementNotFound, | 
					
						
							|  |  |  | 				desc:              "With nested folder feature flag on and force deletion of rules", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				service:      serviceWithFlagOn, | 
					
						
							|  |  |  | 				featuresFlag: featuresFlagOn, | 
					
						
							|  |  |  | 				prefix:       "flagon-noforce", | 
					
						
							|  |  |  | 				depth:        3, | 
					
						
							|  |  |  | 				forceDelete:  false, | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 				deletionErr:  folder.ErrFolderNotEmpty, | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				desc:         "With nested folder feature flag on and no force deletion of rules", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				service:           serviceWithFlagOff, | 
					
						
							|  |  |  | 				featuresFlag:      featuresFlagOff, | 
					
						
							|  |  |  | 				prefix:            "flagoff-force", | 
					
						
							|  |  |  | 				depth:             1, | 
					
						
							|  |  |  | 				forceDelete:       true, | 
					
						
							|  |  |  | 				dashboardErr:      dashboards.ErrFolderNotFound, | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 				folderErr:         folder.ErrFolderNotFound, | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				libPanelParentErr: model.ErrLibraryElementNotFound, | 
					
						
							|  |  |  | 				desc:              "With nested folder feature flag off and force deletion of rules", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				service:      serviceWithFlagOff, | 
					
						
							|  |  |  | 				featuresFlag: featuresFlagOff, | 
					
						
							|  |  |  | 				prefix:       "flagoff-noforce", | 
					
						
							|  |  |  | 				depth:        1, | 
					
						
							|  |  |  | 				forceDelete:  false, | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 				deletionErr:  folder.ErrFolderNotEmpty, | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				desc:         "With nested folder feature flag off and no force deletion of rules", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		for _, tc := range testCases { | 
					
						
							|  |  |  | 			t.Run(tc.desc, func(t *testing.T) { | 
					
						
							|  |  |  | 				origNewGuardian := guardian.New | 
					
						
							|  |  |  | 				guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 					CanSaveValue: true, | 
					
						
							|  |  |  | 					CanViewValue: true, | 
					
						
							|  |  |  | 					// CanEditValue is required to create library elements
 | 
					
						
							|  |  |  | 					CanEditValue: true, | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-12 07:30:50 +08:00
										 |  |  | 				elementService := libraryelements.ProvideService(cfg, db, routeRegister, tc.service, tc.featuresFlag, ac) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				lps, err := librarypanels.ProvideService(cfg, db, routeRegister, elementService, tc.service) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-13 23:55:15 +08:00
										 |  |  | 				dashStore, err := database.ProvideDashboardStore(db, db.Cfg, tc.featuresFlag, tagimpl.ProvideService(db), quotaService) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 				nestedFolderStore := ProvideStore(db, db.Cfg) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				tc.service.dashboardStore = dashStore | 
					
						
							|  |  |  | 				tc.service.store = nestedFolderStore | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 				dashSrv, err := dashboardservice.ProvideDashboardServiceImpl(cfg, dashStore, folderStore, nil, tc.featuresFlag, folderPermissions, dashboardPermissions, ac, tc.service, nil) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-12-04 17:34:38 +08:00
										 |  |  | 				alertStore, err := ngstore.ProvideDBStore(cfg, tc.featuresFlag, db, tc.service, dashSrv, ac) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				ancestors := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, tc.depth, tc.prefix, createCmd) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[0].UID) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				_ = createRule(t, alertStore, parent.UID, "parent alert") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				var ( | 
					
						
							|  |  |  | 					subfolder *folder.Folder | 
					
						
							|  |  |  | 					subPanel  model.LibraryElementDTO | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 				if tc.depth > 1 { | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 					subfolder, err = serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestors[1].UID) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 					require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					_ = createRule(t, alertStore, subfolder.UID, "sub alert") | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 					// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					libraryElementCmd.FolderID = subfolder.ID | 
					
						
							|  |  |  | 					subPanel, err = lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 					require.NoError(t, err) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-11-01 01:24:16 +08:00
										 |  |  | 				// nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				libraryElementCmd.FolderID = parent.ID | 
					
						
							|  |  |  | 				parentPanel, err := lps.LibraryElementService.CreateElement(context.Background(), &signedInUser, libraryElementCmd) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				deleteCmd := folder.DeleteFolderCommand{ | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 					UID:              ancestors[0].UID, | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 					OrgID:            orgID, | 
					
						
							|  |  |  | 					SignedInUser:     &signedInUser, | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					ForceDeleteRules: tc.forceDelete, | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				err = tc.service.Delete(context.Background(), &deleteCmd) | 
					
						
							|  |  |  | 				require.ErrorIs(t, err, tc.deletionErr) | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				for i, ancestor := range ancestors { | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					// dashboard table
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 					_, err := tc.service.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestor.UID) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					require.ErrorIs(t, err, tc.dashboardErr) | 
					
						
							|  |  |  | 					// folder table
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 					_, err = tc.service.store.Get(context.Background(), folder.GetFolderQuery{UID: &ancestors[i].UID, OrgID: orgID}) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					require.ErrorIs(t, err, tc.folderErr) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 				_, err = lps.LibraryElementService.GetElement(context.Background(), &signedInUser, model.GetLibraryElementCommand{ | 
					
						
							|  |  |  | 					FolderName: parent.Title, | 
					
						
							| 
									
										
										
										
											2023-10-31 23:46:48 +08:00
										 |  |  | 					FolderID:   parent.ID, // nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 					UID:        parentPanel.UID, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				require.ErrorIs(t, err, tc.libPanelParentErr) | 
					
						
							|  |  |  | 				if tc.depth > 1 { | 
					
						
							|  |  |  | 					_, err = lps.LibraryElementService.GetElement(context.Background(), &signedInUser, model.GetLibraryElementCommand{ | 
					
						
							|  |  |  | 						FolderName: subfolder.Title, | 
					
						
							| 
									
										
										
										
											2023-10-31 23:46:48 +08:00
										 |  |  | 						FolderID:   subfolder.ID, // nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 						UID:        subPanel.UID, | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					require.ErrorIs(t, err, tc.libPanelSubErr) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 				t.Cleanup(func() { | 
					
						
							|  |  |  | 					guardian.New = origNewGuardian | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2023-04-27 23:00:09 +08:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-07-25 19:05:53 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | func TestNestedFolderServiceFeatureToggle(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 	g := guardian.New | 
					
						
							|  |  |  | 	guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 	t.Cleanup(func() { | 
					
						
							|  |  |  | 		guardian.New = g | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 	nestedFolderStore := NewFakeStore() | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dashStore := dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 	dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 	dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&dashboards.Dashboard{}, nil) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 	dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 	folderService := &Service{ | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 		cfg:                  cfg, | 
					
						
							|  |  |  | 		store:                nestedFolderStore, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 		db:                   sqlstore.InitTestDB(t), | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 		dashboardStore:       &dashStore, | 
					
						
							|  |  |  | 		dashboardFolderStore: dashboardFolderStore, | 
					
						
							|  |  |  | 		features:             featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), | 
					
						
							|  |  |  | 		log:                  log.New("test-folder-service"), | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		accessControl:        acimpl.ProvideAccessControl(cfg), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	t.Run("create folder", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 		nestedFolderStore.ExpectedFolder = &folder.Folder{ParentUID: util.GenerateShortUID()} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 		res, err := folderService.Create(context.Background(), &folder.CreateFolderCommand{SignedInUser: usr, Title: "my folder"}) | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.NotNil(t, res.UID) | 
					
						
							| 
									
										
										
										
											2022-11-24 21:59:47 +08:00
										 |  |  | 		require.NotEmpty(t, res.ParentUID) | 
					
						
							| 
									
										
										
										
											2022-11-08 18:33:13 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | func TestFolderServiceDualWrite(t *testing.T) { | 
					
						
							|  |  |  | 	g := guardian.New | 
					
						
							|  |  |  | 	guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 	t.Cleanup(func() { | 
					
						
							|  |  |  | 		guardian.New = g | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	db := sqlstore.InitTestDB(t) | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	features := featuremgmt.WithFeatures() | 
					
						
							|  |  |  | 	nestedFolderStore := ProvideStore(db, cfg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dashStore, err := database.ProvideDashboardStore(db, cfg, features, tagimpl.ProvideService(db), "atest.FakeQuotaService{}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dashboardFolderStore := ProvideDashboardFolderStore(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	folderService := &Service{ | 
					
						
							|  |  |  | 		cfg:                  setting.NewCfg(), | 
					
						
							|  |  |  | 		store:                nestedFolderStore, | 
					
						
							|  |  |  | 		db:                   sqlstore.InitTestDB(t), | 
					
						
							|  |  |  | 		dashboardStore:       dashStore, | 
					
						
							|  |  |  | 		dashboardFolderStore: dashboardFolderStore, | 
					
						
							|  |  |  | 		features:             featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders), | 
					
						
							|  |  |  | 		log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 		accessControl:        acimpl.ProvideAccessControl(cfg), | 
					
						
							|  |  |  | 		metrics:              newFoldersMetrics(nil), | 
					
						
							|  |  |  | 		bus:                  bus.ProvideBus(tracing.InitializeTracerForTest()), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("When creating a folder it should trim leading and trailing spaces in both dashboard and folder tables", func(t *testing.T) { | 
					
						
							|  |  |  | 		f, err := folderService.Create(context.Background(), &folder.CreateFolderCommand{SignedInUser: usr, OrgID: orgID, Title: "  my folder  "}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.Equal(t, "my folder", f.Title) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dashFolder, err := dashboardFolderStore.GetFolderByUID(context.Background(), orgID, f.UID) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nestedFolder, err := nestedFolderStore.Get(context.Background(), folder.GetFolderQuery{UID: &f.UID, OrgID: orgID}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.Equal(t, dashFolder.Title, nestedFolder.Title) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("When updating a folder it should trim leading and trailing spaces in both dashboard and folder tables", func(t *testing.T) { | 
					
						
							|  |  |  | 		f, err := folderService.Create(context.Background(), &folder.CreateFolderCommand{SignedInUser: usr, OrgID: orgID, Title: "my folder 2"}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		f, err = folderService.Update(context.Background(), &folder.UpdateFolderCommand{SignedInUser: usr, OrgID: orgID, UID: f.UID, NewTitle: util.Pointer("  my updated folder 2 "), Version: f.Version}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.Equal(t, "my updated folder 2", f.Title) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dashFolder, err := dashboardFolderStore.GetFolderByUID(context.Background(), orgID, f.UID) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		nestedFolder, err := nestedFolderStore.Get(context.Background(), folder.GetFolderQuery{UID: &f.UID, OrgID: orgID}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		assert.Equal(t, dashFolder.Title, nestedFolder.Title) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | func TestNestedFolderService(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 	t.Run("with feature flag unset", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 		t.Run("Should create a folder in both dashboard and folders tables", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			// dash is needed here because folderSvc.Create expects SaveDashboard to return it
 | 
					
						
							|  |  |  | 			dash := dashboards.NewDashboardFolder("myFolder") | 
					
						
							|  |  |  | 			dash.ID = rand.Int63() | 
					
						
							|  |  |  | 			dash.UID = "some_uid" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store & service commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(dash, nil) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures(), acimpl.ProvideAccessControl(setting.NewCfg()), sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 				Title:        dash.Title, | 
					
						
							|  |  |  | 				UID:          dash.UID, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-11-10 20:03:00 +08:00
										 |  |  | 			require.True(t, nestedFolderStore.CreateCalled) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("with nested folder feature flag on", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run("Should be able to create a nested folder under the root", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			dash := dashboards.NewDashboardFolder("myFolder") | 
					
						
							|  |  |  | 			dash.ID = rand.Int63() | 
					
						
							|  |  |  | 			dash.UID = "some_uid" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(dash, nil) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 				Title:        dash.Title, | 
					
						
							|  |  |  | 				UID:          dash.UID, | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			// CreateFolder should also call the folder store's create method.
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			require.True(t, nestedFolderStore.CreateCalled) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run("Should not be able to create new folder under another folder without the right permissions", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			dash := dashboards.NewDashboardFolder("Test-Folder") | 
					
						
							|  |  |  | 			dash.ID = rand.Int63() | 
					
						
							|  |  |  | 			dash.UID = "some_uid" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			tempUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			tempUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("wrong_uid")}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							|  |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							|  |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							|  |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&dashboards.Dashboard{}, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, nil, nil, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), dbtest.NewFakeDB()) | 
					
						
							|  |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							|  |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				Title:        dash.Title, | 
					
						
							|  |  |  | 				UID:          dash.UID, | 
					
						
							|  |  |  | 				SignedInUser: tempUser, | 
					
						
							|  |  |  | 				ParentUID:    "some_parent", | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			require.ErrorIs(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("Should be able to create new folder under another folder with the right permissions", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			dash := dashboards.NewDashboardFolder("Test-Folder") | 
					
						
							|  |  |  | 			dash.ID = rand.Int63() | 
					
						
							|  |  |  | 			dash.UID = "some_uid" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							|  |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							|  |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(dash, nil) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 			dashboardFolderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			nestedFolderUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			nestedFolderUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("some_parent")}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							|  |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				Title:        dash.Title, | 
					
						
							|  |  |  | 				UID:          dash.UID, | 
					
						
							|  |  |  | 				SignedInUser: nestedFolderUser, | 
					
						
							|  |  |  | 				ParentUID:    "some_parent", | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			require.True(t, nestedFolderStore.CreateCalled) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 		t.Run("create without UID, no error", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&dashboards.Dashboard{UID: "newUID"}, nil) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			}, sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			f, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				Title:        "myFolder", | 
					
						
							|  |  |  | 				SignedInUser: usr, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			// CreateFolder should also call the folder store's create method.
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			require.True(t, nestedFolderStore.CreateCalled) | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 			require.Equal(t, "newUID", f.UID) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("create failed because of circular reference", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 			dashboardFolder := dashboards.NewDashboardFolder("myFolder") | 
					
						
							|  |  |  | 			dashboardFolder.ID = rand.Int63() | 
					
						
							|  |  |  | 			dashboardFolder.UID = "myFolder" | 
					
						
							|  |  |  | 			f := dashboards.FromDashboard(dashboardFolder) | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							|  |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(dashboardFolder, nil) | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 			dashboardFolderStore.On("GetFolderByUID", mock.Anything, orgID, dashboardFolder.UID).Return(f, nil) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = []*folder.Folder{ | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 				{UID: "newFolder", ParentUID: "newFolder"}, | 
					
						
							|  |  |  | 				{UID: "newFolder2", ParentUID: "newFolder2"}, | 
					
						
							|  |  |  | 				{UID: "newFolder3", ParentUID: "newFolder3"}, | 
					
						
							|  |  |  | 				{UID: "myFolder", ParentUID: "newFolder"}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cmd := folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 				ParentUID:    dashboardFolder.UID, | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 				Title:        "myFolder1", | 
					
						
							|  |  |  | 				UID:          "myFolder1", | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 				SignedInUser: usr, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			}, sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &cmd) | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 			require.Error(t, err, folder.ErrCircularReference) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			// CreateFolder should not call the folder store's create method.
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			require.False(t, nestedFolderStore.CreateCalled) | 
					
						
							| 
									
										
										
										
											2022-12-15 00:07:55 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 		t.Run("create returns error from nested folder service", func(t *testing.T) { | 
					
						
							|  |  |  | 			// This test creates and deletes the dashboard, so needs some extra setup.
 | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil) | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&dashboards.Dashboard{}, nil) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 			// return an error from the folder store
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedError = errors.New("FAILED") | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// the service return success as long as the legacy create succeeds
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			}, sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 17:13:47 +08:00
										 |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				Title:        "myFolder", | 
					
						
							|  |  |  | 				UID:          "myFolder", | 
					
						
							|  |  |  | 				SignedInUser: usr, | 
					
						
							| 
									
										
										
										
											2022-11-10 17:41:03 +08:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 			require.Error(t, err, "FAILED") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// CreateFolder should also call the folder store's create method.
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			require.True(t, nestedFolderStore.CreateCalled) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-11-10 16:42:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run("move without the right permissions should fail", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			nestedFolderUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			nestedFolderUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("wrong_uid")}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), dbtest.NewFakeDB()) | 
					
						
							|  |  |  | 			_, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder", OrgID: orgID, SignedInUser: nestedFolderUser}) | 
					
						
							|  |  |  | 			require.ErrorIs(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run("move with the right permissions succeeds", func(t *testing.T) { | 
					
						
							|  |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							|  |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = []*folder.Folder{ | 
					
						
							|  |  |  | 				{UID: "newFolder", ParentUID: "newFolder"}, | 
					
						
							|  |  |  | 				{UID: "newFolder2", ParentUID: "newFolder2"}, | 
					
						
							|  |  |  | 				{UID: "newFolder3", ParentUID: "newFolder3"}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			nestedFolderUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			nestedFolderUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("newFolder")}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder", OrgID: orgID, SignedInUser: nestedFolderUser}) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			// the folder is set inside InTransaction() but the fake one is called
 | 
					
						
							|  |  |  | 			// require.NotNil(t, f)
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("move to the root folder without folder creation permissions fails", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			nestedFolderUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			nestedFolderUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersWrite: {dashboards.ScopeFoldersProvider.GetResourceScopeUID("")}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), dbtest.NewFakeDB()) | 
					
						
							|  |  |  | 			_, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "", OrgID: orgID, SignedInUser: nestedFolderUser}) | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 			require.Error(t, err, dashboards.ErrFolderAccessDenied) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 		t.Run("move to the root folder with folder creation permissions succeeds", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = []*folder.Folder{ | 
					
						
							| 
									
										
										
										
											2022-12-20 21:00:33 +08:00
										 |  |  | 				{UID: "newFolder", ParentUID: "newFolder"}, | 
					
						
							|  |  |  | 				{UID: "newFolder2", ParentUID: "newFolder2"}, | 
					
						
							|  |  |  | 				{UID: "newFolder3", ParentUID: "newFolder3"}, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:04:22 +08:00
										 |  |  | 			nestedFolderUser := &user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{}} | 
					
						
							|  |  |  | 			nestedFolderUser.Permissions[orgID] = map[string][]string{dashboards.ActionFoldersCreate: {}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), acimpl.ProvideAccessControl(setting.NewCfg()), dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			_, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "", OrgID: orgID, SignedInUser: nestedFolderUser}) | 
					
						
							| 
									
										
										
										
											2022-11-10 22:06:52 +08:00
										 |  |  | 			require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2023-10-24 15:04:45 +08:00
										 |  |  | 			// the folder is set inside InTransaction() but the fake one is called
 | 
					
						
							|  |  |  | 			// require.NotNil(t, f)
 | 
					
						
							| 
									
										
										
										
											2022-11-10 22:06:52 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 21:49:17 +08:00
										 |  |  | 		t.Run("move when parentUID in the current subtree returns error from nested folder service", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedError = folder.ErrCircularReference | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 			}, dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			f, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder", OrgID: orgID, SignedInUser: usr}) | 
					
						
							| 
									
										
										
										
											2022-12-08 21:49:17 +08:00
										 |  |  | 			require.Error(t, err, folder.ErrCircularReference) | 
					
						
							|  |  |  | 			require.Nil(t, f) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("move when new parentUID depth + subTree height bypassed maximum depth returns error", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = []*folder.Folder{ | 
					
						
							| 
									
										
										
										
											2022-12-08 21:49:17 +08:00
										 |  |  | 				{UID: "newFolder", ParentUID: "newFolder"}, | 
					
						
							|  |  |  | 				{UID: "newFolder2", ParentUID: "newFolder2"}, | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore.ExpectedFolderHeight = 5 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 			}, dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			f, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder2", OrgID: orgID, SignedInUser: usr}) | 
					
						
							| 
									
										
										
										
											2022-12-08 21:49:17 +08:00
										 |  |  | 			require.Error(t, err, folder.ErrMaximumDepthReached) | 
					
						
							|  |  |  | 			require.Nil(t, f) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("move when parentUID in the current subtree returns error from nested folder service", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true, CanViewValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"} | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = []*folder.Folder{{UID: "myFolder", ParentUID: "12345"}, {UID: "12345", ParentUID: ""}} | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 			}, dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			f, err := folderSvc.Move(context.Background(), &folder.MoveFolderCommand{UID: "myFolder", NewParentUID: "newFolder2", OrgID: orgID, SignedInUser: usr}) | 
					
						
							| 
									
										
										
										
											2022-12-08 21:49:17 +08:00
										 |  |  | 			require.Error(t, err, folder.ErrCircularReference) | 
					
						
							|  |  |  | 			require.Nil(t, f) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 		t.Run("create returns error if maximum depth reached", func(t *testing.T) { | 
					
						
							|  |  |  | 			// This test creates and deletes the dashboard, so needs some extra setup.
 | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							| 
									
										
										
										
											2023-01-18 23:47:59 +08:00
										 |  |  | 			dashStore.On("ValidateDashboardBeforeSave", mock.Anything, mock.AnythingOfType("*dashboards.Dashboard"), mock.AnythingOfType("bool")).Return(true, nil).Times(2) | 
					
						
							| 
									
										
										
										
											2023-01-16 23:33:55 +08:00
										 |  |  | 			dashStore.On("SaveDashboard", mock.Anything, mock.AnythingOfType("dashboards.SaveDashboardCommand")).Return(&dashboards.Dashboard{}, nil) | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-01 21:43:21 +08:00
										 |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							| 
									
										
										
										
											2023-11-16 19:11:35 +08:00
										 |  |  | 			dashboardFolderStore.On("GetFolderByUID", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).Return(&folder.Folder{}, nil) | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 			parents := make([]*folder.Folder, 0, folder.MaxNestedFolderDepth) | 
					
						
							|  |  |  | 			for i := 0; i < folder.MaxNestedFolderDepth; i++ { | 
					
						
							|  |  |  | 				parents = append(parents, &folder.Folder{UID: fmt.Sprintf("folder%d", i)}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			//nestedFolderStore.ExpectedFolder = &folder.Folder{UID: "myFolder", ParentUID: "newFolder"}
 | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedParentFolders = parents | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-11-22 05:06:20 +08:00
										 |  |  | 			}, sqlstore.InitTestDB(t)) | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 			_, err := folderSvc.Create(context.Background(), &folder.CreateFolderCommand{ | 
					
						
							| 
									
										
										
										
											2022-11-23 22:44:45 +08:00
										 |  |  | 				Title:        "folder", | 
					
						
							|  |  |  | 				OrgID:        orgID, | 
					
						
							|  |  |  | 				ParentUID:    parents[len(parents)-1].UID, | 
					
						
							|  |  |  | 				UID:          util.GenerateShortUID(), | 
					
						
							|  |  |  | 				SignedInUser: usr, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			assert.ErrorIs(t, err, folder.ErrMaximumDepthReached) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2023-02-08 23:16:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		t.Run("get default folder, no error", func(t *testing.T) { | 
					
						
							|  |  |  | 			g := guardian.New | 
					
						
							|  |  |  | 			guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanSaveValue: true}) | 
					
						
							|  |  |  | 			t.Cleanup(func() { | 
					
						
							|  |  |  | 				guardian.New = g | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// dashboard store commands that should be called.
 | 
					
						
							|  |  |  | 			dashStore := &dashboards.FakeDashboardStore{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			dashboardFolderStore := foldertest.NewFakeFolderStore(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			nestedFolderStore := NewFakeStore() | 
					
						
							|  |  |  | 			nestedFolderStore.ExpectedError = folder.ErrFolderNotFound | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			folderSvc := setup(t, dashStore, dashboardFolderStore, nestedFolderStore, featuremgmt.WithFeatures("nestedFolders"), actest.FakeAccessControl{ | 
					
						
							|  |  |  | 				ExpectedEvaluate: true, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 			}, dbtest.NewFakeDB()) | 
					
						
							| 
									
										
										
										
											2023-02-08 23:16:53 +08:00
										 |  |  | 			_, err := folderSvc.Get(context.Background(), &folder.GetFolderQuery{ | 
					
						
							|  |  |  | 				OrgID:        orgID, | 
					
						
							| 
									
										
										
										
											2023-11-15 23:30:00 +08:00
										 |  |  | 				ID:           &folder.GeneralFolder.ID, // nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2023-02-08 23:16:53 +08:00
										 |  |  | 				SignedInUser: usr, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2022-11-08 21:59:55 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | func TestIntegrationNestedFolderSharedWithMe(t *testing.T) { | 
					
						
							|  |  |  | 	if testing.Short() { | 
					
						
							|  |  |  | 		t.Skip("skipping integration test") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	db := sqlstore.InitTestDB(t) | 
					
						
							|  |  |  | 	quotaService := quotatest.New(false, nil) | 
					
						
							|  |  |  | 	folderStore := ProvideDashboardFolderStore(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	featuresFlagOn := featuremgmt.WithFeatures("nestedFolders") | 
					
						
							|  |  |  | 	dashStore, err := database.ProvideDashboardStore(db, db.Cfg, featuresFlagOn, tagimpl.ProvideService(db), quotaService) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-23 00:03:30 +08:00
										 |  |  | 	nestedFolderStore := ProvideStore(db, db.Cfg) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	b := bus.ProvideBus(tracing.InitializeTracerForTest()) | 
					
						
							|  |  |  | 	ac := acimpl.ProvideAccessControl(cfg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	serviceWithFlagOn := &Service{ | 
					
						
							|  |  |  | 		cfg:                  cfg, | 
					
						
							|  |  |  | 		log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 		dashboardStore:       dashStore, | 
					
						
							|  |  |  | 		dashboardFolderStore: folderStore, | 
					
						
							|  |  |  | 		store:                nestedFolderStore, | 
					
						
							|  |  |  | 		features:             featuresFlagOn, | 
					
						
							|  |  |  | 		bus:                  b, | 
					
						
							|  |  |  | 		db:                   db, | 
					
						
							|  |  |  | 		accessControl:        ac, | 
					
						
							|  |  |  | 		registry:             make(map[string]folder.RegistryService), | 
					
						
							|  |  |  | 		metrics:              newFoldersMetrics(nil), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dashboardPermissions := acmock.NewMockedPermissionsService() | 
					
						
							|  |  |  | 	dashboardService, err := dashboardservice.ProvideDashboardServiceImpl( | 
					
						
							|  |  |  | 		cfg, dashStore, folderStore, &dummyDashAlertExtractor{}, | 
					
						
							|  |  |  | 		featuresFlagOn, | 
					
						
							|  |  |  | 		acmock.NewMockedPermissionsService(), | 
					
						
							|  |  |  | 		dashboardPermissions, | 
					
						
							|  |  |  | 		actest.FakeAccessControl{}, | 
					
						
							|  |  |  | 		foldertest.NewFakeService(), | 
					
						
							|  |  |  | 		nil, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	signedInUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{ | 
					
						
							|  |  |  | 		orgID: { | 
					
						
							|  |  |  | 			dashboards.ActionFoldersRead: {}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	signedInAdminUser := user.SignedInUser{UserID: 1, OrgID: orgID, Permissions: map[int64]map[string][]string{ | 
					
						
							|  |  |  | 		orgID: { | 
					
						
							|  |  |  | 			dashboards.ActionFoldersCreate: {}, | 
					
						
							|  |  |  | 			dashboards.ActionFoldersWrite:  {dashboards.ScopeFoldersAll}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	createCmd := folder.CreateFolderCommand{ | 
					
						
							|  |  |  | 		OrgID:        orgID, | 
					
						
							|  |  |  | 		ParentUID:    "", | 
					
						
							|  |  |  | 		SignedInUser: &signedInAdminUser, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Should get folders shared with given user", func(t *testing.T) { | 
					
						
							|  |  |  | 		depth := 3 | 
					
						
							|  |  |  | 		origNewGuardian := guardian.New | 
					
						
							|  |  |  | 		guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 			CanSaveValue: true, | 
					
						
							|  |  |  | 			CanViewValue: true, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 		ancestorFoldersWithPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withPermissions", createCmd) | 
					
						
							|  |  |  | 		ancestorFoldersWithoutPermissions := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "withoutPermissions", createCmd) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 		parent, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorFoldersWithoutPermissions[0].UID) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 		subfolder, err := serviceWithFlagOn.dashboardFolderStore.GetFolderByUID(context.Background(), orgID, ancestorFoldersWithoutPermissions[1].UID) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		// nolint:staticcheck
 | 
					
						
							|  |  |  | 		dash1 := insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in parent", orgID, parent.ID, parent.UID, "prod") | 
					
						
							|  |  |  | 		// nolint:staticcheck
 | 
					
						
							|  |  |  | 		dash2 := insertTestDashboard(t, serviceWithFlagOn.dashboardStore, "dashboard in subfolder", orgID, subfolder.ID, subfolder.UID, "prod") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 			CanSaveValue: true, | 
					
						
							|  |  |  | 			CanViewValue: true, | 
					
						
							|  |  |  | 			CanViewUIDs: []string{ | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 				ancestorFoldersWithPermissions[0].UID, | 
					
						
							|  |  |  | 				ancestorFoldersWithPermissions[1].UID, | 
					
						
							|  |  |  | 				ancestorFoldersWithoutPermissions[1].UID, | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 				dash1.UID, | 
					
						
							|  |  |  | 				dash2.UID, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		signedInUser.Permissions[orgID][dashboards.ActionFoldersRead] = []string{ | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(ancestorFoldersWithPermissions[0].UID), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			// Add permission to the subfolder of folder with permission (to check deduplication)
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(ancestorFoldersWithPermissions[1].UID), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 			// Add permission to the subfolder of folder without permission
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(ancestorFoldersWithoutPermissions[1].UID), | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		signedInUser.Permissions[orgID][dashboards.ActionDashboardsRead] = []string{ | 
					
						
							|  |  |  | 			dashboards.ScopeDashboardsProvider.GetResourceScopeUID(dash1.UID), | 
					
						
							|  |  |  | 			dashboards.ScopeDashboardsProvider.GetResourceScopeUID(dash2.UID), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		getSharedCmd := folder.GetChildrenQuery{ | 
					
						
							|  |  |  | 			UID:          folder.SharedWithMeFolderUID, | 
					
						
							|  |  |  | 			OrgID:        orgID, | 
					
						
							|  |  |  | 			SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sharedFolders, err := serviceWithFlagOn.GetChildren(context.Background(), &getSharedCmd) | 
					
						
							|  |  |  | 		sharedFoldersUIDs := make([]string, 0) | 
					
						
							|  |  |  | 		for _, f := range sharedFolders { | 
					
						
							|  |  |  | 			sharedFoldersUIDs = append(sharedFoldersUIDs, f.UID) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Len(t, sharedFolders, 1) | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 		require.Contains(t, sharedFoldersUIDs, ancestorFoldersWithoutPermissions[1].UID) | 
					
						
							|  |  |  | 		require.NotContains(t, sharedFoldersUIDs, ancestorFoldersWithPermissions[1].UID) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		sharedDashboards, err := dashboardService.GetDashboardsSharedWithUser(context.Background(), &signedInUser) | 
					
						
							|  |  |  | 		sharedDashboardsUIDs := make([]string, 0) | 
					
						
							|  |  |  | 		for _, d := range sharedDashboards { | 
					
						
							|  |  |  | 			sharedDashboardsUIDs = append(sharedDashboardsUIDs, d.UID) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Len(t, sharedDashboards, 1) | 
					
						
							|  |  |  | 		require.Contains(t, sharedDashboardsUIDs, dash1.UID) | 
					
						
							|  |  |  | 		require.NotContains(t, sharedDashboardsUIDs, dash2.UID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			guardian.New = origNewGuardian | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			for _, ancestor := range ancestorFoldersWithPermissions { | 
					
						
							|  |  |  | 				err := serviceWithFlagOn.store.Delete(context.Background(), ancestor.UID, orgID) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 				assert.NoError(t, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			guardian.New = origNewGuardian | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 			for _, ancestor := range ancestorFoldersWithoutPermissions { | 
					
						
							|  |  |  | 				err := serviceWithFlagOn.store.Delete(context.Background(), ancestor.UID, orgID) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 				assert.NoError(t, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Should get org folders visible", func(t *testing.T) { | 
					
						
							|  |  |  | 		depth := 3 | 
					
						
							|  |  |  | 		origNewGuardian := guardian.New | 
					
						
							|  |  |  | 		guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{ | 
					
						
							|  |  |  | 			CanSaveValue: true, | 
					
						
							|  |  |  | 			CanViewValue: true, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// create folder sctructure like this:
 | 
					
						
							|  |  |  | 		// tree1-folder-0
 | 
					
						
							|  |  |  | 		// └──tree1-folder-1
 | 
					
						
							|  |  |  | 		// 	└──tree1-folder-2
 | 
					
						
							|  |  |  | 		// tree2-folder-0
 | 
					
						
							|  |  |  | 		//  └──tree2-folder-1
 | 
					
						
							|  |  |  | 		// 	 └──tree2-folder-2
 | 
					
						
							|  |  |  | 		tree1 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree1-", createCmd) | 
					
						
							|  |  |  | 		tree2 := CreateSubtreeInStore(t, nestedFolderStore, serviceWithFlagOn, depth, "tree2-", createCmd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		signedInUser.Permissions[orgID][dashboards.ActionFoldersRead] = []string{ | 
					
						
							|  |  |  | 			// Add permission to tree1-folder-0
 | 
					
						
							|  |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(tree1[0].UID), | 
					
						
							|  |  |  | 			// Add permission to the subfolder of folder with permission (tree1-folder-1) to check deduplication
 | 
					
						
							|  |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(tree1[1].UID), | 
					
						
							|  |  |  | 			// Add permission to the subfolder of folder without permission (tree2-folder-1)
 | 
					
						
							|  |  |  | 			dashboards.ScopeFoldersProvider.GetResourceScopeUID(tree2[1].UID), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t.Cleanup(func() { | 
					
						
							|  |  |  | 			guardian.New = origNewGuardian | 
					
						
							|  |  |  | 			for _, f := range tree1 { | 
					
						
							|  |  |  | 				err := serviceWithFlagOn.store.Delete(context.Background(), f.UID, orgID) | 
					
						
							|  |  |  | 				assert.NoError(t, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for _, f := range tree2 { | 
					
						
							|  |  |  | 				err := serviceWithFlagOn.store.Delete(context.Background(), f.UID, orgID) | 
					
						
							|  |  |  | 				assert.NoError(t, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		testCases := []struct { | 
					
						
							|  |  |  | 			name     string | 
					
						
							|  |  |  | 			cmd      folder.GetFoldersQuery | 
					
						
							|  |  |  | 			expected []*folder.Folder | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Should get all org folders visible to the user", | 
					
						
							|  |  |  | 				cmd: folder.GetFoldersQuery{ | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []*folder.Folder{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree1[0].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree1[1].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree1[2].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree2[1].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree2[2].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Should get all org folders visible to the user with fullpath", | 
					
						
							|  |  |  | 				cmd: folder.GetFoldersQuery{ | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					WithFullpath: true, | 
					
						
							|  |  |  | 					SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []*folder.Folder{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree1[0].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree1-folder-0", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree1[1].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree1-folder-0/tree1-folder-1", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree1[2].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree1-folder-0/tree1-folder-1/tree1-folder-2", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree2[1].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree2-folder-0/tree2-folder-1", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree2[2].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree2-folder-0/tree2-folder-1/tree2-folder-2", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Should get all org folders visible to the user with fullpath UIDs", | 
					
						
							|  |  |  | 				cmd: folder.GetFoldersQuery{ | 
					
						
							|  |  |  | 					OrgID:            orgID, | 
					
						
							|  |  |  | 					WithFullpathUIDs: true, | 
					
						
							|  |  |  | 					SignedInUser:     &signedInUser, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []*folder.Folder{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree1[0].UID, | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree1[0].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree1[1].UID, | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree1[0].UID, tree1[1].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree1[2].UID, | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree1[0].UID, tree1[1].UID, tree1[2].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree2[1].UID, | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree2[0].UID, tree2[1].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree2[2].UID, | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree2[0].UID, tree2[1].UID, tree2[2].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Should get specific org folders visible to the user", | 
					
						
							|  |  |  | 				cmd: folder.GetFoldersQuery{ | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					UIDs:         []string{tree1[0].UID, tree2[0].UID, tree2[1].UID}, | 
					
						
							|  |  |  | 					SignedInUser: &signedInUser, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []*folder.Folder{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree1[0].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID: tree2[1].UID, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				name: "Should get all org folders visible to the user with admin permissions", | 
					
						
							|  |  |  | 				cmd: folder.GetFoldersQuery{ | 
					
						
							|  |  |  | 					OrgID:        orgID, | 
					
						
							|  |  |  | 					SignedInUser: &signedInAdminUser, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []*folder.Folder{ | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree1[0].UID, | 
					
						
							|  |  |  | 						Fullpath:     "tree1-folder-0", | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree1[0].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree1[1].UID, | 
					
						
							|  |  |  | 						Fullpath:     "tree1-folder-0/tree1-folder-1", | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree1[0].UID, tree1[1].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:      tree1[2].UID, | 
					
						
							|  |  |  | 						Fullpath: "tree1-folder-0/tree1-folder-1/tree1-folder-2", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree2[0].UID, | 
					
						
							|  |  |  | 						Fullpath:     "tree2-folder-0", | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree2[0].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree2[1].UID, | 
					
						
							|  |  |  | 						Fullpath:     "tree2-folder-0/tree2-folder-1", | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree2[0].UID, tree2[1].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						UID:          tree2[2].UID, | 
					
						
							|  |  |  | 						Fullpath:     "tree2-folder-0/tree2-folder-1/tree2-folder-2", | 
					
						
							|  |  |  | 						FullpathUIDs: strings.Join([]string{tree2[0].UID, tree2[1].UID, tree2[2].UID}, "/"), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, tc := range testCases { | 
					
						
							|  |  |  | 			t.Run(tc.name, func(t *testing.T) { | 
					
						
							|  |  |  | 				actualFolders, err := serviceWithFlagOn.GetFolders(context.Background(), tc.cmd) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				require.Len(t, actualFolders, len(tc.expected)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				for i, expected := range tc.expected { | 
					
						
							|  |  |  | 					actualFolder := actualFolders[i] | 
					
						
							|  |  |  | 					require.Equal(t, expected.UID, actualFolder.UID) | 
					
						
							|  |  |  | 					if tc.cmd.WithFullpath { | 
					
						
							|  |  |  | 						require.Equal(t, expected.Fullpath, actualFolder.Fullpath) | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						require.Empty(t, actualFolder.Fullpath) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if tc.cmd.WithFullpathUIDs { | 
					
						
							|  |  |  | 						require.Equal(t, expected.FullpathUIDs, actualFolder.FullpathUIDs) | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						require.Empty(t, actualFolder.FullpathUIDs) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | func CreateSubtreeInStore(t *testing.T, store *sqlStore, service *Service, depth int, prefix string, cmd folder.CreateFolderCommand) []*folder.Folder { | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 	folders := make([]*folder.Folder, 0, depth) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 	for i := 0; i < depth; i++ { | 
					
						
							|  |  |  | 		title := fmt.Sprintf("%sfolder-%d", prefix, i) | 
					
						
							|  |  |  | 		cmd.Title = title | 
					
						
							|  |  |  | 		cmd.UID = util.GenerateShortUID() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		f, err := service.Create(context.Background(), &cmd) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Equal(t, title, f.Title) | 
					
						
							|  |  |  | 		require.NotEmpty(t, f.UID) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 		folders = append(folders, f) | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cmd.ParentUID = f.UID | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-25 15:27:13 +08:00
										 |  |  | 	return folders | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func setup(t *testing.T, dashStore dashboards.Store, dashboardFolderStore folder.FolderStore, nestedFolderStore store, features featuremgmt.FeatureToggles, ac accesscontrol.AccessControl, db db.DB) folder.Service { | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// nothing enabled yet
 | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	return &Service{ | 
					
						
							| 
									
										
										
										
											2023-01-20 00:38:07 +08:00
										 |  |  | 		cfg:                  cfg, | 
					
						
							|  |  |  | 		log:                  log.New("test-folder-service"), | 
					
						
							|  |  |  | 		dashboardStore:       dashStore, | 
					
						
							|  |  |  | 		dashboardFolderStore: dashboardFolderStore, | 
					
						
							|  |  |  | 		store:                nestedFolderStore, | 
					
						
							|  |  |  | 		features:             features, | 
					
						
							|  |  |  | 		accessControl:        ac, | 
					
						
							| 
									
										
										
										
											2023-03-15 16:51:37 +08:00
										 |  |  | 		db:                   db, | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 		metrics:              newFoldersMetrics(nil), | 
					
						
							| 
									
										
										
										
											2023-01-18 18:22:23 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-06-02 22:38:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func createRule(t *testing.T, store *ngstore.DBstore, folderUID, title string) *models.AlertRule { | 
					
						
							|  |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rule := models.AlertRule{ | 
					
						
							|  |  |  | 		OrgID:        orgID, | 
					
						
							|  |  |  | 		NamespaceUID: folderUID, | 
					
						
							|  |  |  | 		Title:        title, | 
					
						
							|  |  |  | 		Updated:      time.Now(), | 
					
						
							|  |  |  | 		UID:          util.GenerateShortUID(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err := store.SQLStore.WithDbSession(context.Background(), func(sess *db.Session) error { | 
					
						
							|  |  |  | 		_, err := sess.Table(models.AlertRule{}).InsertOne(rule) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &rule | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-12-05 23:13:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type dummyDashAlertExtractor struct { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *dummyDashAlertExtractor) GetAlerts(ctx context.Context, dashAlertInfo alerting.DashAlertInfo) ([]*alertmodels.Alert, error) { | 
					
						
							|  |  |  | 	return nil, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (d *dummyDashAlertExtractor) ValidateAlerts(ctx context.Context, dashAlertInfo alerting.DashAlertInfo) error { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |