package util import ( "reflect" "testing" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" ) func TestMergeAnnotation(t *testing.T) { tests := []struct { name string obj *unstructured.Unstructured annotationKey string annotationValue string expected *unstructured.Unstructured }{ { name: "nil annotations", obj: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, annotationKey: "foo", annotationValue: "bar", }, { name: "same annotationKey", obj: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, annotationKey: "foo", annotationValue: "bar1", }, { name: "new labelKey", obj: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar", "foo1": "bar1"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, annotationKey: "foo1", annotationValue: "bar1", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { MergeAnnotation(tt.obj, tt.annotationKey, tt.annotationValue) if !reflect.DeepEqual(tt.obj, tt.expected) { t.Errorf("MergeAnnotation() = %v, want %v", tt.obj, tt.expected) } }) } } func TestRetainAnnotations(t *testing.T) { tests := []struct { name string desired *unstructured.Unstructured observed *unstructured.Unstructured expected *unstructured.Unstructured }{ { name: "observed has nil annotations", desired: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, observed: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, { name: "observed has annotations", desired: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, observed: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, { name: "observed and desired have the same annotation key", desired: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "foo"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, observed: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{"foo": "bar"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{"foo": "foo"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, { name: "do not merge deleted annotations", desired: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{workv1alpha2.ManagedAnnotation: "karmada.io/annotations-managed-keyset"}, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, observed: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ workv1alpha2.ManagedAnnotation: "karmada.io/annotations-managed-keyset,deleted", "deleted": "deleted", "retain": "retain", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", "annotations": map[string]interface{}{ workv1alpha2.ManagedAnnotation: "karmada.io/annotations-managed-keyset", "retain": "retain", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { RetainAnnotations(tt.desired, tt.observed) if !reflect.DeepEqual(tt.desired, tt.expected) { t.Errorf("RetainAnnotations() = %v, want %v", tt.desired, tt.expected) } }) } } func TestGetAnnotationValue(t *testing.T) { tests := []struct { name string annotations map[string]string annotationKey string expected string }{ { name: "nil annotations", annotationKey: "foo", expected: "", }, { name: "annotationKey is not exist", annotations: map[string]string{"foo": "bar"}, annotationKey: "foo1", expected: "", }, { name: "existed annotationKey", annotations: map[string]string{"foo": "bar"}, annotationKey: "foo", expected: "bar", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res := GetAnnotationValue(tt.annotations, tt.annotationKey) if res != tt.expected { t.Errorf("MergeAnnotations() = %v, want %v", res, tt.expected) } }) } } func TestRecordManagedAnnotations(t *testing.T) { tests := []struct { name string object *unstructured.Unstructured expected *unstructured.Unstructured }{ { name: "nil annotation", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ workv1alpha2.ManagedAnnotation: "resourcetemplate.karmada.io/managed-annotations,resourcetemplate.karmada.io/managed-labels", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, { name: "object has has annotations", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ "foo": "foo", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ workv1alpha2.ManagedAnnotation: "foo,resourcetemplate.karmada.io/managed-annotations,resourcetemplate.karmada.io/managed-labels", "foo": "foo", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, { name: "object has has annotations and labels", object: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ "foo": "foo", }, "labels": map[string]interface{}{ "bar": "bar", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, expected: &unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment-1", "annotations": map[string]interface{}{ workv1alpha2.ManagedAnnotation: "foo,resourcetemplate.karmada.io/managed-annotations,resourcetemplate.karmada.io/managed-labels", "foo": "foo", }, "labels": map[string]interface{}{ "bar": "bar", }, }, "spec": map[string]interface{}{ "replicas": 2, }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { RecordManagedAnnotations(tt.object) if !reflect.DeepEqual(tt.object, tt.expected) { t.Errorf("RecordManagedAnnotations() = %v, want %v", tt.object, tt.expected) } }) } } func TestReplaceAnnotation(t *testing.T) { workload := unstructured.Unstructured{ Object: map[string]interface{}{ "apiVersion": "apps/v1", "kind": "Deployment", "metadata": map[string]interface{}{ "name": "demo-deployment", }, }, } workloadExistKey := workload.DeepCopy() workloadExistKey.SetAnnotations(map[string]string{"testKey": "oldValue"}) workloadNotExistKey := workload.DeepCopy() workloadNotExistKey.SetAnnotations(map[string]string{"anotherKey": "anotherValue"}) tests := []struct { name string obj *unstructured.Unstructured annotationKey string annotationValue string want map[string]string }{ { name: "nil annotation", obj: &workload, annotationKey: "testKey", annotationValue: "newValue", want: map[string]string{"testKey": "newValue"}, }, { name: "exist key", obj: workloadExistKey, annotationKey: "testKey", annotationValue: "newValue", want: map[string]string{"testKey": "newValue"}, }, { name: "not exist key", obj: workloadNotExistKey, annotationKey: "testKey", annotationValue: "newValue", want: map[string]string{"anotherKey": "anotherValue", "testKey": "newValue"}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ReplaceAnnotation(tt.obj, tt.annotationKey, tt.annotationValue) if !reflect.DeepEqual(tt.obj.GetAnnotations(), tt.want) { t.Errorf("ReplaceAnnotation(), obj.GetAnnotations = %v, want %v", tt.obj.GetAnnotations(), tt.want) } }) } }