diff --git a/pkg/scheduler/framework/plugins/apienablement/api_enablement_test.go b/pkg/scheduler/framework/plugins/apienablement/api_enablement_test.go new file mode 100644 index 000000000000..cf68ae0c0bac --- /dev/null +++ b/pkg/scheduler/framework/plugins/apienablement/api_enablement_test.go @@ -0,0 +1,147 @@ +/* +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 apienablement + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/scheduler/framework" +) + +func TestAPIEnablement_Filter(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + cluster *clusterv1alpha1.Cluster + expectedCode framework.Code + expectError bool + }{ + { + name: "API is enabled in cluster", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + Status: clusterv1alpha1.ClusterStatus{ + APIEnablements: []clusterv1alpha1.APIEnablement{ + { + GroupVersion: "apps/v1", + Resources: []clusterv1alpha1.APIResource{ + { + Kind: "Deployment", + }, + }, + }, + }, + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + { + name: "API is not enabled in cluster", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "custom.io/v1", + Kind: "CustomResource", + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + Status: clusterv1alpha1.ClusterStatus{ + APIEnablements: []clusterv1alpha1.APIEnablement{ + { + GroupVersion: "apps/v1", + Resources: []clusterv1alpha1.APIResource{ + { + Kind: "Deployment", + }, + }, + }, + }, + }, + }, + expectedCode: framework.Unschedulable, + expectError: true, + }, + { + name: "cluster in target list with incomplete API enablements", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Resource: workv1alpha2.ObjectReference{ + APIVersion: "custom.io/v1", + Kind: "CustomResource", + }, + Clusters: []workv1alpha2.TargetCluster{ + { + Name: "cluster1", + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + Status: clusterv1alpha1.ClusterStatus{ + Conditions: []metav1.Condition{ + { + Type: clusterv1alpha1.ClusterConditionCompleteAPIEnablements, + Status: metav1.ConditionFalse, + }, + }, + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + } + + p := &APIEnablement{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := p.Filter(context.Background(), tt.bindingSpec, nil, tt.cluster) + assert.Equal(t, tt.expectedCode, result.Code()) + assert.Equal(t, tt.expectError, result.AsError() != nil) + }) + } +} + +func TestNew(t *testing.T) { + plugin, err := New() + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*APIEnablement) + assert.True(t, ok) +} + +func TestAPIEnablement_Name(t *testing.T) { + p := &APIEnablement{} + assert.Equal(t, Name, p.Name()) +} diff --git a/pkg/scheduler/framework/plugins/clusteraffinity/cluster_affinity_test.go b/pkg/scheduler/framework/plugins/clusteraffinity/cluster_affinity_test.go new file mode 100644 index 000000000000..f18ff25e6e9d --- /dev/null +++ b/pkg/scheduler/framework/plugins/clusteraffinity/cluster_affinity_test.go @@ -0,0 +1,160 @@ +/* +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 clusteraffinity + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + 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/scheduler/framework" +) + +func TestClusterAffinity_Filter(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + bindingStatus *workv1alpha2.ResourceBindingStatus + cluster *clusterv1alpha1.Cluster + expectedCode framework.Code + expectError bool + }{ + { + name: "matching affinity", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + ClusterAffinity: &policyv1alpha1.ClusterAffinity{ + ClusterNames: []string{"cluster1"}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + { + name: "non-matching affinity", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + ClusterAffinity: &policyv1alpha1.ClusterAffinity{ + ClusterNames: []string{"cluster2"}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Unschedulable, + expectError: true, + }, + { + name: "matching affinity from ClusterAffinities", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + ClusterAffinities: []policyv1alpha1.ClusterAffinityTerm{ + { + AffinityName: "affinity1", + ClusterAffinity: policyv1alpha1.ClusterAffinity{ + ClusterNames: []string{"cluster1"}, + }, + }, + }, + }, + }, + bindingStatus: &workv1alpha2.ResourceBindingStatus{ + SchedulerObservedAffinityName: "affinity1", + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + { + name: "no affinity specified", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{}, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + } + + p := &ClusterAffinity{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := p.Filter(context.Background(), tt.bindingSpec, tt.bindingStatus, tt.cluster) + assert.Equal(t, tt.expectedCode, result.Code()) + assert.Equal(t, tt.expectError, result.AsError() != nil) + }) + } +} + +func TestClusterAffinity_Score(t *testing.T) { + p := &ClusterAffinity{} + spec := &workv1alpha2.ResourceBindingSpec{} + cluster := &clusterv1alpha1.Cluster{} + + score, result := p.Score(context.Background(), spec, cluster) + + assert.Equal(t, framework.MinClusterScore, score) + assert.Equal(t, framework.Success, result.Code()) +} + +func TestClusterAffinity_ScoreExtensions(t *testing.T) { + p := &ClusterAffinity{} + assert.Equal(t, p, p.ScoreExtensions()) +} + +func TestClusterAffinity_NormalizeScore(t *testing.T) { + p := &ClusterAffinity{} + result := p.NormalizeScore(context.Background(), nil) + assert.Equal(t, framework.Success, result.Code()) +} + +func TestNew(t *testing.T) { + plugin, err := New() + + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*ClusterAffinity) + assert.True(t, ok) +} + +func TestClusterAffinity_Name(t *testing.T) { + p := &ClusterAffinity{} + assert.Equal(t, Name, p.Name()) +} diff --git a/pkg/scheduler/framework/plugins/clustereviction/cluster_eviction_test.go b/pkg/scheduler/framework/plugins/clustereviction/cluster_eviction_test.go new file mode 100644 index 000000000000..18111cb1927b --- /dev/null +++ b/pkg/scheduler/framework/plugins/clustereviction/cluster_eviction_test.go @@ -0,0 +1,107 @@ +/* +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 clustereviction + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/scheduler/framework" +) + +func TestClusterEviction_Filter(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + cluster *clusterv1alpha1.Cluster + expectedCode framework.Code + expectError bool + }{ + { + name: "cluster is in graceful eviction tasks", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + GracefulEvictionTasks: []workv1alpha2.GracefulEvictionTask{ + { + FromCluster: "cluster1", + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Unschedulable, + expectError: true, + }, + { + name: "cluster is not in graceful eviction tasks", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + GracefulEvictionTasks: []workv1alpha2.GracefulEvictionTask{ + { + FromCluster: "cluster2", + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + { + name: "no graceful eviction tasks", + bindingSpec: &workv1alpha2.ResourceBindingSpec{}, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + expectError: false, + }, + } + + p := &ClusterEviction{} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := p.Filter(context.Background(), tt.bindingSpec, nil, tt.cluster) + assert.Equal(t, tt.expectedCode, result.Code()) + assert.Equal(t, tt.expectError, result.AsError() != nil) + }) + } +} + +func TestNew(t *testing.T) { + plugin, err := New() + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*ClusterEviction) + assert.True(t, ok) +} + +func TestClusterEviction_Name(t *testing.T) { + p := &ClusterEviction{} + assert.Equal(t, Name, p.Name()) +} diff --git a/pkg/scheduler/framework/plugins/clusterlocality/cluster_locality_test.go b/pkg/scheduler/framework/plugins/clusterlocality/cluster_locality_test.go new file mode 100644 index 000000000000..6ed32ec73c9a --- /dev/null +++ b/pkg/scheduler/framework/plugins/clusterlocality/cluster_locality_test.go @@ -0,0 +1,109 @@ +/* +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 clusterlocality + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" + "github.com/karmada-io/karmada/pkg/scheduler/framework" +) + +func TestClusterLocality_Score(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + cluster *clusterv1alpha1.Cluster + expectedScore int64 + }{ + { + name: "no clusters in spec", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{}, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedScore: framework.MinClusterScore, + }, + { + name: "cluster in spec", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster1"}, + {Name: "cluster2"}, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedScore: framework.MaxClusterScore, + }, + { + name: "cluster not in spec", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster2"}, + {Name: "cluster3"}, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedScore: framework.MinClusterScore, + }, + } + + p := &ClusterLocality{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + score, result := p.Score(context.Background(), tt.bindingSpec, tt.cluster) + assert.Equal(t, tt.expectedScore, score) + assert.Equal(t, framework.Success, result.Code()) + }) + } +} + +func TestNew(t *testing.T) { + plugin, err := New() + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*ClusterLocality) + assert.True(t, ok) +} + +func TestClusterLocality_Name(t *testing.T) { + p := &ClusterLocality{} + assert.Equal(t, Name, p.Name()) +} + +func TestClusterLocality_ScoreExtensions(t *testing.T) { + p := &ClusterLocality{} + assert.Nil(t, p.ScoreExtensions()) +} diff --git a/pkg/scheduler/framework/plugins/spreadconstraint/spread_constraint_test.go b/pkg/scheduler/framework/plugins/spreadconstraint/spread_constraint_test.go new file mode 100644 index 000000000000..771171a17178 --- /dev/null +++ b/pkg/scheduler/framework/plugins/spreadconstraint/spread_constraint_test.go @@ -0,0 +1,160 @@ +/* +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 spreadconstraint + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + 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/scheduler/framework" +) + +func TestSpreadConstraint_Filter(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + cluster *clusterv1alpha1.Cluster + expectedCode framework.Code + expectedReason string + }{ + { + name: "no spread constraints", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{}, + }, + cluster: &clusterv1alpha1.Cluster{}, + expectedCode: framework.Success, + }, + { + name: "spread by provider - provider present", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldProvider}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + Spec: clusterv1alpha1.ClusterSpec{ + Provider: "aws", + }, + }, + expectedCode: framework.Success, + }, + { + name: "spread by provider - provider missing", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldProvider}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{}, + expectedCode: framework.Unschedulable, + expectedReason: "cluster(s) did not have provider property", + }, + { + name: "spread by region - region present", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldRegion}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + Spec: clusterv1alpha1.ClusterSpec{ + Region: "us-west-2", + }, + }, + expectedCode: framework.Success, + }, + { + name: "spread by region - region missing", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldRegion}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{}, + expectedCode: framework.Unschedulable, + expectedReason: "cluster(s) did not have region property", + }, + { + name: "spread by zone - zones present", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldZone}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + Spec: clusterv1alpha1.ClusterSpec{ + Zones: []string{"us-west-2a"}, + }, + }, + expectedCode: framework.Success, + }, + { + name: "spread by zone - zones missing", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + SpreadConstraints: []policyv1alpha1.SpreadConstraint{ + {SpreadByField: policyv1alpha1.SpreadByFieldZone}, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{}, + expectedCode: framework.Unschedulable, + expectedReason: "cluster(s) did not have zones property", + }, + } + + p := &SpreadConstraint{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := p.Filter(context.Background(), tt.bindingSpec, nil, tt.cluster) + assert.Equal(t, tt.expectedCode, result.Code()) + if tt.expectedReason != "" { + assert.Contains(t, result.AsError().Error(), tt.expectedReason) + } + }) + } +} + +func TestNew(t *testing.T) { + plugin, err := New() + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*SpreadConstraint) + assert.True(t, ok) +} + +func TestSpreadConstraint_Name(t *testing.T) { + p := &SpreadConstraint{} + assert.Equal(t, Name, p.Name()) +} diff --git a/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration_test.go b/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration_test.go new file mode 100644 index 000000000000..05a39c6e2d51 --- /dev/null +++ b/pkg/scheduler/framework/plugins/tainttoleration/taint_toleration_test.go @@ -0,0 +1,135 @@ +/* +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 tainttoleration + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + 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/scheduler/framework" +) + +func TestTaintToleration_Filter(t *testing.T) { + tests := []struct { + name string + bindingSpec *workv1alpha2.ResourceBindingSpec + cluster *clusterv1alpha1.Cluster + expectedCode framework.Code + expectedReason string + }{ + { + name: "cluster already in target clusters", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Clusters: []workv1alpha2.TargetCluster{ + {Name: "cluster1"}, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1", + }, + }, + expectedCode: framework.Success, + }, + { + name: "no taints", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{}, + }, + cluster: &clusterv1alpha1.Cluster{}, + expectedCode: framework.Success, + }, + { + name: "tolerated taint", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{ + ClusterTolerations: []corev1.Toleration{ + { + Key: "key1", + Operator: corev1.TolerationOpEqual, + Value: "value1", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + }, + }, + cluster: &clusterv1alpha1.Cluster{ + Spec: clusterv1alpha1.ClusterSpec{ + Taints: []corev1.Taint{ + { + Key: "key1", + Value: "value1", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + }, + }, + expectedCode: framework.Success, + }, + { + name: "untolerated taint", + bindingSpec: &workv1alpha2.ResourceBindingSpec{ + Placement: &policyv1alpha1.Placement{}, + }, + cluster: &clusterv1alpha1.Cluster{ + Spec: clusterv1alpha1.ClusterSpec{ + Taints: []corev1.Taint{ + { + Key: "key1", + Value: "value1", + Effect: corev1.TaintEffectNoSchedule, + }, + }, + }, + }, + expectedCode: framework.Unschedulable, + expectedReason: "cluster(s) had untolerated taint {key1=value1:NoSchedule}", + }, + } + + p := &TaintToleration{} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := p.Filter(context.Background(), tt.bindingSpec, nil, tt.cluster) + assert.Equal(t, tt.expectedCode, result.Code()) + if tt.expectedReason != "" { + assert.Contains(t, result.AsError().Error(), tt.expectedReason) + } + }) + } +} + +func TestNew(t *testing.T) { + plugin, err := New() + assert.NoError(t, err) + assert.NotNil(t, plugin) + _, ok := plugin.(*TaintToleration) + assert.True(t, ok) +} + +func TestTaintToleration_Name(t *testing.T) { + p := &TaintToleration{} + assert.Equal(t, Name, p.Name()) +}