Replace error string with ErrorList in scheduler valiation test

Remove expected status

Remove unnecessary code

Revert changes to BindVerb
This commit is contained in:
Yuan Chen 2022-10-18 15:52:31 -07:00
parent 859ada198f
commit dd1b4fa407

View File

@ -17,11 +17,12 @@ limitations under the License.
package validation package validation
import ( import (
"strings"
"testing" "testing"
"time" "time"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
componentbaseconfig "k8s.io/component-base/config" componentbaseconfig "k8s.io/component-base/config"
"k8s.io/kubernetes/pkg/scheduler/apis/config" "k8s.io/kubernetes/pkg/scheduler/apis/config"
configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1" configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1"
@ -198,8 +199,8 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
extenderDuplicateManagedResource := validConfig.DeepCopy() extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{ extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
} }
extenderDuplicateBind := validConfig.DeepCopy() extenderDuplicateBind := validConfig.DeepCopy()
@ -214,132 +215,203 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2})
scenarios := map[string]struct { scenarios := map[string]struct {
expectedToFail bool config *config.KubeSchedulerConfiguration
config *config.KubeSchedulerConfiguration wantErrs field.ErrorList
errorString string
}{ }{
"good": { "good": {
expectedToFail: false, config: validConfig,
config: validConfig,
}, },
"bad-parallelism-invalid-value": { "bad-parallelism-invalid-value": {
expectedToFail: true, config: invalidParallelismValue,
config: invalidParallelismValue, wantErrs: field.ErrorList{
errorString: "should be an integer value greater than zero", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "parallelism",
},
},
}, },
"bad-resource-name-not-set": { "bad-resource-name-not-set": {
expectedToFail: true, config: resourceNameNotSet,
config: resourceNameNotSet, wantErrs: field.ErrorList{
errorString: "resourceName is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceName",
},
},
}, },
"bad-resource-namespace-not-set": { "bad-resource-namespace-not-set": {
expectedToFail: true, config: resourceNamespaceNotSet,
config: resourceNamespaceNotSet, wantErrs: field.ErrorList{
errorString: "resourceNamespace is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceNamespace",
},
},
}, },
"non-empty-metrics-bind-addr": { "non-empty-metrics-bind-addr": {
expectedToFail: true, config: metricsBindAddrInvalid,
config: metricsBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "metricsBindAddress",
},
},
}, },
"non-empty-healthz-bind-addr": { "non-empty-healthz-bind-addr": {
expectedToFail: true, config: healthzBindAddrInvalid,
config: healthzBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "healthzBindAddress",
},
},
}, },
"greater-than-100-percentage-of-nodes-to-score": { "greater-than-100-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScore101,
config: percentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "percentageOfNodesToScore",
},
},
}, },
"negative-percentage-of-nodes-to-score": { "negative-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScoreNegative,
config: percentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "percentageOfNodesToScore",
},
},
}, },
"scheduler-name-not-set": { "scheduler-name-not-set": {
expectedToFail: true, config: schedulerNameNotSet,
config: schedulerNameNotSet, wantErrs: field.ErrorList{
errorString: "Required value", &field.Error{
Type: field.ErrorTypeRequired,
Field: "profiles[1].schedulerName",
},
},
}, },
"repeated-scheduler-name": { "repeated-scheduler-name": {
expectedToFail: true, config: repeatedSchedulerName,
config: repeatedSchedulerName, wantErrs: field.ErrorList{
errorString: "Duplicate value", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: "profiles[1].schedulerName",
},
},
}, },
"greater-than-100-profile-percentage-of-nodes-to-score": { "greater-than-100-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScore101,
config: profilePercentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"negative-100-profile-percentage-of-nodes-to-score": { "negative-100-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScoreNegative,
config: profilePercentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"different-queue-sort": { "different-queue-sort": {
expectedToFail: true, config: differentQueueSort,
config: differentQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"one-empty-queue-sort": { "one-empty-queue-sort": {
expectedToFail: true, config: oneEmptyQueueSort,
config: oneEmptyQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"extender-negative-weight": { "extender-negative-weight": {
expectedToFail: true, config: extenderNegativeWeight,
config: extenderNegativeWeight, wantErrs: field.ErrorList{
errorString: "must have a positive weight applied to it", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].weight",
},
},
}, },
"extender-duplicate-managed-resources": { "extender-duplicate-managed-resources": {
expectedToFail: true, config: extenderDuplicateManagedResource,
config: extenderDuplicateManagedResource, wantErrs: field.ErrorList{
errorString: "duplicate extender managed resource name", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].managedResources[1].name",
},
},
}, },
"extender-duplicate-bind": { "extender-duplicate-bind": {
expectedToFail: true, config: extenderDuplicateBind,
config: extenderDuplicateBind, wantErrs: field.ErrorList{
errorString: "only one extender can implement bind", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders",
},
},
}, },
"invalid-node-percentage": { "invalid-node-percentage": {
expectedToFail: true, config: invalidNodePercentage,
config: invalidNodePercentage, wantErrs: field.ErrorList{
errorString: "not in valid range [0, 100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
},
},
}, },
"invalid-plugin-args": { "invalid-plugin-args": {
expectedToFail: true, config: invalidPluginArgs,
config: invalidPluginArgs, wantErrs: field.ErrorList{
errorString: "has to match plugin args", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args",
},
},
}, },
"duplicated-plugin-config": { "duplicated-plugin-config": {
expectedToFail: true, config: duplicatedPluginConfig,
config: duplicatedPluginConfig, wantErrs: field.ErrorList{
errorString: "Duplicate value: \"config\"", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: `profiles[0].pluginConfig[1]`,
},
},
}, },
"mismatch-queue-sort": { "mismatch-queue-sort": {
expectedToFail: true, config: mismatchQueueSort,
config: mismatchQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"valid-plugins": { "valid-plugins": {
expectedToFail: false, config: validPlugins,
config: validPlugins,
}, },
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
errs := ValidateKubeSchedulerConfiguration(scenario.config) errs := ValidateKubeSchedulerConfiguration(scenario.config)
if errs == nil && scenario.expectedToFail { diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
t.Error("Unexpected success") if diff != "" {
} t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
if errs != nil && !scenario.expectedToFail {
t.Errorf("Unexpected failure: %+v", errs)
}
if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) {
t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error())
} }
}) })
} }
@ -513,8 +585,8 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
extenderDuplicateManagedResource := validConfig.DeepCopy() extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{ extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
} }
extenderDuplicateBind := validConfig.DeepCopy() extenderDuplicateBind := validConfig.DeepCopy()
@ -529,132 +601,203 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2}) validPlugins.Profiles[0].Plugins.Score.Enabled = append(validPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "PodTopologySpread", Weight: 2})
scenarios := map[string]struct { scenarios := map[string]struct {
expectedToFail bool config *config.KubeSchedulerConfiguration
config *config.KubeSchedulerConfiguration wantErrs field.ErrorList
errorString string
}{ }{
"good": { "good": {
expectedToFail: false, config: validConfig,
config: validConfig,
}, },
"bad-parallelism-invalid-value": { "bad-parallelism-invalid-value": {
expectedToFail: true, config: invalidParallelismValue,
config: invalidParallelismValue, wantErrs: field.ErrorList{
errorString: "should be an integer value greater than zero", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "parallelism",
},
},
}, },
"bad-resource-name-not-set": { "bad-resource-name-not-set": {
expectedToFail: true, config: resourceNameNotSet,
config: resourceNameNotSet, wantErrs: field.ErrorList{
errorString: "resourceName is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceName",
},
},
}, },
"bad-resource-namespace-not-set": { "bad-resource-namespace-not-set": {
expectedToFail: true, config: resourceNamespaceNotSet,
config: resourceNamespaceNotSet, wantErrs: field.ErrorList{
errorString: "resourceNamespace is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceNamespace",
},
},
}, },
"non-empty-metrics-bind-addr": { "non-empty-metrics-bind-addr": {
expectedToFail: true, config: metricsBindAddrInvalid,
config: metricsBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "metricsBindAddress",
},
},
}, },
"non-empty-healthz-bind-addr": { "non-empty-healthz-bind-addr": {
expectedToFail: true, config: healthzBindAddrInvalid,
config: healthzBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "healthzBindAddress",
},
},
}, },
"bad-percentage-of-nodes-to-score": { "bad-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScore101,
config: percentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "percentageOfNodesToScore",
},
},
}, },
"negative-percentage-of-nodes-to-score": { "negative-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScoreNegative,
config: percentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"scheduler-name-not-set": { "scheduler-name-not-set": {
expectedToFail: true, config: schedulerNameNotSet,
config: schedulerNameNotSet, wantErrs: field.ErrorList{
errorString: "Required value", &field.Error{
Type: field.ErrorTypeRequired,
Field: "profiles[1].schedulerName",
},
},
}, },
"repeated-scheduler-name": { "repeated-scheduler-name": {
expectedToFail: true, config: repeatedSchedulerName,
config: repeatedSchedulerName, wantErrs: field.ErrorList{
errorString: "Duplicate value", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: "profiles[1].schedulerName",
},
},
}, },
"greater-than-100-profile-percentage-of-nodes-to-score": { "greater-than-100-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScore101,
config: profilePercentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"negative-100-profile-percentage-of-nodes-to-score": { "negative-100-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScoreNegative,
config: profilePercentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"different-queue-sort": { "different-queue-sort": {
expectedToFail: true, config: differentQueueSort,
config: differentQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"one-empty-queue-sort": { "one-empty-queue-sort": {
expectedToFail: true, config: oneEmptyQueueSort,
config: oneEmptyQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"extender-negative-weight": { "extender-negative-weight": {
expectedToFail: true, config: extenderNegativeWeight,
config: extenderNegativeWeight, wantErrs: field.ErrorList{
errorString: "must have a positive weight applied to it", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].weight",
},
},
}, },
"extender-duplicate-managed-resources": { "extender-duplicate-managed-resources": {
expectedToFail: true, config: extenderDuplicateManagedResource,
config: extenderDuplicateManagedResource, wantErrs: field.ErrorList{
errorString: "duplicate extender managed resource name", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].managedResources[1].name",
},
},
}, },
"extender-duplicate-bind": { "extender-duplicate-bind": {
expectedToFail: true, config: extenderDuplicateBind,
config: extenderDuplicateBind, wantErrs: field.ErrorList{
errorString: "only one extender can implement bind", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders",
},
},
}, },
"invalid-node-percentage": { "invalid-node-percentage": {
expectedToFail: true, config: invalidNodePercentage,
config: invalidNodePercentage, wantErrs: field.ErrorList{
errorString: "not in valid range [0, 100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
},
},
}, },
"invalid-plugin-args": { "invalid-plugin-args": {
expectedToFail: true, config: invalidPluginArgs,
config: invalidPluginArgs, wantErrs: field.ErrorList{
errorString: "has to match plugin args", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args",
},
},
}, },
"duplicated-plugin-config": { "duplicated-plugin-config": {
expectedToFail: true, config: duplicatedPluginConfig,
config: duplicatedPluginConfig, wantErrs: field.ErrorList{
errorString: "Duplicate value: \"config\"", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: "profiles[0].pluginConfig[1]",
},
},
}, },
"mismatch-queue-sort": { "mismatch-queue-sort": {
expectedToFail: true, config: mismatchQueueSort,
config: mismatchQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"valid-plugins": { "valid-plugins": {
expectedToFail: false, config: validPlugins,
config: validPlugins,
}, },
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
errs := ValidateKubeSchedulerConfiguration(scenario.config) errs := ValidateKubeSchedulerConfiguration(scenario.config)
if errs == nil && scenario.expectedToFail { diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
t.Error("Unexpected success") if diff != "" {
} t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
if errs != nil && !scenario.expectedToFail {
t.Errorf("Unexpected failure: %+v", errs)
}
if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) {
t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error())
} }
}) })
} }
@ -829,8 +972,8 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
extenderDuplicateManagedResource := validConfig.DeepCopy() extenderDuplicateManagedResource := validConfig.DeepCopy()
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{ extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
{Name: "foo", IgnoredByScheduler: false}, {Name: "example.com/foo", IgnoredByScheduler: false},
} }
extenderDuplicateBind := validConfig.DeepCopy() extenderDuplicateBind := validConfig.DeepCopy()
@ -848,137 +991,212 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
invalidPlugins.Profiles[0].Plugins.Score.Enabled = append(invalidPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "SelectorSpread"}) invalidPlugins.Profiles[0].Plugins.Score.Enabled = append(invalidPlugins.Profiles[0].Plugins.Score.Enabled, config.Plugin{Name: "SelectorSpread"})
scenarios := map[string]struct { scenarios := map[string]struct {
expectedToFail bool config *config.KubeSchedulerConfiguration
config *config.KubeSchedulerConfiguration wantErrs field.ErrorList
errorString string
}{ }{
"good": { "good": {
expectedToFail: false, config: validConfig,
config: validConfig,
}, },
"bad-parallelism-invalid-value": { "bad-parallelism-invalid-value": {
expectedToFail: true, config: invalidParallelismValue,
config: invalidParallelismValue, wantErrs: field.ErrorList{
errorString: "should be an integer value greater than zero", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "parallelism",
},
},
}, },
"bad-resource-name-not-set": { "bad-resource-name-not-set": {
expectedToFail: true, config: resourceNameNotSet,
config: resourceNameNotSet, wantErrs: field.ErrorList{
errorString: "resourceName is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceName",
},
},
}, },
"bad-resource-namespace-not-set": { "bad-resource-namespace-not-set": {
expectedToFail: true, config: resourceNamespaceNotSet,
config: resourceNamespaceNotSet, wantErrs: field.ErrorList{
errorString: "resourceNamespace is required", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "leaderElection.resourceNamespace",
},
},
}, },
"non-empty-metrics-bind-addr": { "non-empty-metrics-bind-addr": {
expectedToFail: true, config: metricsBindAddrInvalid,
config: metricsBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "metricsBindAddress",
},
},
}, },
"non-empty-healthz-bind-addr": { "non-empty-healthz-bind-addr": {
expectedToFail: true, config: healthzBindAddrInvalid,
config: healthzBindAddrInvalid, wantErrs: field.ErrorList{
errorString: "must be empty or with an explicit 0 port", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "healthzBindAddress",
},
},
}, },
"bad-percentage-of-nodes-to-score": { "bad-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScore101,
config: percentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "percentageOfNodesToScore",
},
},
}, },
"negative-percentage-of-nodes-to-score": { "negative-percentage-of-nodes-to-score": {
expectedToFail: true, config: percentageOfNodesToScoreNegative,
config: percentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "percentageOfNodesToScore",
},
},
}, },
"scheduler-name-not-set": { "scheduler-name-not-set": {
expectedToFail: true, config: schedulerNameNotSet,
config: schedulerNameNotSet, wantErrs: field.ErrorList{
errorString: "Required value", &field.Error{
Type: field.ErrorTypeRequired,
Field: "profiles[1].schedulerName",
},
},
}, },
"repeated-scheduler-name": { "repeated-scheduler-name": {
expectedToFail: true, config: repeatedSchedulerName,
config: repeatedSchedulerName, wantErrs: field.ErrorList{
errorString: "Duplicate value", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: "profiles[1].schedulerName",
},
},
}, },
"greater-than-100-profile-percentage-of-nodes-to-score": { "greater-than-100-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScore101,
config: profilePercentageOfNodesToScore101, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"negative-profile-percentage-of-nodes-to-score": { "negative-profile-percentage-of-nodes-to-score": {
expectedToFail: true, config: profilePercentageOfNodesToScoreNegative,
config: profilePercentageOfNodesToScoreNegative, wantErrs: field.ErrorList{
errorString: "not in valid range [0-100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].percentageOfNodesToScore",
},
},
}, },
"different-queue-sort": { "different-queue-sort": {
expectedToFail: true, config: differentQueueSort,
config: differentQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"one-empty-queue-sort": { "one-empty-queue-sort": {
expectedToFail: true, config: oneEmptyQueueSort,
config: oneEmptyQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[1].plugins.queueSort",
},
},
}, },
"extender-negative-weight": { "extender-negative-weight": {
expectedToFail: true, config: extenderNegativeWeight,
config: extenderNegativeWeight, wantErrs: field.ErrorList{
errorString: "must have a positive weight applied to it", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].weight",
},
},
}, },
"extender-duplicate-managed-resources": { "extender-duplicate-managed-resources": {
expectedToFail: true, config: extenderDuplicateManagedResource,
config: extenderDuplicateManagedResource, wantErrs: field.ErrorList{
errorString: "duplicate extender managed resource name", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders[0].managedResources[1].name",
},
},
}, },
"extender-duplicate-bind": { "extender-duplicate-bind": {
expectedToFail: true, config: extenderDuplicateBind,
config: extenderDuplicateBind, wantErrs: field.ErrorList{
errorString: "only one extender can implement bind", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "extenders",
},
},
}, },
"invalid-node-percentage": { "invalid-node-percentage": {
expectedToFail: true, config: invalidNodePercentage,
config: invalidNodePercentage, wantErrs: field.ErrorList{
errorString: "not in valid range [0, 100]", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
},
},
}, },
"invalid-plugin-args": { "invalid-plugin-args": {
expectedToFail: true, config: invalidPluginArgs,
config: invalidPluginArgs, wantErrs: field.ErrorList{
errorString: "has to match plugin args", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].pluginConfig[0].args",
},
},
}, },
"duplicated-plugin-config": { "duplicated-plugin-config": {
expectedToFail: true, config: duplicatedPluginConfig,
config: duplicatedPluginConfig, wantErrs: field.ErrorList{
errorString: "Duplicate value: \"config\"", &field.Error{
Type: field.ErrorTypeDuplicate,
Field: "profiles[0].pluginConfig[1]",
},
},
}, },
"mismatch-queue-sort": { "mismatch-queue-sort": {
expectedToFail: true, config: mismatchQueueSort,
config: mismatchQueueSort, wantErrs: field.ErrorList{
errorString: "has to match for all profiles", &field.Error{
}, Type: field.ErrorTypeInvalid,
"valid-plugins": { Field: "profiles[1].plugins.queueSort",
expectedToFail: false, },
config: validPlugins, },
}, },
"invalid-plugins": { "invalid-plugins": {
expectedToFail: true, config: invalidPlugins,
config: invalidPlugins, wantErrs: field.ErrorList{
errorString: "\"SelectorSpread\": was invalid", &field.Error{
Type: field.ErrorTypeInvalid,
Field: "profiles[0].plugins.score.enabled[0]",
},
},
},
"valid-plugins": {
config: validPlugins,
}, },
} }
for name, scenario := range scenarios { for name, scenario := range scenarios {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
errs := ValidateKubeSchedulerConfiguration(scenario.config) errs := ValidateKubeSchedulerConfiguration(scenario.config)
if errs == nil && scenario.expectedToFail { diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
t.Error("Unexpected success") if diff != "" {
} t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
if errs != nil && !scenario.expectedToFail {
t.Errorf("Unexpected failure: %+v", errs)
}
if errs != nil && scenario.errorString != "" && !strings.Contains(errs.Error(), scenario.errorString) {
t.Errorf("Unexpected error string\n want:\t%s\n got:\t%s", scenario.errorString, errs.Error())
} }
}) })
} }