From 58c44f6c663c2b9f2c9175712986c82c4f2116c0 Mon Sep 17 00:00:00 2001 From: Leonor Oliveira <9090754+leonorfmartins@users.noreply.github.com> Date: Thu, 19 Dec 2024 17:56:14 +0100 Subject: [PATCH] Trim folder title (#98275) --- pkg/registry/apis/folders/register.go | 15 ++ pkg/registry/apis/folders/register_test.go | 203 +++++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index 3f9f868c31e..390965ab43c 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "slices" + "strings" "github.com/prometheus/client_golang/prometheus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -238,6 +239,20 @@ var folderValidationRules = struct { invalidNames: []string{"general"}, } +func (b *FolderAPIBuilder) Mutate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error { + verb := a.GetOperation() + if verb == admission.Create || verb == admission.Update { + obj := a.GetObject() + f, ok := obj.(*v0alpha1.Folder) + if !ok { + return fmt.Errorf("obj is not v0alpha1.Folder") + } + f.Spec.Title = strings.Trim(f.Spec.Title, "") + return nil + } + return nil +} + func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error { id := a.GetName() obj := a.GetObject() diff --git a/pkg/registry/apis/folders/register_test.go b/pkg/registry/apis/folders/register_test.go index 99335fc05a6..6d9211cfa26 100644 --- a/pkg/registry/apis/folders/register_test.go +++ b/pkg/registry/apis/folders/register_test.go @@ -577,3 +577,206 @@ func TestFolderAPIBuilder_Validate_Update(t *testing.T) { }) } } + +func TestFolderAPIBuilder_Mutate_Create(t *testing.T) { + tests := []struct { + name string + input *v0alpha1.Folder + expected *v0alpha1.Folder + wantErr bool + }{ + { + name: "should trim a title", + input: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{ + Title: " foo ", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + expected: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{ + Title: "foo", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + }, + { + name: "should return error if title doesnt exist", + input: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{}, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + wantErr: true, + }, + { + name: "should return error if spec doesnt exist", + input: &v0alpha1.Folder{ + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + wantErr: true, + }, + } + s := (grafanarest.Storage)(nil) + m := &mock.Mock{} + us := storageMock{m, s} + sm := searcherMock{Mock: m} + b := &FolderAPIBuilder{ + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders"), zanzana.NewNoopClient()), + searcher: sm, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := b.Validate(context.Background(), admission.NewAttributesRecord( + tt.input, + nil, + v0alpha1.SchemeGroupVersion.WithKind("folder"), + "stacks-123", + tt.input.Name, + v0alpha1.SchemeGroupVersion.WithResource("folders"), + "", + "CREATE", + nil, + true, + &user.SignedInUser{}, + ), nil) + + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} + +func TestFolderAPIBuilder_Mutate_Update(t *testing.T) { + existingObj := &v0alpha1.Folder{ + Spec: v0alpha1.Spec{ + Title: "some title", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + } + tests := []struct { + name string + input *v0alpha1.Folder + expected *v0alpha1.Folder + wantErr bool + }{ + { + name: "should trim a title", + input: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{ + Title: " foo ", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + expected: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{ + Title: "foo", + }, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + }, + { + name: "should return error if title doesnt exist", + input: &v0alpha1.Folder{ + Spec: v0alpha1.Spec{}, + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + wantErr: true, + }, + { + name: "should return error if spec doesnt exist", + input: &v0alpha1.Folder{ + TypeMeta: metav1.TypeMeta{ + Kind: "Folder", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "valid-name", + }, + }, + wantErr: true, + }, + } + s := (grafanarest.Storage)(nil) + m := &mock.Mock{} + us := storageMock{m, s} + sm := searcherMock{Mock: m} + b := &FolderAPIBuilder{ + gv: resourceInfo.GroupVersion(), + features: nil, + namespacer: func(_ int64) string { return "123" }, + folderSvc: foldertest.NewFakeService(), + storage: us, + accessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures("nestedFolders"), zanzana.NewNoopClient()), + searcher: sm, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := b.Validate(context.Background(), admission.NewAttributesRecord( + tt.input, + existingObj, + v0alpha1.SchemeGroupVersion.WithKind("folder"), + "stacks-123", + tt.input.Name, + v0alpha1.SchemeGroupVersion.WithResource("folders"), + "", + "UPDATE", + nil, + true, + &user.SignedInUser{}, + ), nil) + + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +}