mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Replace error string with ErrorList in scheduler valiation test
Remove expected status Remove unnecessary code Revert changes to BindVerb
This commit is contained in:
parent
859ada198f
commit
dd1b4fa407
@ -17,11 +17,12 @@ limitations under the License.
|
||||
package validation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
componentbaseconfig "k8s.io/component-base/config"
|
||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||
configv1 "k8s.io/kubernetes/pkg/scheduler/apis/config/v1"
|
||||
@ -198,8 +199,8 @@ func TestValidateKubeSchedulerConfigurationV1beta2(t *testing.T) {
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
}
|
||||
|
||||
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})
|
||||
|
||||
scenarios := map[string]struct {
|
||||
expectedToFail bool
|
||||
config *config.KubeSchedulerConfiguration
|
||||
errorString string
|
||||
config *config.KubeSchedulerConfiguration
|
||||
wantErrs field.ErrorList
|
||||
}{
|
||||
"good": {
|
||||
expectedToFail: false,
|
||||
config: validConfig,
|
||||
config: validConfig,
|
||||
},
|
||||
"bad-parallelism-invalid-value": {
|
||||
expectedToFail: true,
|
||||
config: invalidParallelismValue,
|
||||
errorString: "should be an integer value greater than zero",
|
||||
config: invalidParallelismValue,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "parallelism",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNameNotSet,
|
||||
errorString: "resourceName is required",
|
||||
config: resourceNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-namespace-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNamespaceNotSet,
|
||||
errorString: "resourceNamespace is required",
|
||||
config: resourceNamespaceNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceNamespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-metrics-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: metricsBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: metricsBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "metricsBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-healthz-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: healthzBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: healthzBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "healthzBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"greater-than-100-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"scheduler-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: schedulerNameNotSet,
|
||||
errorString: "Required value",
|
||||
config: schedulerNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeRequired,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"repeated-scheduler-name": {
|
||||
expectedToFail: true,
|
||||
config: repeatedSchedulerName,
|
||||
errorString: "Duplicate value",
|
||||
config: repeatedSchedulerName,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"greater-than-100-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-100-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"different-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: differentQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: differentQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"one-empty-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: oneEmptyQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: oneEmptyQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-negative-weight": {
|
||||
expectedToFail: true,
|
||||
config: extenderNegativeWeight,
|
||||
errorString: "must have a positive weight applied to it",
|
||||
config: extenderNegativeWeight,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].weight",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-managed-resources": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateManagedResource,
|
||||
errorString: "duplicate extender managed resource name",
|
||||
config: extenderDuplicateManagedResource,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].managedResources[1].name",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-bind": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateBind,
|
||||
errorString: "only one extender can implement bind",
|
||||
config: extenderDuplicateBind,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-node-percentage": {
|
||||
expectedToFail: true,
|
||||
config: invalidNodePercentage,
|
||||
errorString: "not in valid range [0, 100]",
|
||||
config: invalidNodePercentage,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-plugin-args": {
|
||||
expectedToFail: true,
|
||||
config: invalidPluginArgs,
|
||||
errorString: "has to match plugin args",
|
||||
config: invalidPluginArgs,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args",
|
||||
},
|
||||
},
|
||||
},
|
||||
"duplicated-plugin-config": {
|
||||
expectedToFail: true,
|
||||
config: duplicatedPluginConfig,
|
||||
errorString: "Duplicate value: \"config\"",
|
||||
config: duplicatedPluginConfig,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: `profiles[0].pluginConfig[1]`,
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatch-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: mismatchQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: mismatchQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"valid-plugins": {
|
||||
expectedToFail: false,
|
||||
config: validPlugins,
|
||||
config: validPlugins,
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
errs := ValidateKubeSchedulerConfiguration(scenario.config)
|
||||
if errs == nil && scenario.expectedToFail {
|
||||
t.Error("Unexpected success")
|
||||
}
|
||||
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())
|
||||
diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
|
||||
if diff != "" {
|
||||
t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -513,8 +585,8 @@ func TestValidateKubeSchedulerConfigurationV1beta3(t *testing.T) {
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
}
|
||||
|
||||
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})
|
||||
|
||||
scenarios := map[string]struct {
|
||||
expectedToFail bool
|
||||
config *config.KubeSchedulerConfiguration
|
||||
errorString string
|
||||
config *config.KubeSchedulerConfiguration
|
||||
wantErrs field.ErrorList
|
||||
}{
|
||||
"good": {
|
||||
expectedToFail: false,
|
||||
config: validConfig,
|
||||
config: validConfig,
|
||||
},
|
||||
"bad-parallelism-invalid-value": {
|
||||
expectedToFail: true,
|
||||
config: invalidParallelismValue,
|
||||
errorString: "should be an integer value greater than zero",
|
||||
config: invalidParallelismValue,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "parallelism",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNameNotSet,
|
||||
errorString: "resourceName is required",
|
||||
config: resourceNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-namespace-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNamespaceNotSet,
|
||||
errorString: "resourceNamespace is required",
|
||||
config: resourceNamespaceNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceNamespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-metrics-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: metricsBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: metricsBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "metricsBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-healthz-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: healthzBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: healthzBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "healthzBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"scheduler-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: schedulerNameNotSet,
|
||||
errorString: "Required value",
|
||||
config: schedulerNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeRequired,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"repeated-scheduler-name": {
|
||||
expectedToFail: true,
|
||||
config: repeatedSchedulerName,
|
||||
errorString: "Duplicate value",
|
||||
config: repeatedSchedulerName,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"greater-than-100-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-100-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"different-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: differentQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: differentQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"one-empty-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: oneEmptyQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: oneEmptyQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-negative-weight": {
|
||||
expectedToFail: true,
|
||||
config: extenderNegativeWeight,
|
||||
errorString: "must have a positive weight applied to it",
|
||||
config: extenderNegativeWeight,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].weight",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-managed-resources": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateManagedResource,
|
||||
errorString: "duplicate extender managed resource name",
|
||||
config: extenderDuplicateManagedResource,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].managedResources[1].name",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-bind": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateBind,
|
||||
errorString: "only one extender can implement bind",
|
||||
config: extenderDuplicateBind,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-node-percentage": {
|
||||
expectedToFail: true,
|
||||
config: invalidNodePercentage,
|
||||
errorString: "not in valid range [0, 100]",
|
||||
config: invalidNodePercentage,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-plugin-args": {
|
||||
expectedToFail: true,
|
||||
config: invalidPluginArgs,
|
||||
errorString: "has to match plugin args",
|
||||
config: invalidPluginArgs,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args",
|
||||
},
|
||||
},
|
||||
},
|
||||
"duplicated-plugin-config": {
|
||||
expectedToFail: true,
|
||||
config: duplicatedPluginConfig,
|
||||
errorString: "Duplicate value: \"config\"",
|
||||
config: duplicatedPluginConfig,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: "profiles[0].pluginConfig[1]",
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatch-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: mismatchQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: mismatchQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"valid-plugins": {
|
||||
expectedToFail: false,
|
||||
config: validPlugins,
|
||||
config: validPlugins,
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
errs := ValidateKubeSchedulerConfiguration(scenario.config)
|
||||
if errs == nil && scenario.expectedToFail {
|
||||
t.Error("Unexpected success")
|
||||
}
|
||||
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())
|
||||
diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
|
||||
if diff != "" {
|
||||
t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -829,8 +972,8 @@ func TestValidateKubeSchedulerConfigurationV1(t *testing.T) {
|
||||
|
||||
extenderDuplicateManagedResource := validConfig.DeepCopy()
|
||||
extenderDuplicateManagedResource.Extenders[0].ManagedResources = []config.ExtenderManagedResource{
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
{Name: "example.com/foo", IgnoredByScheduler: false},
|
||||
}
|
||||
|
||||
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"})
|
||||
|
||||
scenarios := map[string]struct {
|
||||
expectedToFail bool
|
||||
config *config.KubeSchedulerConfiguration
|
||||
errorString string
|
||||
config *config.KubeSchedulerConfiguration
|
||||
wantErrs field.ErrorList
|
||||
}{
|
||||
"good": {
|
||||
expectedToFail: false,
|
||||
config: validConfig,
|
||||
config: validConfig,
|
||||
},
|
||||
"bad-parallelism-invalid-value": {
|
||||
expectedToFail: true,
|
||||
config: invalidParallelismValue,
|
||||
errorString: "should be an integer value greater than zero",
|
||||
config: invalidParallelismValue,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "parallelism",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNameNotSet,
|
||||
errorString: "resourceName is required",
|
||||
config: resourceNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-resource-namespace-not-set": {
|
||||
expectedToFail: true,
|
||||
config: resourceNamespaceNotSet,
|
||||
errorString: "resourceNamespace is required",
|
||||
config: resourceNamespaceNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "leaderElection.resourceNamespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-metrics-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: metricsBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: metricsBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "metricsBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"non-empty-healthz-bind-addr": {
|
||||
expectedToFail: true,
|
||||
config: healthzBindAddrInvalid,
|
||||
errorString: "must be empty or with an explicit 0 port",
|
||||
config: healthzBindAddrInvalid,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "healthzBindAddress",
|
||||
},
|
||||
},
|
||||
},
|
||||
"bad-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: percentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"scheduler-name-not-set": {
|
||||
expectedToFail: true,
|
||||
config: schedulerNameNotSet,
|
||||
errorString: "Required value",
|
||||
config: schedulerNameNotSet,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeRequired,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"repeated-scheduler-name": {
|
||||
expectedToFail: true,
|
||||
config: repeatedSchedulerName,
|
||||
errorString: "Duplicate value",
|
||||
config: repeatedSchedulerName,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: "profiles[1].schedulerName",
|
||||
},
|
||||
},
|
||||
},
|
||||
"greater-than-100-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScore101,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"negative-profile-percentage-of-nodes-to-score": {
|
||||
expectedToFail: true,
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
errorString: "not in valid range [0-100]",
|
||||
config: profilePercentageOfNodesToScoreNegative,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].percentageOfNodesToScore",
|
||||
},
|
||||
},
|
||||
},
|
||||
"different-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: differentQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: differentQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"one-empty-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: oneEmptyQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
config: oneEmptyQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-negative-weight": {
|
||||
expectedToFail: true,
|
||||
config: extenderNegativeWeight,
|
||||
errorString: "must have a positive weight applied to it",
|
||||
config: extenderNegativeWeight,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].weight",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-managed-resources": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateManagedResource,
|
||||
errorString: "duplicate extender managed resource name",
|
||||
config: extenderDuplicateManagedResource,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders[0].managedResources[1].name",
|
||||
},
|
||||
},
|
||||
},
|
||||
"extender-duplicate-bind": {
|
||||
expectedToFail: true,
|
||||
config: extenderDuplicateBind,
|
||||
errorString: "only one extender can implement bind",
|
||||
config: extenderDuplicateBind,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "extenders",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-node-percentage": {
|
||||
expectedToFail: true,
|
||||
config: invalidNodePercentage,
|
||||
errorString: "not in valid range [0, 100]",
|
||||
config: invalidNodePercentage,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args.minCandidateNodesPercentage",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-plugin-args": {
|
||||
expectedToFail: true,
|
||||
config: invalidPluginArgs,
|
||||
errorString: "has to match plugin args",
|
||||
config: invalidPluginArgs,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].pluginConfig[0].args",
|
||||
},
|
||||
},
|
||||
},
|
||||
"duplicated-plugin-config": {
|
||||
expectedToFail: true,
|
||||
config: duplicatedPluginConfig,
|
||||
errorString: "Duplicate value: \"config\"",
|
||||
config: duplicatedPluginConfig,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeDuplicate,
|
||||
Field: "profiles[0].pluginConfig[1]",
|
||||
},
|
||||
},
|
||||
},
|
||||
"mismatch-queue-sort": {
|
||||
expectedToFail: true,
|
||||
config: mismatchQueueSort,
|
||||
errorString: "has to match for all profiles",
|
||||
},
|
||||
"valid-plugins": {
|
||||
expectedToFail: false,
|
||||
config: validPlugins,
|
||||
config: mismatchQueueSort,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[1].plugins.queueSort",
|
||||
},
|
||||
},
|
||||
},
|
||||
"invalid-plugins": {
|
||||
expectedToFail: true,
|
||||
config: invalidPlugins,
|
||||
errorString: "\"SelectorSpread\": was invalid",
|
||||
config: invalidPlugins,
|
||||
wantErrs: field.ErrorList{
|
||||
&field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "profiles[0].plugins.score.enabled[0]",
|
||||
},
|
||||
},
|
||||
},
|
||||
"valid-plugins": {
|
||||
config: validPlugins,
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
errs := ValidateKubeSchedulerConfiguration(scenario.config)
|
||||
if errs == nil && scenario.expectedToFail {
|
||||
t.Error("Unexpected success")
|
||||
}
|
||||
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())
|
||||
diff := cmp.Diff(scenario.wantErrs.ToAggregate(), errs, ignoreBadValueDetail)
|
||||
if diff != "" {
|
||||
t.Errorf("KubeSchedulerConfiguration returned err (-want,+got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user