Folders: Add max depth check with descendant to /apis (#115305)
This commit is contained in:
@@ -282,6 +282,7 @@ func TestValidateUpdate(t *testing.T) {
|
||||
old *folders.Folder
|
||||
parents *folders.FolderInfoList
|
||||
parentsError error
|
||||
allFolders []folders.Folder
|
||||
expectedErr string
|
||||
maxDepth int // defaults to 5 unless set
|
||||
}{
|
||||
@@ -454,6 +455,74 @@ func TestValidateUpdate(t *testing.T) {
|
||||
},
|
||||
expectedErr: "cannot move folder under its own descendant",
|
||||
},
|
||||
{
|
||||
name: "error when moving folder from root to level2 with children exceeds max depth",
|
||||
folder: &folders.Folder{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "folderWithChildren",
|
||||
Annotations: map[string]string{
|
||||
utils.AnnoKeyFolder: "level2",
|
||||
},
|
||||
},
|
||||
Spec: folders.FolderSpec{
|
||||
Title: "folder with children",
|
||||
},
|
||||
},
|
||||
old: &folders.Folder{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "folderWithChildren",
|
||||
},
|
||||
Spec: folders.FolderSpec{
|
||||
Title: "folder with children",
|
||||
},
|
||||
},
|
||||
parents: &folders.FolderInfoList{
|
||||
Items: []folders.FolderInfo{
|
||||
{Name: "level2", Parent: "level1"},
|
||||
{Name: "level1", Parent: folder.GeneralFolderUID},
|
||||
{Name: folder.GeneralFolderUID},
|
||||
},
|
||||
},
|
||||
allFolders: []folders.Folder{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "child1", Annotations: map[string]string{utils.AnnoKeyFolder: "folderWithChildren"}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "grandchild1", Annotations: map[string]string{utils.AnnoKeyFolder: "child1"}}},
|
||||
},
|
||||
maxDepth: 4,
|
||||
expectedErr: "[folder.maximum-depth-reached]",
|
||||
},
|
||||
{
|
||||
name: "can move folder from root level to level1 with children when within max depth",
|
||||
folder: &folders.Folder{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "folderWithChildren",
|
||||
Annotations: map[string]string{
|
||||
utils.AnnoKeyFolder: "level1",
|
||||
},
|
||||
},
|
||||
Spec: folders.FolderSpec{
|
||||
Title: "folder with children",
|
||||
},
|
||||
},
|
||||
old: &folders.Folder{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "folderWithChildren",
|
||||
},
|
||||
Spec: folders.FolderSpec{
|
||||
Title: "folder with children",
|
||||
},
|
||||
},
|
||||
parents: &folders.FolderInfoList{
|
||||
Items: []folders.FolderInfo{
|
||||
{Name: "level1", Parent: folder.GeneralFolderUID},
|
||||
{Name: folder.GeneralFolderUID},
|
||||
},
|
||||
},
|
||||
allFolders: []folders.Folder{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "child1", Annotations: map[string]string{utils.AnnoKeyFolder: "folderWithChildren"}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "grandchild1", Annotations: map[string]string{utils.AnnoKeyFolder: "child1"}}},
|
||||
},
|
||||
maxDepth: 4,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -474,11 +543,17 @@ func TestValidateUpdate(t *testing.T) {
|
||||
}, nil).Maybe()
|
||||
}
|
||||
}
|
||||
for i := range tt.allFolders {
|
||||
f := tt.allFolders[i]
|
||||
m.On("Get", context.Background(), f.Name, &metav1.GetOptions{}).Return(&f, nil).Maybe()
|
||||
}
|
||||
|
||||
err := validateOnUpdate(context.Background(), tt.folder, tt.old, m,
|
||||
func(ctx context.Context, folder *folders.Folder) (*folders.FolderInfoList, error) {
|
||||
return tt.parents, tt.parentsError
|
||||
}, maxDepth)
|
||||
},
|
||||
&mockSearchClient{folders: tt.allFolders},
|
||||
maxDepth)
|
||||
|
||||
if tt.expectedErr == "" {
|
||||
require.NoError(t, err)
|
||||
@@ -693,8 +768,7 @@ type mockSearchClient struct {
|
||||
stats *resourcepb.ResourceStatsResponse
|
||||
statsErr error
|
||||
|
||||
search *resourcepb.ResourceSearchResponse
|
||||
searchErr error
|
||||
folders []folders.Folder
|
||||
}
|
||||
|
||||
// GetStats implements resourcepb.ResourceIndexClient.
|
||||
@@ -703,8 +777,37 @@ func (m *mockSearchClient) GetStats(ctx context.Context, in *resourcepb.Resource
|
||||
}
|
||||
|
||||
// Search implements resourcepb.ResourceIndexClient.
|
||||
func (m *mockSearchClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) {
|
||||
return m.search, m.searchErr
|
||||
func (m *mockSearchClient) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) {
|
||||
// get the list of parents from the search request
|
||||
parentSet := make(map[string]bool)
|
||||
if req.Options != nil && req.Options.Fields != nil {
|
||||
for _, field := range req.Options.Fields {
|
||||
if field.Key == "folder" && field.Operator == "in" {
|
||||
for _, v := range field.Values {
|
||||
parentSet[v] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find children that match the parent filter
|
||||
var rows []*resourcepb.ResourceTableRow
|
||||
for i := range m.folders {
|
||||
meta, err := utils.MetaAccessor(&m.folders[i])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
parentUID := meta.GetFolder()
|
||||
if parentSet[parentUID] {
|
||||
rows = append(rows, &resourcepb.ResourceTableRow{
|
||||
Key: &resourcepb.ResourceKey{Name: m.folders[i].Name},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &resourcepb.ResourceSearchResponse{
|
||||
Results: &resourcepb.ResourceTable{Rows: rows},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// RebuildIndexes implements resourcepb.ResourceIndexClient.
|
||||
|
||||
Reference in New Issue
Block a user