From effcc6c8998ad4012707dc2634bc5ac63c3a6f57 Mon Sep 17 00:00:00 2001 From: xovoxy Date: Fri, 9 Aug 2024 21:51:39 +0800 Subject: [PATCH] Improve test coverage for /pkg/controllers/binding Signed-off-by: xovoxy --- .../binding/binding_controller_test.go | 176 ++++++- ...luster_resource_binding_controller_test.go | 434 ++++++++++++++++++ 2 files changed, 593 insertions(+), 17 deletions(-) create mode 100644 pkg/controllers/binding/cluster_resource_binding_controller_test.go diff --git a/pkg/controllers/binding/binding_controller_test.go b/pkg/controllers/binding/binding_controller_test.go index 726d3f58b..70d813d98 100644 --- a/pkg/controllers/binding/binding_controller_test.go +++ b/pkg/controllers/binding/binding_controller_test.go @@ -34,10 +34,12 @@ import ( controllerruntime "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" testing2 "github.com/karmada-io/karmada/pkg/search/proxy/testing" + "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" "github.com/karmada-io/karmada/pkg/util/gclient" testing3 "github.com/karmada-io/karmada/pkg/util/testing" @@ -257,19 +259,15 @@ func TestResourceBindingController_newOverridePolicyFunc(t *testing.T) { Name: "pod", } tests := []struct { - name string - want bool - obIsNil bool + name string + want []reconcile.Request + req client.Object + rb *workv1alpha2.ResourceBinding }{ { - name: "newOverridePolicyFunc success test", - want: false, - obIsNil: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tempOP := &policyv1alpha1.OverridePolicy{ + name: "newOverridePolicyFunc success test", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: "default", Name: "test-rb"}}}, + req: &policyv1alpha1.OverridePolicy{ ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{ { @@ -279,18 +277,162 @@ func TestResourceBindingController_newOverridePolicyFunc(t *testing.T) { Name: rs.Name, }, }}, - } + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "namespace not match", + want: nil, + req: &policyv1alpha1.OverridePolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, + Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: rs.APIVersion, + Kind: rs.Kind, + Namespace: rs.Namespace, + Name: rs.Name, + }, + }}, + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "test", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "ResourceSelector is empty", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: "default", Name: "test-rb"}}}, + req: &policyv1alpha1.OverridePolicy{ + ObjectMeta: metav1.ObjectMeta{Namespace: rs.Namespace}, + Spec: policyv1alpha1.OverrideSpec{ResourceSelectors: []policyv1alpha1.ResourceSelector{}}, + }, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "client is nil", + want: nil, + req: nil, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-rb", + Namespace: "default", + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { c, makeErr := makeFakeRBCByResource(&rs) if makeErr != nil { t.Errorf("makeFakeRBCByResource %v", makeErr) return } - got := c.newOverridePolicyFunc() - if (got == nil) != tt.want { - t.Errorf("newOverridePolicyFunc() is not same as want:%v", tt.want) + + if tt.rb != nil { + if err := c.Client.Create(context.Background(), tt.rb); err != nil { + t.Errorf("create rb %v", err) + return + } } - if (got(context.TODO(), client.Object(tempOP)) == nil) == tt.obIsNil { - t.Errorf("newOverridePolicyFunc() got() result is not same as want: %v", tt.obIsNil) + + got := c.newOverridePolicyFunc() + result := got(context.Background(), tt.req) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("newOverridePolicyFunc() got() result is %v not same as want: %v", result, tt.want) + } + }) + } +} + +func TestResourceBindingController_removeFinalizer(t *testing.T) { + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + rb *workv1alpha2.ResourceBinding + create bool + }{ + { + name: "Remove finalizer succeed", + want: controllerruntime.Result{}, + wantErr: false, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.BindingControllerFinalizer}, + }, + }, + create: true, + }, + { + name: "finalizers not exist", + want: controllerruntime.Result{}, + wantErr: false, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + create: true, + }, + { + name: "rb not found", + want: controllerruntime.Result{}, + wantErr: true, + rb: &workv1alpha2.ResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.BindingControllerFinalizer}, + }, + }, + create: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeRBCByResource(nil) + if err != nil { + t.Fatalf("Failed to create ClusterResourceBindingController: %v", err) + } + + if tt.create && tt.rb != nil { + if err := c.Client.Create(context.Background(), tt.rb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + result, err := c.removeFinalizer(context.Background(), tt.rb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.removeFinalizer() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.removeFinalizer() = %v, want %v", result, tt.want) } }) } diff --git a/pkg/controllers/binding/cluster_resource_binding_controller_test.go b/pkg/controllers/binding/cluster_resource_binding_controller_test.go new file mode 100644 index 000000000..22572b493 --- /dev/null +++ b/pkg/controllers/binding/cluster_resource_binding_controller_test.go @@ -0,0 +1,434 @@ +/* +Copyright 2024 The Karmada Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package binding + +import ( + "context" + "fmt" + "reflect" + "testing" + + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + fakedynamic "k8s.io/client-go/dynamic/fake" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/tools/record" + controllerruntime "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + testing2 "github.com/karmada-io/karmada/pkg/search/proxy/testing" + "github.com/karmada-io/karmada/pkg/util" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" + "github.com/karmada-io/karmada/pkg/util/gclient" + testing3 "github.com/karmada-io/karmada/pkg/util/testing" + "github.com/karmada-io/karmada/test/helper" +) + +func makeFakeCRBCByResource(rs *workv1alpha2.ObjectReference) (*ClusterResourceBindingController, error) { + tempDyClient := fakedynamic.NewSimpleDynamicClient(scheme.Scheme) + if rs == nil { + return &ClusterResourceBindingController{ + Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), + RESTMapper: testing2.RestMapper, + InformerManager: genericmanager.NewSingleClusterInformerManager(tempDyClient, 0, nil), + DynamicClient: tempDyClient, + }, nil + } + + var obj runtime.Object + var src string + switch rs.Kind { + case "Namespace": + obj = &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Namespace: "", Name: rs.Name}} + src = "namespaces" + default: + return nil, fmt.Errorf("%s not support yet, pls add for it", rs.Kind) + } + + tempDyClient.Resources = []*metav1.APIResourceList{ + { + GroupVersion: appsv1.SchemeGroupVersion.String(), + APIResources: []metav1.APIResource{ + {Name: rs.Name, Namespaced: true, Kind: rs.Kind, Version: rs.APIVersion}, + }, + }, + } + + return &ClusterResourceBindingController{ + Client: fake.NewClientBuilder().WithScheme(gclient.NewSchema()).Build(), + RESTMapper: helper.NewGroupRESTMapper(rs.Kind, meta.RESTScopeNamespace), + InformerManager: testing3.NewSingleClusterInformerManagerByRS(src, obj), + DynamicClient: tempDyClient, + EventRecorder: record.NewFakeRecorder(1024), + }, nil +} + +func TestClusterResourceBindingController_Reconcile(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + req := controllerruntime.Request{NamespacedName: client.ObjectKey{Namespace: "", Name: "test"}} + + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + del bool + req controllerruntime.Request + }{ + { + name: "Reconcile create crb", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + req: req, + }, + { + name: "Reconcile crb deleted", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + del: true, + req: req, + }, + { + name: "Req not found", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-noexist", + }, + }, + req: req, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("%s", err) + } + + if tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + if tt.del { + if err := c.Client.Delete(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to delete ClusterResourceBinding: %v", err) + } + } + + result, err := c.Reconcile(context.Background(), req) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.Reconcile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.Reconcile() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_removeFinalizer(t *testing.T) { + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + create bool + }{ + { + name: "Remove finalizer succeed", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + }, + create: true, + }, + { + name: "finalizers not exist", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + }, + }, + create: true, + }, + { + name: "crb not found", + want: controllerruntime.Result{}, + wantErr: true, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + }, + create: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(nil) + if err != nil { + t.Fatalf("Failed to create ClusterResourceBindingController: %v", err) + } + + if tt.create && tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + result, err := c.removeFinalizer(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.removeFinalizer() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.removeFinalizer() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_syncBinding(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + tests := []struct { + name string + want controllerruntime.Result + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "sync binding", + want: controllerruntime.Result{}, + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + result, err := c.syncBinding(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.syncBinding() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.syncBinding() = %v, want %v", result, tt.want) + } + }) + } +} + +func TestClusterResourceBindingController_removeOrphanWorks(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + tests := []struct { + name string + wantErr bool + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "removeOrphanWorks test", + wantErr: false, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + err = c.removeOrphanWorks(context.Background(), tt.crb) + if (err != nil) != tt.wantErr { + t.Errorf("ClusterResourceBindingController.syncBinding() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} + +func TestClusterResourceBindingController_newOverridePolicyFunc(t *testing.T) { + rs := workv1alpha2.ObjectReference{ + APIVersion: "v1", + Kind: "Namespace", + Name: "test", + } + + tests := []struct { + name string + want []reconcile.Request + req client.Object + crb *workv1alpha2.ClusterResourceBinding + }{ + { + name: "not clusteroverridepolicy", + want: nil, + req: &policyv1alpha1.OverridePolicy{}, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "newOverridePolicyFunc test succeed", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Name: rs.Name}}}, + req: &policyv1alpha1.ClusterOverridePolicy{ + Spec: policyv1alpha1.OverrideSpec{ + ResourceSelectors: []policyv1alpha1.ResourceSelector{ + { + APIVersion: rs.APIVersion, + Kind: rs.Kind, + Name: rs.Name, + }, + }, + }, + }, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + { + name: "ResourceSelector is empty", + want: []reconcile.Request{{NamespacedName: types.NamespacedName{Name: rs.Name}}}, + req: &policyv1alpha1.ClusterOverridePolicy{ + Spec: policyv1alpha1.OverrideSpec{ + ResourceSelectors: []policyv1alpha1.ResourceSelector{}, + }, + }, + crb: &workv1alpha2.ClusterResourceBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: map[string]string{"clusterresourcebinding.karmada.io/permanent-id": "f2603cdb-f3f3-4a4b-b289-3186a4fef979"}, + Finalizers: []string{util.ClusterResourceBindingControllerFinalizer}, + }, + Spec: workv1alpha2.ResourceBindingSpec{ + Resource: rs, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c, err := makeFakeCRBCByResource(&rs) + if err != nil { + t.Fatalf("failed to create fake ClusterResourceBindingController: %v", err) + } + + if tt.crb != nil { + if err := c.Client.Create(context.Background(), tt.crb); err != nil { + t.Fatalf("Failed to create ClusterResourceBinding: %v", err) + } + } + + got := c.newOverridePolicyFunc() + result := got(context.Background(), tt.req) + if !reflect.DeepEqual(result, tt.want) { + t.Errorf("ClusterResourceBindingController.newOverridePolicyFunc() get = %v, want %v", result, tt.want) + return + } + }) + } +}