package store import ( "context" "testing" "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/setting" ) func TestIntegration_GetUserVisibleNamespaces(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) b := &fakeBus{} logger := log.New("test-dbstore") store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) admin := &user.SignedInUser{ UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, IsGrafanaAdmin: true, } folders := []struct { uid string title string parentUid string }{ {uid: uuid.NewString(), title: "folder1", parentUid: ""}, {uid: uuid.NewString(), title: "folder2", parentUid: ""}, {uid: uuid.NewString(), title: "nested/folder", parentUid: ""}, } for _, f := range folders { createFolder(t, store, f.uid, f.title, 1, f.parentUid) } t.Run("returns all folders", func(t *testing.T) { namespaces, err := store.GetUserVisibleNamespaces(context.Background(), 1, admin) require.NoError(t, err) require.Len(t, namespaces, len(folders)) }) t.Run("returns empty list for a non existing org", func(t *testing.T) { emptyOrgID := int64(999) namespaces, err := store.GetUserVisibleNamespaces(context.Background(), emptyOrgID, admin) require.NoError(t, err) require.Empty(t, namespaces) }) } func TestIntegration_GetNamespaceByUID(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) b := &fakeBus{} logger := log.New("test-dbstore") store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) u := &user.SignedInUser{ UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, IsGrafanaAdmin: true, } uid := uuid.NewString() parentUid := uuid.NewString() title := "folder/title" parentTitle := "parent-title" createFolder(t, store, parentUid, parentTitle, 1, "") createFolder(t, store, uid, title, 1, parentUid) actual, err := store.GetNamespaceByUID(context.Background(), uid, 1, u) require.NoError(t, err) require.Equal(t, title, actual.Title) require.Equal(t, uid, actual.UID) require.Equal(t, title, actual.Fullpath) t.Run("error when user does not have permissions", func(t *testing.T) { someUser := &user.SignedInUser{ UserID: 2, OrgID: 1, OrgRole: org.RoleViewer, } _, err = store.GetNamespaceByUID(context.Background(), uid, 1, someUser) require.ErrorIs(t, err, dashboards.ErrFolderAccessDenied) }) t.Run("error when folder does not exist", func(t *testing.T) { nonExistentUID := uuid.NewString() _, err := store.GetNamespaceByUID(context.Background(), nonExistentUID, 1, u) require.ErrorIs(t, err, dashboards.ErrFolderAccessDenied) }) t.Run("when nested folders are enabled full path should be populated with correct value", func(t *testing.T) { store.FolderService = setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)) actual, err := store.GetNamespaceByUID(context.Background(), uid, 1, u) require.NoError(t, err) require.Equal(t, title, actual.Title) require.Equal(t, uid, actual.UID) require.Equal(t, "parent-title/folder\\/title", actual.Fullpath) }) } func TestIntegration_GetNamespaceByTitle(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) b := &fakeBus{} logger := log.New("test-dbstore") store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) store.FolderService = setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)) u := &user.SignedInUser{ UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, IsGrafanaAdmin: true, } // Create parent folder parentUID := uuid.NewString() parentTitle := "parent-folder" createFolder(t, store, parentUID, parentTitle, 1, "") // Create child folder under parent childUID := uuid.NewString() childTitle := "child-folder" createFolder(t, store, childUID, childTitle, 1, parentUID) // Create another folder with same title but under root sameTitleInRoot := uuid.NewString() createFolder(t, store, sameTitleInRoot, childTitle, 1, "") t.Run("should find folder by title and parent UID", func(t *testing.T) { actual, err := store.GetNamespaceByTitle(context.Background(), childTitle, 1, u, parentUID) require.NoError(t, err) require.Equal(t, childTitle, actual.Title) require.Equal(t, childUID, actual.UID) require.Equal(t, parentUID, actual.ParentUID) }) t.Run("should find folder by title in root", func(t *testing.T) { actual, err := store.GetNamespaceByTitle(context.Background(), childTitle, 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, childTitle, actual.Title) require.Equal(t, sameTitleInRoot, actual.UID) require.Equal(t, folder.RootFolderUID, actual.ParentUID) }) t.Run("should return ErrFolderNotFound when folder with title doesn't exist under specified parent", func(t *testing.T) { nonExistentTitle := "non-existent-folder" f, err := store.GetNamespaceByTitle(context.Background(), nonExistentTitle, 1, u, parentUID) require.Nil(t, f) require.ErrorIs(t, err, dashboards.ErrFolderNotFound) }) } func TestIntegration_GetOrCreateNamespaceByTitle(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } u := &user.SignedInUser{ UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, IsGrafanaAdmin: true, } setupStore := func(t *testing.T) *DBstore { sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) b := &fakeBus{} logger := log.New("test-dbstore") store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) store.FolderService = setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)) return store } t.Run("should create folder when it does not exist", func(t *testing.T) { store := setupStore(t) f, err := store.GetOrCreateNamespaceByTitle(context.Background(), "new folder", 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, "new folder", f.Title) require.NotEmpty(t, f.UID) require.Equal(t, folder.RootFolderUID, f.ParentUID) folders, err := store.FolderService.GetFolders( context.Background(), folder.GetFoldersQuery{ OrgID: 1, WithFullpath: true, SignedInUser: u, }, ) require.NoError(t, err) require.Len(t, folders, 1) }) t.Run("should return existing folder when it exists", func(t *testing.T) { store := setupStore(t) title := "existing folder" createFolder(t, store, "", title, 1, "") f, err := store.GetOrCreateNamespaceByTitle(context.Background(), title, 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, title, f.Title) folders, err := store.FolderService.GetFolders( context.Background(), folder.GetFoldersQuery{ OrgID: 1, WithFullpath: true, SignedInUser: u, }, ) require.NoError(t, err) require.Len(t, folders, 1) }) t.Run("should create folder under specified parent when it does not exist", func(t *testing.T) { store := setupStore(t) // Create parent folder first parentTitle := "parent folder" parentFolder, err := store.GetOrCreateNamespaceByTitle(context.Background(), parentTitle, 1, u, folder.RootFolderUID) require.NoError(t, err) // Now create a child folder under the parent childTitle := "child folder" childFolder, err := store.GetOrCreateNamespaceByTitle(context.Background(), childTitle, 1, u, parentFolder.UID) require.NoError(t, err) // Verify the child folder was created under the parent folders, err := store.FolderService.GetChildren(context.Background(), &folder.GetChildrenQuery{UID: parentFolder.UID, OrgID: 1, SignedInUser: u}) require.NoError(t, err) require.Len(t, folders, 1) require.Equal(t, childFolder.UID, folders[0].UID) folders, err = store.FolderService.GetChildren(context.Background(), &folder.GetChildrenQuery{UID: folder.RootFolderUID, OrgID: 1, SignedInUser: u}) require.NoError(t, err) require.Len(t, folders, 1) require.Equal(t, parentFolder.UID, folders[0].UID) }) t.Run("should get correct folder when same title exists under different parents", func(t *testing.T) { store := setupStore(t) // Create first parent folder parent1Title := "parent folder 1" parent1, err := store.GetOrCreateNamespaceByTitle(context.Background(), parent1Title, 1, u, folder.RootFolderUID) require.NoError(t, err) // Create second parent folder parent2Title := "parent folder 2" parent2, err := store.GetOrCreateNamespaceByTitle(context.Background(), parent2Title, 1, u, folder.RootFolderUID) require.NoError(t, err) // Create folders with same title under different parents sameTitle := "same title folder" // Create under first parent folder1, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent1.UID) require.NoError(t, err) // Create under second parent folder2, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent2.UID) require.NoError(t, err) // Create under root folder3, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, folder.RootFolderUID) require.NoError(t, err) // Verify we get the correct folders when specifying the parent gotFolder1, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent1.UID) require.NoError(t, err) require.Equal(t, folder1.UID, gotFolder1.UID) require.Equal(t, parent1.UID, gotFolder1.ParentUID) gotFolder2, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, parent2.UID) require.NoError(t, err) require.Equal(t, folder2.UID, gotFolder2.UID) require.Equal(t, parent2.UID, gotFolder2.ParentUID) gotFolder3, err := store.GetOrCreateNamespaceByTitle(context.Background(), sameTitle, 1, u, folder.RootFolderUID) require.NoError(t, err) require.Equal(t, folder3.UID, gotFolder3.UID) require.Equal(t, folder.RootFolderUID, gotFolder3.ParentUID) }) } func TestIntegration_GetNamespaceChildren(t *testing.T) { if testing.Short() { t.Skip("skipping integration test") } sqlStore := db.InitTestDB(t) cfg := setting.NewCfg() folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) b := &fakeBus{} logger := log.New("test-dbstore") store := createTestStore(sqlStore, folderService, logger, cfg.UnifiedAlerting, b) store.FolderService = setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)) admin := &user.SignedInUser{ UserID: 1, OrgID: 1, OrgRole: org.RoleAdmin, IsGrafanaAdmin: true, } // Create root folders rootFolder1 := uuid.NewString() rootFolder2 := uuid.NewString() createFolder(t, store, rootFolder1, "Root Folder 1", 1, "") createFolder(t, store, rootFolder2, "Root Folder 2", 1, "") // Create child folders under root folder 1 child1 := uuid.NewString() child2 := uuid.NewString() createFolder(t, store, child1, "Child Folder 1", 1, rootFolder1) createFolder(t, store, child2, "Child Folder 2", 1, rootFolder1) // Create nested child under child1 nestedChild := uuid.NewString() createFolder(t, store, nestedChild, "Nested Child", 1, child1) differentOrgID := int64(999) createFolder(t, store, util.GenerateShortUID(), "Root Folder 1", differentOrgID, "") /* * Folder structure: * * Root Folder 1 * - Child Folder 1 * - Nested Child * - Child Folder 2 * Root Folder 2 */ t.Run("should return direct children of a folder", func(t *testing.T) { children, err := store.GetNamespaceChildren(context.Background(), rootFolder1, 1, admin) require.NoError(t, err) require.Len(t, children, 2) require.ElementsMatch(t, []string{child1, child2}, []string{children[0].UID, children[1].UID}) // Verify parent UID for _, child := range children { require.Equal(t, rootFolder1, child.ParentUID) } }) t.Run("should return direct children of a nested folder", func(t *testing.T) { children, err := store.GetNamespaceChildren(context.Background(), child1, 1, admin) require.NoError(t, err) require.Len(t, children, 1) require.Equal(t, nestedChild, children[0].UID) require.Equal(t, child1, children[0].ParentUID) }) t.Run("should return nil when folder does not exist", func(t *testing.T) { nonExistentUID := uuid.NewString() children, err := store.GetNamespaceChildren(context.Background(), nonExistentUID, 1, admin) require.NotNil(t, children) require.Empty(t, children) require.Nil(t, err) }) t.Run("should return empty array for folders with no children", func(t *testing.T) { children, err := store.GetNamespaceChildren(context.Background(), rootFolder2, 1, admin) require.Empty(t, children) require.NotNil(t, children) require.Nil(t, err) }) t.Run("should return no children for a different org", func(t *testing.T) { children, err := store.GetNamespaceChildren(context.Background(), rootFolder1, differentOrgID, admin) require.Empty(t, children) require.Nil(t, err) }) t.Run("should return children from root folder", func(t *testing.T) { children, err := store.GetNamespaceChildren(context.Background(), "", 1, admin) require.NoError(t, err) require.Equal(t, len(children), 2) require.ElementsMatch(t, []string{rootFolder1, rootFolder2}, []string{children[0].UID, children[1].UID}) }) }