mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +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
|
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())
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user