package helper import ( "context" "reflect" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" "sigs.k8s.io/controller-runtime/pkg/client/fake" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" "github.com/karmada-io/karmada/pkg/util" ) func TestSetDefaultSpreadConstraints(t *testing.T) { tests := []struct { name string spreadConstraint []policyv1alpha1.SpreadConstraint expectedSpreadConstraint []policyv1alpha1.SpreadConstraint }{ { name: "set spreadByField", spreadConstraint: []policyv1alpha1.SpreadConstraint{ { MinGroups: 1, }, }, expectedSpreadConstraint: []policyv1alpha1.SpreadConstraint{ { SpreadByField: policyv1alpha1.SpreadByFieldCluster, MinGroups: 1, }, }, }, { name: "set minGroups", spreadConstraint: []policyv1alpha1.SpreadConstraint{ { SpreadByField: policyv1alpha1.SpreadByFieldCluster, }, }, expectedSpreadConstraint: []policyv1alpha1.SpreadConstraint{ { SpreadByField: policyv1alpha1.SpreadByFieldCluster, MinGroups: 1, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { SetDefaultSpreadConstraints(tt.spreadConstraint) if !reflect.DeepEqual(tt.spreadConstraint, tt.expectedSpreadConstraint) { t.Errorf("expected: %v, but got %v", tt.expectedSpreadConstraint, tt.spreadConstraint) } }) } } func TestIsDependentOverridesPresent(t *testing.T) { tests := []struct { name string policy *policyv1alpha1.PropagationPolicy policyCreated bool expectedExist bool }{ { name: "dependent override policy exist", policy: &policyv1alpha1.PropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "bar", }, Spec: policyv1alpha1.PropagationSpec{ DependentOverrides: []string{"foo"}, }, }, policyCreated: true, expectedExist: true, }, { name: "dependent override policy do not exist", policy: &policyv1alpha1.PropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: "bar", }, Spec: policyv1alpha1.PropagationSpec{ DependentOverrides: []string{"foo"}, }, }, policyCreated: false, expectedExist: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(Schema).Build() if tt.policyCreated { testOverridePolicy := &policyv1alpha1.OverridePolicy{ ObjectMeta: metav1.ObjectMeta{ Namespace: tt.policy.Namespace, Name: tt.policy.Name, }, } err := fakeClient.Create(context.TODO(), testOverridePolicy) if err != nil { t.Fatalf("failed to create overridePolicy, err is: %v", err) } } res, err := IsDependentOverridesPresent(fakeClient, tt.policy) if !reflect.DeepEqual(res, tt.expectedExist) || err != nil { t.Errorf("expected %v, but got %v", tt.expectedExist, res) } }) } } func TestIsDependentClusterOverridesPresent(t *testing.T) { tests := []struct { name string policy *policyv1alpha1.ClusterPropagationPolicy policyCreated bool expectedExist bool }{ { name: "dependent cluster override policy exist", policy: &policyv1alpha1.ClusterPropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, Spec: policyv1alpha1.PropagationSpec{ DependentOverrides: []string{"foo"}, }, }, policyCreated: true, expectedExist: true, }, { name: "dependent cluster override policy do not exist", policy: &policyv1alpha1.ClusterPropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, Spec: policyv1alpha1.PropagationSpec{ DependentOverrides: []string{"foo"}, }, }, policyCreated: false, expectedExist: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(Schema).Build() if tt.policyCreated { testClusterOverridePolicy := &policyv1alpha1.ClusterOverridePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: tt.policy.Name, }, } err := fakeClient.Create(context.TODO(), testClusterOverridePolicy) if err != nil { t.Fatalf("failed to create clusterOverridePolicy, err is: %v", err) } } res, err := IsDependentClusterOverridesPresent(fakeClient, tt.policy) if !reflect.DeepEqual(res, tt.expectedExist) || err != nil { t.Errorf("expected %v, but got %v", tt.expectedExist, res) } }) } } func TestCheckMatchServiceImport(t *testing.T) { tests := []struct { name string resourceSelectors []policyv1alpha1.ResourceSelector expected bool }{ { name: " get followed resource selector", resourceSelectors: []policyv1alpha1.ResourceSelector{ { Name: "foo1", Kind: util.ServiceImportKind, }, { Name: "foo2", Namespace: "bar", Kind: util.ServiceKind, }, { Name: "foo3", Namespace: "bar", Kind: util.ServiceImportKind, APIVersion: "multicluster.x-k8s.io/v1alpha1", }, }, expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res := ContainsServiceImport(tt.resourceSelectors) if !reflect.DeepEqual(res, tt.expected) { t.Errorf("expected %v, but got %v", tt.expected, res) } }) } } func TestIsReplicaDynamicDivided(t *testing.T) { tests := []struct { name string strategy *policyv1alpha1.ReplicaSchedulingStrategy expected bool }{ { name: "strategy empty", strategy: nil, expected: false, }, { name: "strategy duplicated", strategy: &policyv1alpha1.ReplicaSchedulingStrategy{ ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDuplicated, }, expected: false, }, { name: "strategy division preference weighted", strategy: &policyv1alpha1.ReplicaSchedulingStrategy{ ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceWeighted, ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, WeightPreference: &policyv1alpha1.ClusterPreferences{ DynamicWeight: policyv1alpha1.DynamicWeightByAvailableReplicas, }, }, expected: true, }, { name: "strategy division preference aggregated", strategy: &policyv1alpha1.ReplicaSchedulingStrategy{ ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceAggregated, }, expected: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res := IsReplicaDynamicDivided(&policyv1alpha1.Placement{ReplicaScheduling: tt.strategy}) if res != tt.expected { t.Errorf("expected %v, but got %v", tt.expected, res) } }) } } func TestGetAppliedPlacement(t *testing.T) { tests := []struct { name string annotations map[string]string expectedPlacement *policyv1alpha1.Placement expectedErr error }{ { name: "policy placement annotation exist", annotations: map[string]string{ util.PolicyPlacementAnnotation: "{\"clusterAffinity\":{\"clusterNames\":[\"member1\",\"member2\"]}}", }, expectedPlacement: &policyv1alpha1.Placement{ ClusterAffinity: &policyv1alpha1.ClusterAffinity{ ClusterNames: []string{"member1", "member2"}, }, }, expectedErr: nil, }, { name: "policy placement annotation do not exist", annotations: map[string]string{ "foo": "bar", }, expectedPlacement: nil, expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := GetAppliedPlacement(tt.annotations) if !reflect.DeepEqual(res, tt.expectedPlacement) || err != tt.expectedErr { t.Errorf("expected %v and %v, but got %v and %v", tt.expectedPlacement, tt.expectedErr, res, err) } }) } } func TestSetReplicaDivisionPreferenceWeighted(t *testing.T) { tests := []struct { name string strategy *policyv1alpha1.ReplicaSchedulingStrategy expectedWeighted bool }{ { name: "no replica scheduling strategy declared", expectedWeighted: false, }, { name: "specified aggregated division preference", strategy: &policyv1alpha1.ReplicaSchedulingStrategy{ ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, ReplicaDivisionPreference: policyv1alpha1.ReplicaDivisionPreferenceAggregated, }, expectedWeighted: false, }, { name: "unspecified replica division preference", strategy: &policyv1alpha1.ReplicaSchedulingStrategy{ ReplicaSchedulingType: policyv1alpha1.ReplicaSchedulingTypeDivided, }, expectedWeighted: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p := &policyv1alpha1.Placement{ReplicaScheduling: tt.strategy} SetReplicaDivisionPreferenceWeighted(p) if (p.ReplicaScheduling != nil && p.ReplicaScheduling.ReplicaDivisionPreference == policyv1alpha1.ReplicaDivisionPreferenceWeighted) != tt.expectedWeighted { t.Errorf("expectedWeighted %v, but got %v", tt.expectedWeighted, !tt.expectedWeighted) } }) } } func TestSetDefaultGracePeriodSeconds(t *testing.T) { tests := []struct { name string behavior *policyv1alpha1.ApplicationFailoverBehavior expectBehavior *policyv1alpha1.ApplicationFailoverBehavior }{ { name: "purgeMode is not graciously", behavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Never, }, expectBehavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Never, }, }, { name: "purgeMode is graciously and gracePeriodSeconds is set", behavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Graciously, GracePeriodSeconds: pointer.Int32(200), }, expectBehavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Graciously, GracePeriodSeconds: pointer.Int32(200), }, }, { name: "purgeMode is graciously and gracePeriodSeconds is not set", behavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Graciously, }, expectBehavior: &policyv1alpha1.ApplicationFailoverBehavior{ PurgeMode: policyv1alpha1.Graciously, GracePeriodSeconds: pointer.Int32(600), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { SetDefaultGracePeriodSeconds(tt.behavior) if !reflect.DeepEqual(tt.behavior, tt.expectBehavior) { t.Errorf("expectedBehavior %v, but got %v", tt.expectBehavior, tt.behavior) } }) } }