package binding import ( "reflect" "testing" v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" "github.com/karmada-io/karmada/pkg/util/names" ) func Test_mergeTargetClusters(t *testing.T) { tests := []struct { name string targetClusters []workv1alpha2.TargetCluster requiredByBindingSnapshot []workv1alpha2.BindingSnapshot want []workv1alpha2.TargetCluster }{ { name: "the same cluster", targetClusters: []workv1alpha2.TargetCluster{ { Name: "foo", Replicas: 1, }, }, requiredByBindingSnapshot: []workv1alpha2.BindingSnapshot{ { Clusters: []workv1alpha2.TargetCluster{ { Name: "foo", Replicas: 1, }, }, }, }, want: []workv1alpha2.TargetCluster{ { Name: "foo", Replicas: 1, }, }, }, { name: "different clusters", targetClusters: []workv1alpha2.TargetCluster{ { Name: "foo", Replicas: 1, }, }, requiredByBindingSnapshot: []workv1alpha2.BindingSnapshot{ { Clusters: []workv1alpha2.TargetCluster{ { Name: "bar", Replicas: 1, }, }, }, }, want: []workv1alpha2.TargetCluster{ { Name: "foo", Replicas: 1, }, { Name: "bar", Replicas: 1, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := mergeTargetClusters(tt.targetClusters, tt.requiredByBindingSnapshot); !reflect.DeepEqual(got, tt.want) { t.Errorf("mergeTargetClusters() = %v, want %v", got, tt.want) } }) } } func Test_mergeLabel(t *testing.T) { namespace := "fake-ns" bindingName := "fake-bindingName" rbID := "93162d3c-ee8e-4995-9034-05f4d5d2c2b9" tests := []struct { name string workload *unstructured.Unstructured workNamespace string binding metav1.Object scope v1.ResourceScope want map[string]string }{ { name: "NamespaceScoped", workload: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "namespace": namespace, }, }, }, workNamespace: namespace, binding: &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: bindingName, Namespace: namespace, Labels: map[string]string{ workv1alpha2.ResourceBindingPermanentIDLabel: rbID, }, }, }, scope: v1.NamespaceScoped, want: map[string]string{ workv1alpha2.ResourceBindingPermanentIDLabel: rbID, workv1alpha2.ResourceBindingReferenceKey: names.GenerateBindingReferenceKey(namespace, bindingName), }, }, { name: "ClusterScoped", workload: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Namespace", "metadata": map[string]interface{}{ "name": "demo-ns", }, }, }, binding: &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: bindingName, Labels: map[string]string{ workv1alpha2.ClusterResourceBindingPermanentIDLabel: rbID, }, }, }, scope: v1.ClusterScoped, want: map[string]string{ workv1alpha2.ClusterResourceBindingPermanentIDLabel: rbID, workv1alpha2.ClusterResourceBindingReferenceKey: names.GenerateBindingReferenceKey("", bindingName), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := mergeLabel(tt.workload, tt.workNamespace, tt.binding, tt.scope); !reflect.DeepEqual(got, tt.want) { t.Errorf("mergeLabel() = %v, want %v", got, tt.want) } }) } } func Test_mergeAnnotations(t *testing.T) { namespace := "fake-ns" bindingName := "fake-bindingName" tests := []struct { name string namespace string workload *unstructured.Unstructured binding metav1.Object scope v1.ResourceScope want map[string]string }{ { name: "NamespaceScoped", namespace: "test", workload: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "namespace": namespace, }, }, }, binding: &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: bindingName, Namespace: namespace, }, }, scope: v1.NamespaceScoped, want: map[string]string{ workv1alpha2.ResourceBindingNamespaceAnnotationKey: namespace, workv1alpha2.ResourceBindingNameAnnotationKey: bindingName, }, }, { name: "ClusterScoped", namespace: "", workload: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "v1", "kind": "Namespace", "metadata": map[string]interface{}{ "name": "demo-ns", }, }, }, binding: &workv1alpha2.ClusterResourceBinding{ ObjectMeta: metav1.ObjectMeta{ Name: bindingName, }, }, scope: v1.ClusterScoped, want: map[string]string{ workv1alpha2.ClusterResourceBindingAnnotationKey: bindingName, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := mergeAnnotations(tt.workload, tt.namespace, tt.binding, tt.scope); !reflect.DeepEqual(got, tt.want) { t.Errorf("mergeAnnotations() = %v, want %v", got, tt.want) } }) } } func Test_mergeConflictResolution(t *testing.T) { namespace := "fake-ns" workload := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "test-deployment", "namespace": namespace, }, }, } workloadOverwrite := workload.DeepCopy() workloadOverwrite.SetAnnotations(map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionOverwrite}) workloadAbort := workload.DeepCopy() workloadAbort.SetAnnotations(map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionAbort}) workloadInvalid := workload.DeepCopy() workloadInvalid.SetAnnotations(map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: "unknown"}) tests := []struct { name string workload *unstructured.Unstructured conflictResolutionInBinding policyv1alpha1.ConflictResolution annotations map[string]string want map[string]string }{ { name: "EmptyInRT_OverwriteInRB", workload: &workload, conflictResolutionInBinding: policyv1alpha1.ConflictOverwrite, annotations: map[string]string{}, want: map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionOverwrite}, }, { name: "EmptyInRT_AbortInRB", workload: &workload, conflictResolutionInBinding: policyv1alpha1.ConflictAbort, annotations: map[string]string{}, want: map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionAbort}, }, { name: "OverwriteInRT_AbortInPP", workload: workloadOverwrite, conflictResolutionInBinding: policyv1alpha1.ConflictAbort, annotations: map[string]string{}, want: map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionOverwrite}, }, { name: "AbortInRT_OverwriteInPP", workload: workloadAbort, conflictResolutionInBinding: policyv1alpha1.ConflictOverwrite, annotations: map[string]string{}, want: map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionAbort}, }, { name: "InvalidInRT_OverwriteInPP", workload: workloadInvalid, conflictResolutionInBinding: policyv1alpha1.ConflictOverwrite, annotations: map[string]string{}, want: map[string]string{workv1alpha2.ResourceConflictResolutionAnnotation: workv1alpha2.ResourceConflictResolutionOverwrite}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := mergeConflictResolution(tt.workload, tt.conflictResolutionInBinding, tt.annotations); !reflect.DeepEqual(got, tt.want) { t.Errorf("mergeConflictResolution() = %v, want %v", got, tt.want) } }) } }