fix(unified-storage): make full path setting optional on get folders (#104757)

This commit is contained in:
Mustafa Sencer Özcan
2025-05-06 16:20:49 +02:00
committed by GitHub
parent fa93b3b74c
commit dc63f8003c
5 changed files with 223 additions and 233 deletions
+69 -72
View File
@@ -13,12 +13,13 @@ import (
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
)
func parseUnstructuredToLegacyFolder(item *unstructured.Unstructured) (*folder.Folder, string, string, error) {
func convertUnstructuredToFolder(item *unstructured.Unstructured, identifiers map[string]*user.User) (*folder.Folder, error) {
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, "", "", err
return nil, err
}
info, _ := authlib.ParseNamespace(meta.GetNamespace())
@@ -45,10 +46,20 @@ func parseUnstructuredToLegacyFolder(item *unstructured.Unstructured) (*folder.F
updated = &tmp
}
creator := meta.GetCreatedBy()
updater := meta.GetUpdatedBy()
if updater == "" {
updater = creator
createdBy, updatedBy := int64(0), int64(0)
createdByUID, updatedByUID := "", ""
if len(identifiers) > 0 {
user, ok := identifiers[meta.GetCreatedBy()]
if ok {
createdBy = user.ID
createdByUID = user.UID
}
user, ok = identifiers[meta.GetUpdatedBy()]
if ok {
updatedBy = user.ID
updatedByUID = user.UID
}
}
manager, _ := meta.GetManagerProperties()
@@ -67,90 +78,91 @@ func parseUnstructuredToLegacyFolder(item *unstructured.Unstructured) (*folder.F
Created: created,
Updated: *updated,
OrgID: info.OrgID,
}, creator, updater, nil
CreatedBy: createdBy,
CreatedByUID: createdByUID,
UpdatedBy: updatedBy,
UpdatedByUID: updatedByUID,
}, nil
}
func (ss *FolderUnifiedStoreImpl) UnstructuredToLegacyFolder(ctx context.Context, item *unstructured.Unstructured) (*folder.Folder, error) {
folder, creatorRaw, updaterRaw, err := parseUnstructuredToLegacyFolder(item)
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
userUIDtoIDmapping, err := ss.getUserUIDtoIDmappingFromIdentifiers(ctx, []string{creatorRaw, updaterRaw})
identifiers := make(map[string]struct{}, 0)
identifiers[meta.GetCreatedBy()] = struct{}{}
identifiers[meta.GetUpdatedBy()] = struct{}{}
folderUserIdentifiers, err := ss.getFolderIdentifiers(ctx, identifiers)
if err != nil {
return nil, err
}
creatorId := getIdFromMapping(creatorRaw, userUIDtoIDmapping)
updaterId := getIdFromMapping(updaterRaw, userUIDtoIDmapping)
if updaterId == 0 {
updaterId = creatorId
folder, err := convertUnstructuredToFolder(item, folderUserIdentifiers)
if err != nil {
return nil, err
}
folder.Version = int(item.GetGeneration())
folder.CreatedBy = creatorId
folder.UpdatedBy = updaterId
return folder, nil
}
func (ss *FolderUnifiedStoreImpl) UnstructuredToLegacyFolderList(ctx context.Context, unstructuredList *unstructured.UnstructuredList) ([]*folder.Folder, error) {
folders := make([]*folder.Folder, 0)
identifiers := make([]string, 0)
identifiers := make(map[string]struct{}, 0)
for _, item := range unstructuredList.Items {
meta, err := utils.MetaAccessor(&item)
if err != nil {
return nil, fmt.Errorf("unable to convert unstructured item to legacy folder %w", err)
}
identifiers = append(identifiers, meta.GetCreatedBy(), meta.GetUpdatedBy())
identifiers[meta.GetCreatedBy()] = struct{}{}
identifiers[meta.GetUpdatedBy()] = struct{}{}
}
userUIDtoIDmapping, err := ss.getUserUIDtoIDmappingFromIdentifiers(ctx, identifiers)
folderUserIdentifiers, err := ss.getFolderIdentifiers(ctx, identifiers)
if err != nil {
return nil, err
}
folders := make([]*folder.Folder, 0)
for _, item := range unstructuredList.Items {
folder, creatorRaw, updaterRaw, err := parseUnstructuredToLegacyFolder(&item)
folder, err := convertUnstructuredToFolder(&item, folderUserIdentifiers)
if err != nil {
return nil, err
}
creatorId := getIdFromMapping(creatorRaw, userUIDtoIDmapping)
updaterId := getIdFromMapping(updaterRaw, userUIDtoIDmapping)
if updaterId == 0 {
updaterId = creatorId
}
folder.Version = int(item.GetGeneration())
folder.CreatedBy = creatorId
folder.UpdatedBy = updaterId
folders = append(folders, folder)
}
return folders, nil
}
func (ss *FolderUnifiedStoreImpl) getUserUIDtoIDmappingFromIdentifiers(ctx context.Context, rawIdentifiers []string) (map[string]int64, error) {
userUIDs, userIds := parseIdentifiers(rawIdentifiers)
allUsers, err := ss.userService.ListByIdOrUID(ctx, userUIDs, userIds)
func (ss *FolderUnifiedStoreImpl) getFolderIdentifiers(ctx context.Context, identifiers map[string]struct{}) (map[string]*user.User, error) {
identifierMap, userUIDs, userIds := separateUIDsAndIDs(identifiers)
if len(userUIDs) == 0 && len(userIds) == 0 {
return nil, nil
}
users, err := ss.userService.ListByIdOrUID(ctx, userUIDs, userIds)
if err != nil {
return nil, err
}
mapping := make(map[string]int64)
for _, user := range allUsers {
mapping[user.UID] = user.ID
}
userMap := make(map[string]*user.User, len(users))
for _, u := range users {
if _, ok := identifierMap[fmt.Sprintf("user:%d", u.ID)]; ok {
userMap[fmt.Sprintf("user:%d", u.ID)] = u
}
return mapping, nil
if _, ok := identifierMap[fmt.Sprintf("user:%s", u.UID)]; ok {
userMap[fmt.Sprintf("user:%s", u.UID)] = u
}
}
return userMap, nil
}
func getIdentifier(rawIdentifier string) string {
parts := strings.Split(rawIdentifier, ":")
func parseIdentifier(identifier string) string {
parts := strings.Split(identifier, ":")
if len(parts) < 2 {
return ""
}
@@ -160,41 +172,26 @@ func getIdentifier(rawIdentifier string) string {
return parts[1]
}
func parseIdentifiers(rawIdentifiers []string) ([]string, []int64) {
func separateUIDsAndIDs(identifiers map[string]struct{}) (map[string]string, []string, []int64) {
uids := make([]string, 0)
ids := make([]int64, 0)
for _, rawIdentifier := range rawIdentifiers {
identifier := getIdentifier(rawIdentifier)
if identifier == "" {
identifierMap := make(map[string]string, 0)
for identifier := range identifiers {
value := parseIdentifier(identifier)
if value == "" {
continue
}
id, err := strconv.ParseInt(identifier, 10, 64)
identifierMap[identifier] = value
id, err := strconv.ParseInt(value, 10, 64)
if err == nil {
ids = append(ids, id)
} else if identifier != "" {
uids = append(uids, identifier)
} else {
uids = append(uids, value)
}
}
return uids, ids
}
func getIdFromMapping(rawIdentifier string, mapping map[string]int64) int64 {
identifier := getIdentifier(rawIdentifier)
if identifier == "" {
return 0
}
id, err := strconv.ParseInt(identifier, 10, 64)
if err == nil {
return id
}
uid, ok := mapping[identifier]
if ok {
return uid
}
return 0
return identifierMap, uids, ids
}
@@ -25,7 +25,7 @@ func TestFolderConversions(t *testing.T) {
"uid": "wfi3RARqQREzEKtUJCWurWevwbQ7i9ii0cA7JUIbMtEX",
"resourceVersion": "1734509107000",
"creationTimestamp": "2022-12-02T02:02:02Z",
"generation": 4,
"generation": 4,
"labels": {
"grafana.app/deprecatedInternalID": "234"
},
@@ -67,19 +67,21 @@ func TestFolderConversions(t *testing.T) {
require.Equal(t, 1, len(fake.ListUsersByIdOrUidCalls)) // only one call to the user service
require.Equal(t, usertest.ListUsersByIdOrUidCall{Uids: []string{"useruid"}, Ids: []int64{2}}, fake.ListUsersByIdOrUidCalls[0])
require.Equal(t, folder.Folder{
ID: 234,
OrgID: 1,
Version: 4,
UID: "be79sztagf20wd",
ParentUID: "parent-folder-name",
Title: "test folder",
Description: "Something set in the file",
URL: "/dashboards/f/be79sztagf20wd/test-folder",
ManagedBy: utils.ManagerKindRepo,
Created: created,
Updated: created.Add(time.Hour * 5),
CreatedBy: 1,
UpdatedBy: 2,
ID: 234,
OrgID: 1,
Version: 4,
UID: "be79sztagf20wd",
ParentUID: "parent-folder-name",
Title: "test folder",
Description: "Something set in the file",
URL: "/dashboards/f/be79sztagf20wd/test-folder",
ManagedBy: utils.ManagerKindRepo,
Created: created,
Updated: created.Add(time.Hour * 5),
CreatedBy: 1,
UpdatedBy: 2,
CreatedByUID: "useruid",
UpdatedByUID: "useruid2",
}, *converted)
}
@@ -117,7 +119,8 @@ func TestFolderListConversions(t *testing.T) {
"kind": "Folder",
"metadata": {
"annotations": {
"grafana.app/createdBy": "user:uuuuuuuuuuuuuu"
"grafana.app/createdBy": "user:uuuuuuuuuuuuuu",
"grafana.app/updatedBy": "user:uuuuuuuuuuuuuu"
},
"creationTimestamp": "2022-12-02T02:02:02Z",
"generation": 1,
@@ -162,7 +165,8 @@ func TestFolderListConversions(t *testing.T) {
"kind": "Folder",
"metadata": {
"annotations": {
"grafana.app/createdBy": "user:1"
"grafana.app/createdBy": "user:1",
"grafana.app/updatedBy": "user:1"
},
"creationTimestamp": "2022-12-02T02:02:02Z",
"generation": 1,
@@ -268,7 +272,8 @@ func TestFolderListConversions(t *testing.T) {
converted, err := fs.UnstructuredToLegacyFolderList(context.Background(), input)
require.NoError(t, err)
require.Equal(t, 1, len(fake.ListUsersByIdOrUidCalls)) // only one call to the user service
require.Equal(t, usertest.ListUsersByIdOrUidCall{Uids: []string{"uuuuuuuuuuuuuu", "iiiiiiiiiiiiii", "jjjjjjjjjjjjjj"}, Ids: []int64{1, 2, 3}}, fake.ListUsersByIdOrUidCalls[0])
require.ElementsMatch(t, []string{"uuuuuuuuuuuuuu", "iiiiiiiiiiiiii", "jjjjjjjjjjjjjj"}, fake.ListUsersByIdOrUidCalls[0].Uids)
require.ElementsMatch(t, []int64{1, 2, 3}, fake.ListUsersByIdOrUidCalls[0].Ids)
require.Equal(t, 6, len(converted))
require.Equal(t, []*folder.Folder{
{
@@ -287,64 +292,72 @@ func TestFolderListConversions(t *testing.T) {
UpdatedBy: 0, // service account,
},
{
ID: 149,
OrgID: 1,
Version: 1,
UID: "foldername2",
ParentUID: "",
Title: "yeye",
Description: "description yeye",
URL: "/dashboards/f/foldername2/yeye",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 4,
UpdatedBy: 4,
ID: 149,
OrgID: 1,
Version: 1,
UID: "foldername2",
ParentUID: "",
Title: "yeye",
Description: "description yeye",
URL: "/dashboards/f/foldername2/yeye",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 4,
UpdatedBy: 4,
CreatedByUID: "uuuuuuuuuuuuuu",
UpdatedByUID: "uuuuuuuuuuuuuu",
},
{
ID: 145,
OrgID: 1,
Version: 1,
UID: "foldername3",
ParentUID: "",
Title: "yoyo",
Description: "description yoyo",
URL: "/dashboards/f/foldername3/yoyo",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 5,
UpdatedBy: 6,
ID: 145,
OrgID: 1,
Version: 1,
UID: "foldername3",
ParentUID: "",
Title: "yoyo",
Description: "description yoyo",
URL: "/dashboards/f/foldername3/yoyo",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 5,
UpdatedBy: 6,
CreatedByUID: "iiiiiiiiiiiiii",
UpdatedByUID: "jjjjjjjjjjjjjj",
},
{
ID: 146,
OrgID: 1,
Version: 1,
UID: "foldername4",
ParentUID: "",
Title: "yaya",
Description: "description yaya",
URL: "/dashboards/f/foldername4/yaya",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 1,
UpdatedBy: 1,
ID: 146,
OrgID: 1,
Version: 1,
UID: "foldername4",
ParentUID: "",
Title: "yaya",
Description: "description yaya",
URL: "/dashboards/f/foldername4/yaya",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 1,
UpdatedBy: 1,
CreatedByUID: "aaaaaaaaaaaaaa",
UpdatedByUID: "aaaaaaaaaaaaaa",
},
{
ID: 147,
OrgID: 1,
Version: 1,
UID: "foldername5",
ParentUID: "",
Title: "yiyi",
Description: "description yiyi",
URL: "/dashboards/f/foldername5/yiyi",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 2,
UpdatedBy: 3,
ID: 147,
OrgID: 1,
Version: 1,
UID: "foldername5",
ParentUID: "",
Title: "yiyi",
Description: "description yiyi",
URL: "/dashboards/f/foldername5/yiyi",
ManagedBy: "",
Created: created,
Updated: created,
CreatedBy: 2,
UpdatedBy: 3,
CreatedByUID: "oooooooooooooo",
UpdatedByUID: "eeeeeeeeeeeeee",
},
{
ID: 148,
+4 -17
View File
@@ -353,14 +353,9 @@ func (s *Service) GetLegacy(ctx context.Context, q *folder.GetFolderQuery) (*fol
return f, err
}
func (s *Service) setFullpath(ctx context.Context, f *folder.Folder, user identity.Requester, forceLegacy bool) (*folder.Folder, error) {
func (s *Service) setFullpath(ctx context.Context, f *folder.Folder, forceLegacy bool) (*folder.Folder, error) {
ctx, span := s.tracer.Start(ctx, "folder.setFullpath")
defer span.End()
// #TODO is some kind of intermediate conversion required as is the case with user id where
// it gets parsed using UserIdentifier(). Also is there some kind of validation taking place as
// part of the parsing?
f.CreatedByUID = user.GetUID()
f.UpdatedByUID = user.GetUID()
if f.ParentUID == "" {
return f, nil
@@ -386,15 +381,7 @@ func (s *Service) setFullpath(ctx context.Context, f *folder.Folder, user identi
}
// #TODO revisit setting permissions so that we can centralise the logic for escaping slashes in titles
// Escape forward slashes in the title
escapedSlash := "\\/"
title := strings.ReplaceAll(f.Title, "/", escapedSlash)
f.Fullpath = title
f.FullpathUIDs = f.UID
for _, p := range parents {
pt := strings.ReplaceAll(p.Title, "/", escapedSlash)
f.Fullpath = f.Fullpath + "/" + pt
f.FullpathUIDs = f.FullpathUIDs + "/" + p.UID
}
f.Fullpath, f.FullpathUIDs = computeFullPath(append(parents, f))
return f, nil
}
@@ -573,7 +560,7 @@ func (s *Service) GetSharedWithMe(ctx context.Context, q *folder.GetChildrenQuer
return nil, folder.ErrInternal.Errorf("failed to fetch root folders to which the user has access: %w", err)
}
dedupAvailableNonRootFolders := s.deduplicateAvailableFolders(ctx, availableNonRootFolders, rootFolders, q.OrgID)
dedupAvailableNonRootFolders := s.deduplicateAvailableFolders(ctx, availableNonRootFolders, rootFolders)
s.metrics.sharedWithMeFetchFoldersRequestsDuration.WithLabelValues("success").Observe(time.Since(start).Seconds())
return dedupAvailableNonRootFolders, nil
}
@@ -641,7 +628,7 @@ func (s *Service) getAvailableNonRootFolders(ctx context.Context, q *folder.GetC
return nonRootFolders, nil
}
func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*folder.Folder, rootFolders []*folder.FolderReference, orgID int64) []*folder.FolderReference {
func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*folder.Folder, rootFolders []*folder.FolderReference) []*folder.FolderReference {
foldersRef := make([]*folder.FolderReference, len(folders))
for i, f := range folders {
foldersRef[i] = f.ToFolderReference()
@@ -151,9 +151,11 @@ func (s *Service) getFromApiServer(ctx context.Context, q *folder.GetFolderQuery
f.ID = dashFolder.ID
f.Version = dashFolder.Version
f, err = s.setFullpath(ctx, f, q.SignedInUser, false)
if err != nil {
return nil, err
if q.WithFullpath || q.WithFullpathUIDs {
f, err = s.setFullpath(ctx, f, false)
if err != nil {
return nil, err
}
}
return f, err
@@ -512,8 +514,6 @@ func (s *Service) createOnApiServer(ctx context.Context, cmd *folder.CreateFolde
return nil, dashboards.ErrFolderInvalidUID
}
user := cmd.SignedInUser
cmd = &folder.CreateFolderCommand{
// TODO: Today, if a UID isn't specified, the dashboard store
// generates a new UID. The new folder store will need to do this as
@@ -531,11 +531,6 @@ func (s *Service) createOnApiServer(ctx context.Context, cmd *folder.CreateFolde
return nil, err
}
f, err = s.setFullpath(ctx, f, user, false)
if err != nil {
return nil, err
}
return f, nil
}
@@ -15,7 +15,7 @@ import (
"k8s.io/apimachinery/pkg/selection"
clientrest "k8s.io/client-go/rest"
foldersv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
folderv1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/bus"
@@ -77,19 +77,19 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
t.Skip("skipping integration test")
}
m := map[string]foldersv1.Folder{}
m := map[string]folderv1.Folder{}
unifiedStorageFolder := &foldersv1.Folder{}
unifiedStorageFolder := &folderv1.Folder{}
unifiedStorageFolder.Kind = "folder"
fooFolder := &folder.Folder{
ID: 123,
Title: "Foo Folder",
OrgID: orgID,
UID: "foo",
URL: "/dashboards/f/foo/foo-folder",
CreatedByUID: "user:1",
UpdatedByUID: "user:1",
ID: 123,
Title: "Foo Folder",
OrgID: orgID,
UID: "foo",
URL: "/dashboards/f/foo/foo-folder",
CreatedBy: 1,
UpdatedBy: 1,
}
updateFolder := &folder.Folder{
@@ -106,7 +106,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
mux.HandleFunc("GET /apis/folder.grafana.app/v1beta1/namespaces/default/folders", func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
l := &foldersv1.FolderList{}
l := &folderv1.FolderList{}
l.Kind = "Folder"
err := json.NewEncoder(w).Encode(l)
require.NoError(t, err)
@@ -137,7 +137,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
buf, err := io.ReadAll(req.Body)
require.NoError(t, err)
var foldr foldersv1.Folder
var foldr folderv1.Folder
err = json.Unmarshal(buf, &foldr)
require.NoError(t, err)
@@ -166,7 +166,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
buf, err := io.ReadAll(req.Body)
require.NoError(t, err)
var folder foldersv1.Folder
var folder folderv1.Folder
err = json.Unmarshal(buf, &folder)
require.NoError(t, err)
@@ -202,7 +202,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
features := featuremgmt.WithFeatures(featuresArr...)
dashboardStore := dashboards.NewFakeDashboardStore(t)
k8sCli := client.NewK8sHandler(dualwrite.ProvideTestService(), request.GetNamespaceMapper(cfg), foldersv1.FolderResourceInfo.GroupVersionResource(), restCfgProvider.GetRestConfig, dashboardStore, userService, nil, sort.ProvideService())
k8sCli := client.NewK8sHandler(dualwrite.ProvideTestService(), request.GetNamespaceMapper(cfg), folderv1.FolderResourceInfo.GroupVersionResource(), restCfgProvider.GetRestConfig, dashboardStore, userService, nil, sort.ProvideService())
unifiedStore := ProvideUnifiedStore(k8sCli, userService)
ctx := context.Background()
@@ -315,12 +315,12 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
ctx = identity.WithRequester(context.Background(), usr)
f := &folder.Folder{
OrgID: orgID,
Title: "Test-Folder",
UID: "testfolder",
URL: "/dashboards/f/testfolder/test-folder",
CreatedByUID: "user:1",
UpdatedByUID: "user:1",
OrgID: orgID,
Title: "Test-Folder",
UID: "testfolder",
URL: "/dashboards/f/testfolder/test-folder",
CreatedBy: 1,
UpdatedBy: 1,
}
t.Run("When creating folder should not return access denied error", func(t *testing.T) {
@@ -559,8 +559,8 @@ func TestSearchFoldersFromApiServer(t *testing.T) {
Options: &resource.ListOptions{
Key: &resource.ResourceKey{
Namespace: "default",
Group: foldersv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: foldersv1.FolderResourceInfo.GroupVersionResource().Resource,
Group: folderv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource,
},
Fields: []*resource.Requirement{
{
@@ -649,8 +649,8 @@ func TestSearchFoldersFromApiServer(t *testing.T) {
Options: &resource.ListOptions{
Key: &resource.ResourceKey{
Namespace: "default",
Group: foldersv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: foldersv1.FolderResourceInfo.GroupVersionResource().Resource,
Group: folderv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource,
},
Fields: []*resource.Requirement{},
Labels: []*resource.Requirement{
@@ -718,8 +718,8 @@ func TestSearchFoldersFromApiServer(t *testing.T) {
Options: &resource.ListOptions{
Key: &resource.ResourceKey{
Namespace: "default",
Group: foldersv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: foldersv1.FolderResourceInfo.GroupVersionResource().Resource,
Group: folderv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource,
},
Fields: []*resource.Requirement{},
Labels: []*resource.Requirement{},
@@ -798,8 +798,13 @@ func TestGetFoldersFromApiServer(t *testing.T) {
user := &user.SignedInUser{OrgID: 1}
ctx := identity.WithRequester(context.Background(), user)
fakeK8sClient.On("GetNamespace", mock.Anything, mock.Anything).Return("default")
folderkey := &resource.ResourceKey{
Namespace: "default",
Group: folderv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: folderv1.FolderResourceInfo.GroupVersionResource().Resource,
}
t.Run("Get folder by title)", func(t *testing.T) {
t.Run("Get folder by title", func(t *testing.T) {
// the search here will return a parent, this will be the parent folder returned when we query for it to add to the hit info
fakeFolderStore := folder.NewFakeStore()
fakeFolderStore.ExpectedFolder = &folder.Folder{
@@ -813,57 +818,50 @@ func TestGetFoldersFromApiServer(t *testing.T) {
service.unifiedStore = fakeFolderStore
fakeK8sClient.On("Search", mock.Anything, int64(1), &resource.ResourceSearchRequest{
Options: &resource.ListOptions{
Key: &resource.ResourceKey{
Namespace: "default",
Group: foldersv1.FolderResourceInfo.GroupVersionResource().Group,
Resource: foldersv1.FolderResourceInfo.GroupVersionResource().Resource,
},
Key: folderkey,
Fields: []*resource.Requirement{},
Labels: []*resource.Requirement{},
},
Query: "foo title",
Limit: folderSearchLimit}).Return(&resource.ResourceSearchResponse{
Results: &resource.ResourceTable{
Columns: []*resource.ResourceTableColumnDefinition{
{
Name: "title",
Type: resource.ResourceTableColumnDefinition_STRING,
},
{
Name: "folder",
Type: resource.ResourceTableColumnDefinition_STRING,
},
},
Rows: []*resource.ResourceTableRow{
{
Key: &resource.ResourceKey{
Name: "uid",
Resource: "folder",
Limit: folderSearchLimit}).
Return(&resource.ResourceSearchResponse{
Results: &resource.ResourceTable{
Columns: []*resource.ResourceTableColumnDefinition{
{
Name: "title",
Type: resource.ResourceTableColumnDefinition_STRING,
},
Cells: [][]byte{
[]byte("foouid"),
[]byte("parentuid"),
{
Name: "folder",
Type: resource.ResourceTableColumnDefinition_STRING,
},
},
Rows: []*resource.ResourceTableRow{
{
Key: &resource.ResourceKey{
Name: "uid",
Resource: "folder",
},
Cells: [][]byte{
[]byte("foouid"),
[]byte("parentuid"),
},
},
},
},
},
TotalHits: 1,
}, nil).Once()
TotalHits: 1,
}, nil).Once()
result, err := service.getFolderByTitleFromApiServer(ctx, 1, "foo title", nil)
require.NoError(t, err)
expectedResult := &folder.Folder{
ID: 2,
UID: "foouid",
ParentUID: "parentuid",
Title: "foo title",
OrgID: 1,
URL: "/dashboards/f/foouid/foo-title",
Fullpath: "foo title",
FullpathUIDs: "foouid",
CreatedByUID: ":0",
UpdatedByUID: ":0",
ID: 2,
UID: "foouid",
ParentUID: "parentuid",
Title: "foo title",
OrgID: 1,
URL: "/dashboards/f/foouid/foo-title",
}
compareFoldersNormalizeTime(t, expectedResult, result)
fakeK8sClient.AssertExpectations(t)