...

Source file src/k8s.io/kubernetes/pkg/apis/autoscaling/validation/validation_test.go

Documentation: k8s.io/kubernetes/pkg/apis/autoscaling/validation

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package validation
    18  
    19  import (
    20  	"strings"
    21  	"testing"
    22  
    23  	"k8s.io/apimachinery/pkg/api/resource"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    26  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    27  	"k8s.io/kubernetes/pkg/apis/autoscaling"
    28  	api "k8s.io/kubernetes/pkg/apis/core"
    29  	"k8s.io/kubernetes/pkg/features"
    30  	utilpointer "k8s.io/utils/pointer"
    31  )
    32  
    33  func TestValidateScale(t *testing.T) {
    34  	successCases := []autoscaling.Scale{{
    35  		ObjectMeta: metav1.ObjectMeta{
    36  			Name:      "frontend",
    37  			Namespace: metav1.NamespaceDefault,
    38  		},
    39  		Spec: autoscaling.ScaleSpec{
    40  			Replicas: 1,
    41  		},
    42  	}, {
    43  		ObjectMeta: metav1.ObjectMeta{
    44  			Name:      "frontend",
    45  			Namespace: metav1.NamespaceDefault,
    46  		},
    47  		Spec: autoscaling.ScaleSpec{
    48  			Replicas: 10,
    49  		},
    50  	}, {
    51  		ObjectMeta: metav1.ObjectMeta{
    52  			Name:      "frontend",
    53  			Namespace: metav1.NamespaceDefault,
    54  		},
    55  		Spec: autoscaling.ScaleSpec{
    56  			Replicas: 0,
    57  		},
    58  	}}
    59  
    60  	for _, successCase := range successCases {
    61  		if errs := ValidateScale(&successCase); len(errs) != 0 {
    62  			t.Errorf("expected success: %v", errs)
    63  		}
    64  	}
    65  
    66  	errorCases := []struct {
    67  		scale autoscaling.Scale
    68  		msg   string
    69  	}{{
    70  		scale: autoscaling.Scale{
    71  			ObjectMeta: metav1.ObjectMeta{
    72  				Name:      "frontend",
    73  				Namespace: metav1.NamespaceDefault,
    74  			},
    75  			Spec: autoscaling.ScaleSpec{
    76  				Replicas: -1,
    77  			},
    78  		},
    79  		msg: "must be greater than or equal to 0",
    80  	}}
    81  
    82  	for _, c := range errorCases {
    83  		if errs := ValidateScale(&c.scale); len(errs) == 0 {
    84  			t.Errorf("expected failure for %s", c.msg)
    85  		} else if !strings.Contains(errs[0].Error(), c.msg) {
    86  			t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
    87  		}
    88  	}
    89  }
    90  
    91  func TestValidateBehavior(t *testing.T) {
    92  	maxPolicy := autoscaling.MaxPolicySelect
    93  	minPolicy := autoscaling.MinPolicySelect
    94  	disabledPolicy := autoscaling.DisabledPolicySelect
    95  	incorrectPolicy := autoscaling.ScalingPolicySelect("incorrect")
    96  	simplePoliciesList := []autoscaling.HPAScalingPolicy{{
    97  		Type:          autoscaling.PercentScalingPolicy,
    98  		Value:         10,
    99  		PeriodSeconds: 1,
   100  	}, {
   101  		Type:          autoscaling.PodsScalingPolicy,
   102  		Value:         1,
   103  		PeriodSeconds: 1800,
   104  	}}
   105  	successCases := []autoscaling.HorizontalPodAutoscalerBehavior{{
   106  		ScaleUp:   nil,
   107  		ScaleDown: nil,
   108  	}, {
   109  		ScaleUp: &autoscaling.HPAScalingRules{
   110  			StabilizationWindowSeconds: utilpointer.Int32(3600),
   111  			SelectPolicy:               &minPolicy,
   112  			Policies:                   simplePoliciesList,
   113  		},
   114  		ScaleDown: &autoscaling.HPAScalingRules{
   115  			StabilizationWindowSeconds: utilpointer.Int32(0),
   116  			SelectPolicy:               &disabledPolicy,
   117  			Policies:                   simplePoliciesList,
   118  		},
   119  	}, {
   120  		ScaleUp: &autoscaling.HPAScalingRules{
   121  			StabilizationWindowSeconds: utilpointer.Int32(120),
   122  			SelectPolicy:               &maxPolicy,
   123  			Policies: []autoscaling.HPAScalingPolicy{{
   124  				Type:          autoscaling.PodsScalingPolicy,
   125  				Value:         1,
   126  				PeriodSeconds: 2,
   127  			}, {
   128  				Type:          autoscaling.PercentScalingPolicy,
   129  				Value:         3,
   130  				PeriodSeconds: 4,
   131  			}, {
   132  				Type:          autoscaling.PodsScalingPolicy,
   133  				Value:         5,
   134  				PeriodSeconds: 6,
   135  			}, {
   136  				Type:          autoscaling.PercentScalingPolicy,
   137  				Value:         7,
   138  				PeriodSeconds: 8,
   139  			}},
   140  		},
   141  		ScaleDown: &autoscaling.HPAScalingRules{
   142  			StabilizationWindowSeconds: utilpointer.Int32(120),
   143  			SelectPolicy:               &maxPolicy,
   144  			Policies: []autoscaling.HPAScalingPolicy{{
   145  				Type:          autoscaling.PodsScalingPolicy,
   146  				Value:         1,
   147  				PeriodSeconds: 2,
   148  			}, {
   149  				Type:          autoscaling.PercentScalingPolicy,
   150  				Value:         3,
   151  				PeriodSeconds: 4,
   152  			}, {
   153  				Type:          autoscaling.PodsScalingPolicy,
   154  				Value:         5,
   155  				PeriodSeconds: 6,
   156  			}, {
   157  				Type:          autoscaling.PercentScalingPolicy,
   158  				Value:         7,
   159  				PeriodSeconds: 8,
   160  			}},
   161  		},
   162  	}}
   163  	for _, behavior := range successCases {
   164  		hpa := prepareHPAWithBehavior(behavior)
   165  		if errs := ValidateHorizontalPodAutoscaler(&hpa); len(errs) != 0 {
   166  			t.Errorf("expected success: %v", errs)
   167  		}
   168  	}
   169  	errorCases := []struct {
   170  		behavior autoscaling.HorizontalPodAutoscalerBehavior
   171  		msg      string
   172  	}{{
   173  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   174  			ScaleUp: &autoscaling.HPAScalingRules{
   175  				SelectPolicy: &minPolicy,
   176  			},
   177  		},
   178  		msg: "spec.behavior.scaleUp.policies: Required value: must specify at least one Policy",
   179  	}, {
   180  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   181  			ScaleUp: &autoscaling.HPAScalingRules{
   182  				StabilizationWindowSeconds: utilpointer.Int32(3601),
   183  				SelectPolicy:               &minPolicy,
   184  				Policies:                   simplePoliciesList,
   185  			},
   186  		},
   187  		msg: "spec.behavior.scaleUp.stabilizationWindowSeconds: Invalid value: 3601: must be less than or equal to 3600",
   188  	}, {
   189  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   190  			ScaleUp: &autoscaling.HPAScalingRules{
   191  				Policies: []autoscaling.HPAScalingPolicy{{
   192  					Type:          autoscaling.PodsScalingPolicy,
   193  					Value:         7,
   194  					PeriodSeconds: 1801,
   195  				}},
   196  			},
   197  		},
   198  		msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: 1801: must be less than or equal to 1800",
   199  	}, {
   200  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   201  			ScaleUp: &autoscaling.HPAScalingRules{
   202  				SelectPolicy: &incorrectPolicy,
   203  				Policies: []autoscaling.HPAScalingPolicy{{
   204  					Type:          autoscaling.PodsScalingPolicy,
   205  					Value:         7,
   206  					PeriodSeconds: 8,
   207  				}},
   208  			},
   209  		},
   210  		msg: `spec.behavior.scaleUp.selectPolicy: Unsupported value: "incorrect": supported values: "Disabled", "Max", "Min"`,
   211  	}, {
   212  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   213  			ScaleUp: &autoscaling.HPAScalingRules{
   214  				Policies: []autoscaling.HPAScalingPolicy{{
   215  					Type:          autoscaling.HPAScalingPolicyType("hm"),
   216  					Value:         7,
   217  					PeriodSeconds: 8,
   218  				}},
   219  			},
   220  		},
   221  		msg: `spec.behavior.scaleUp.policies[0].type: Unsupported value: "hm": supported values: "Percent", "Pods"`,
   222  	}, {
   223  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   224  			ScaleUp: &autoscaling.HPAScalingRules{
   225  				Policies: []autoscaling.HPAScalingPolicy{{
   226  					Type:  autoscaling.PodsScalingPolicy,
   227  					Value: 8,
   228  				}},
   229  			},
   230  		},
   231  		msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: 0: must be greater than zero",
   232  	}, {
   233  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   234  			ScaleUp: &autoscaling.HPAScalingRules{
   235  				Policies: []autoscaling.HPAScalingPolicy{{
   236  					Type:          autoscaling.PodsScalingPolicy,
   237  					PeriodSeconds: 8,
   238  				}},
   239  			},
   240  		},
   241  		msg: "spec.behavior.scaleUp.policies[0].value: Invalid value: 0: must be greater than zero",
   242  	}, {
   243  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   244  			ScaleUp: &autoscaling.HPAScalingRules{
   245  				Policies: []autoscaling.HPAScalingPolicy{{
   246  					Type:          autoscaling.PodsScalingPolicy,
   247  					PeriodSeconds: -1,
   248  					Value:         1,
   249  				}},
   250  			},
   251  		},
   252  		msg: "spec.behavior.scaleUp.policies[0].periodSeconds: Invalid value: -1: must be greater than zero",
   253  	}, {
   254  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   255  			ScaleUp: &autoscaling.HPAScalingRules{
   256  				Policies: []autoscaling.HPAScalingPolicy{{
   257  					Type:          autoscaling.PodsScalingPolicy,
   258  					PeriodSeconds: 1,
   259  					Value:         -1,
   260  				}},
   261  			},
   262  		},
   263  		msg: "spec.behavior.scaleUp.policies[0].value: Invalid value: -1: must be greater than zero",
   264  	}, {
   265  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   266  			ScaleDown: &autoscaling.HPAScalingRules{
   267  				SelectPolicy: &minPolicy,
   268  			},
   269  		},
   270  		msg: "spec.behavior.scaleDown.policies: Required value: must specify at least one Policy",
   271  	}, {
   272  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   273  			ScaleDown: &autoscaling.HPAScalingRules{
   274  				StabilizationWindowSeconds: utilpointer.Int32(3601),
   275  				SelectPolicy:               &minPolicy,
   276  				Policies:                   simplePoliciesList,
   277  			},
   278  		},
   279  		msg: "spec.behavior.scaleDown.stabilizationWindowSeconds: Invalid value: 3601: must be less than or equal to 3600",
   280  	}, {
   281  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   282  			ScaleDown: &autoscaling.HPAScalingRules{
   283  				Policies: []autoscaling.HPAScalingPolicy{{
   284  					Type:          autoscaling.PercentScalingPolicy,
   285  					Value:         7,
   286  					PeriodSeconds: 1801,
   287  				}},
   288  			},
   289  		},
   290  		msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: 1801: must be less than or equal to 1800",
   291  	}, {
   292  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   293  			ScaleDown: &autoscaling.HPAScalingRules{
   294  				SelectPolicy: &incorrectPolicy,
   295  				Policies: []autoscaling.HPAScalingPolicy{{
   296  					Type:          autoscaling.PodsScalingPolicy,
   297  					Value:         7,
   298  					PeriodSeconds: 8,
   299  				}},
   300  			},
   301  		},
   302  		msg: `spec.behavior.scaleDown.selectPolicy: Unsupported value: "incorrect": supported values: "Disabled", "Max", "Min"`,
   303  	}, {
   304  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   305  			ScaleDown: &autoscaling.HPAScalingRules{
   306  				Policies: []autoscaling.HPAScalingPolicy{{
   307  					Type:          autoscaling.HPAScalingPolicyType("hm"),
   308  					Value:         7,
   309  					PeriodSeconds: 8,
   310  				}},
   311  			},
   312  		},
   313  		msg: `spec.behavior.scaleDown.policies[0].type: Unsupported value: "hm": supported values: "Percent", "Pods"`,
   314  	}, {
   315  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   316  			ScaleDown: &autoscaling.HPAScalingRules{
   317  				Policies: []autoscaling.HPAScalingPolicy{{
   318  					Type:  autoscaling.PodsScalingPolicy,
   319  					Value: 8,
   320  				}},
   321  			},
   322  		},
   323  		msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: 0: must be greater than zero",
   324  	}, {
   325  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   326  			ScaleDown: &autoscaling.HPAScalingRules{
   327  				Policies: []autoscaling.HPAScalingPolicy{{
   328  					Type:          autoscaling.PodsScalingPolicy,
   329  					PeriodSeconds: 8,
   330  				}},
   331  			},
   332  		},
   333  		msg: "spec.behavior.scaleDown.policies[0].value: Invalid value: 0: must be greater than zero",
   334  	}, {
   335  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   336  			ScaleDown: &autoscaling.HPAScalingRules{
   337  				Policies: []autoscaling.HPAScalingPolicy{{
   338  					Type:          autoscaling.PodsScalingPolicy,
   339  					PeriodSeconds: -1,
   340  					Value:         1,
   341  				}},
   342  			},
   343  		},
   344  		msg: "spec.behavior.scaleDown.policies[0].periodSeconds: Invalid value: -1: must be greater than zero",
   345  	}, {
   346  		behavior: autoscaling.HorizontalPodAutoscalerBehavior{
   347  			ScaleDown: &autoscaling.HPAScalingRules{
   348  				Policies: []autoscaling.HPAScalingPolicy{{
   349  					Type:          autoscaling.PodsScalingPolicy,
   350  					PeriodSeconds: 1,
   351  					Value:         -1,
   352  				}},
   353  			},
   354  		},
   355  		msg: "spec.behavior.scaleDown.policies[0].value: Invalid value: -1: must be greater than zero",
   356  	}}
   357  	for _, c := range errorCases {
   358  		hpa := prepareHPAWithBehavior(c.behavior)
   359  		if errs := ValidateHorizontalPodAutoscaler(&hpa); len(errs) == 0 {
   360  			t.Errorf("expected failure for %s", c.msg)
   361  		} else if !strings.Contains(errs[0].Error(), c.msg) {
   362  			t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
   363  		}
   364  	}
   365  }
   366  
   367  func prepareHPAWithBehavior(b autoscaling.HorizontalPodAutoscalerBehavior) autoscaling.HorizontalPodAutoscaler {
   368  	return autoscaling.HorizontalPodAutoscaler{
   369  		ObjectMeta: metav1.ObjectMeta{
   370  			Name:      "myautoscaler",
   371  			Namespace: metav1.NamespaceDefault,
   372  		},
   373  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   374  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   375  				Kind: "ReplicationController",
   376  				Name: "myrc",
   377  			},
   378  			MinReplicas: utilpointer.Int32(1),
   379  			MaxReplicas: 5,
   380  			Metrics: []autoscaling.MetricSpec{{
   381  				Type: autoscaling.ResourceMetricSourceType,
   382  				Resource: &autoscaling.ResourceMetricSource{
   383  					Name: api.ResourceCPU,
   384  					Target: autoscaling.MetricTarget{
   385  						Type:               autoscaling.UtilizationMetricType,
   386  						AverageUtilization: utilpointer.Int32(70),
   387  					},
   388  				},
   389  			}},
   390  			Behavior: &b,
   391  		},
   392  	}
   393  }
   394  
   395  func TestValidateHorizontalPodAutoscaler(t *testing.T) {
   396  	metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
   397  	if err != nil {
   398  		t.Errorf("unable to parse label selector: %v", err)
   399  	}
   400  
   401  	successCases := []autoscaling.HorizontalPodAutoscaler{{
   402  		ObjectMeta: metav1.ObjectMeta{
   403  			Name:      "myautoscaler",
   404  			Namespace: metav1.NamespaceDefault,
   405  		},
   406  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   407  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   408  				Kind: "ReplicationController",
   409  				Name: "myrc",
   410  			},
   411  			MinReplicas: utilpointer.Int32(1),
   412  			MaxReplicas: 5,
   413  			Metrics: []autoscaling.MetricSpec{{
   414  				Type: autoscaling.ResourceMetricSourceType,
   415  				Resource: &autoscaling.ResourceMetricSource{
   416  					Name: api.ResourceCPU,
   417  					Target: autoscaling.MetricTarget{
   418  						Type:               autoscaling.UtilizationMetricType,
   419  						AverageUtilization: utilpointer.Int32(70),
   420  					},
   421  				},
   422  			}},
   423  		},
   424  	}, {
   425  		ObjectMeta: metav1.ObjectMeta{
   426  			Name:      "myautoscaler",
   427  			Namespace: metav1.NamespaceDefault,
   428  		},
   429  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   430  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   431  				Kind: "ReplicationController",
   432  				Name: "myrc",
   433  			},
   434  			MinReplicas: utilpointer.Int32(1),
   435  			MaxReplicas: 5,
   436  		},
   437  	}, {
   438  		ObjectMeta: metav1.ObjectMeta{
   439  			Name:      "myautoscaler",
   440  			Namespace: metav1.NamespaceDefault,
   441  		},
   442  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   443  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   444  				Kind: "ReplicationController",
   445  				Name: "myrc",
   446  			},
   447  			MinReplicas: utilpointer.Int32(1),
   448  			MaxReplicas: 5,
   449  			Metrics: []autoscaling.MetricSpec{{
   450  				Type: autoscaling.ResourceMetricSourceType,
   451  				Resource: &autoscaling.ResourceMetricSource{
   452  					Name: api.ResourceCPU,
   453  					Target: autoscaling.MetricTarget{
   454  						Type:         autoscaling.AverageValueMetricType,
   455  						AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
   456  					},
   457  				},
   458  			}},
   459  		},
   460  	}, {
   461  		ObjectMeta: metav1.ObjectMeta{
   462  			Name:      "myautoscaler",
   463  			Namespace: metav1.NamespaceDefault,
   464  		},
   465  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   466  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   467  				Kind: "ReplicationController",
   468  				Name: "myrc",
   469  			},
   470  			MinReplicas: utilpointer.Int32(1),
   471  			MaxReplicas: 5,
   472  			Metrics: []autoscaling.MetricSpec{{
   473  				Type: autoscaling.PodsMetricSourceType,
   474  				Pods: &autoscaling.PodsMetricSource{
   475  					Metric: autoscaling.MetricIdentifier{
   476  						Name: "somemetric",
   477  					},
   478  					Target: autoscaling.MetricTarget{
   479  						Type:         autoscaling.AverageValueMetricType,
   480  						AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
   481  					},
   482  				},
   483  			}},
   484  		},
   485  	}, {
   486  		ObjectMeta: metav1.ObjectMeta{
   487  			Name:      "myautoscaler",
   488  			Namespace: metav1.NamespaceDefault,
   489  		},
   490  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   491  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   492  				Kind: "ReplicationController",
   493  				Name: "myrc",
   494  			},
   495  			MinReplicas: utilpointer.Int32(1),
   496  			MaxReplicas: 5,
   497  			Metrics: []autoscaling.MetricSpec{{
   498  				Type: autoscaling.ContainerResourceMetricSourceType,
   499  				ContainerResource: &autoscaling.ContainerResourceMetricSource{
   500  					Name:      api.ResourceCPU,
   501  					Container: "test-container",
   502  					Target: autoscaling.MetricTarget{
   503  						Type:               autoscaling.UtilizationMetricType,
   504  						AverageUtilization: utilpointer.Int32(70),
   505  					},
   506  				},
   507  			}},
   508  		},
   509  	}, {
   510  		ObjectMeta: metav1.ObjectMeta{
   511  			Name:      "myautoscaler",
   512  			Namespace: metav1.NamespaceDefault,
   513  		},
   514  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   515  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   516  				Kind: "ReplicationController",
   517  				Name: "myrc",
   518  			},
   519  			MinReplicas: utilpointer.Int32(1),
   520  			MaxReplicas: 5,
   521  			Metrics: []autoscaling.MetricSpec{{
   522  				Type: autoscaling.ContainerResourceMetricSourceType,
   523  				ContainerResource: &autoscaling.ContainerResourceMetricSource{
   524  					Name:      api.ResourceCPU,
   525  					Container: "test-container",
   526  					Target: autoscaling.MetricTarget{
   527  						Type:         autoscaling.AverageValueMetricType,
   528  						AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
   529  					},
   530  				},
   531  			}},
   532  		},
   533  	}, {
   534  		ObjectMeta: metav1.ObjectMeta{
   535  			Name:      "myautoscaler",
   536  			Namespace: metav1.NamespaceDefault,
   537  		},
   538  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   539  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   540  				Kind: "ReplicationController",
   541  				Name: "myrc",
   542  			},
   543  			MinReplicas: utilpointer.Int32(1),
   544  			MaxReplicas: 5,
   545  			Metrics: []autoscaling.MetricSpec{{
   546  				Type: autoscaling.ObjectMetricSourceType,
   547  				Object: &autoscaling.ObjectMetricSource{
   548  					DescribedObject: autoscaling.CrossVersionObjectReference{
   549  						Kind: "ReplicationController",
   550  						Name: "myrc",
   551  					},
   552  					Metric: autoscaling.MetricIdentifier{
   553  						Name: "somemetric",
   554  					},
   555  					Target: autoscaling.MetricTarget{
   556  						Type:  autoscaling.ValueMetricType,
   557  						Value: resource.NewMilliQuantity(300, resource.DecimalSI),
   558  					},
   559  				},
   560  			}},
   561  		},
   562  	}, {
   563  		ObjectMeta: metav1.ObjectMeta{
   564  			Name:      "myautoscaler",
   565  			Namespace: metav1.NamespaceDefault,
   566  		},
   567  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   568  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   569  				Kind: "ReplicationController",
   570  				Name: "myrc",
   571  			},
   572  			MinReplicas: utilpointer.Int32(1),
   573  			MaxReplicas: 5,
   574  			Metrics: []autoscaling.MetricSpec{{
   575  				Type: autoscaling.ExternalMetricSourceType,
   576  				External: &autoscaling.ExternalMetricSource{
   577  					Metric: autoscaling.MetricIdentifier{
   578  						Name:     "somemetric",
   579  						Selector: metricLabelSelector,
   580  					},
   581  					Target: autoscaling.MetricTarget{
   582  						Type:  autoscaling.ValueMetricType,
   583  						Value: resource.NewMilliQuantity(300, resource.DecimalSI),
   584  					},
   585  				},
   586  			}},
   587  		},
   588  	}, {
   589  		ObjectMeta: metav1.ObjectMeta{
   590  			Name:      "myautoscaler",
   591  			Namespace: metav1.NamespaceDefault,
   592  		},
   593  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
   594  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
   595  				Kind: "ReplicationController",
   596  				Name: "myrc",
   597  			},
   598  			MinReplicas: utilpointer.Int32(1),
   599  			MaxReplicas: 5,
   600  			Metrics: []autoscaling.MetricSpec{{
   601  				Type: autoscaling.ExternalMetricSourceType,
   602  				External: &autoscaling.ExternalMetricSource{
   603  					Metric: autoscaling.MetricIdentifier{
   604  						Name:     "somemetric",
   605  						Selector: metricLabelSelector,
   606  					},
   607  					Target: autoscaling.MetricTarget{
   608  						Type:         autoscaling.AverageValueMetricType,
   609  						AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
   610  					},
   611  				},
   612  			}},
   613  		},
   614  	}}
   615  	for _, successCase := range successCases {
   616  		if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
   617  			t.Errorf("expected success: %v", errs)
   618  		}
   619  	}
   620  
   621  	errorCases := []struct {
   622  		horizontalPodAutoscaler autoscaling.HorizontalPodAutoscaler
   623  		msg                     string
   624  	}{{
   625  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   626  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   627  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   628  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
   629  				MinReplicas:    utilpointer.Int32(1),
   630  				MaxReplicas:    5,
   631  				Metrics: []autoscaling.MetricSpec{{
   632  					Type: autoscaling.ResourceMetricSourceType,
   633  					Resource: &autoscaling.ResourceMetricSource{
   634  						Name: api.ResourceCPU,
   635  						Target: autoscaling.MetricTarget{
   636  							Type:               autoscaling.UtilizationMetricType,
   637  							AverageUtilization: utilpointer.Int32(70),
   638  						},
   639  					},
   640  				}},
   641  			},
   642  		},
   643  		msg: "scaleTargetRef.kind: Required",
   644  	}, {
   645  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   646  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   647  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   648  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc"},
   649  				MinReplicas:    utilpointer.Int32(1),
   650  				MaxReplicas:    5,
   651  				Metrics: []autoscaling.MetricSpec{{
   652  					Type: autoscaling.ContainerResourceMetricSourceType,
   653  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   654  						Name:      api.ResourceCPU,
   655  						Container: "test-application",
   656  						Target: autoscaling.MetricTarget{
   657  							Type:               autoscaling.UtilizationMetricType,
   658  							AverageUtilization: utilpointer.Int32(70),
   659  						},
   660  					},
   661  				}},
   662  			},
   663  		},
   664  		msg: "scaleTargetRef.kind: Required",
   665  	}, {
   666  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   667  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   668  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   669  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
   670  				MinReplicas:    utilpointer.Int32(1),
   671  				MaxReplicas:    5,
   672  				Metrics: []autoscaling.MetricSpec{{
   673  					Type: autoscaling.ResourceMetricSourceType,
   674  					Resource: &autoscaling.ResourceMetricSource{
   675  						Name: api.ResourceCPU,
   676  						Target: autoscaling.MetricTarget{
   677  							Type:               autoscaling.UtilizationMetricType,
   678  							AverageUtilization: utilpointer.Int32(70),
   679  						},
   680  					},
   681  				}},
   682  			},
   683  		},
   684  		msg: "scaleTargetRef.kind: Invalid",
   685  	}, {
   686  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   687  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   688  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   689  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "..", Name: "myrc"},
   690  				MinReplicas:    utilpointer.Int32(1),
   691  				MaxReplicas:    5,
   692  				Metrics: []autoscaling.MetricSpec{{
   693  					Type: autoscaling.ContainerResourceMetricSourceType,
   694  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   695  						Name:      api.ResourceCPU,
   696  						Container: "test-application",
   697  						Target: autoscaling.MetricTarget{
   698  							Type:               autoscaling.UtilizationMetricType,
   699  							AverageUtilization: utilpointer.Int32(70),
   700  						},
   701  					},
   702  				}},
   703  			},
   704  		},
   705  		msg: "scaleTargetRef.kind: Invalid",
   706  	}, {
   707  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   708  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   709  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   710  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
   711  				MinReplicas:    utilpointer.Int32(1),
   712  				MaxReplicas:    5,
   713  				Metrics: []autoscaling.MetricSpec{{
   714  					Type: autoscaling.ResourceMetricSourceType,
   715  					Resource: &autoscaling.ResourceMetricSource{
   716  						Name: api.ResourceCPU,
   717  						Target: autoscaling.MetricTarget{
   718  							Type:               autoscaling.UtilizationMetricType,
   719  							AverageUtilization: utilpointer.Int32(70),
   720  						},
   721  					},
   722  				}},
   723  			},
   724  		},
   725  		msg: "scaleTargetRef.name: Required",
   726  	}, {
   727  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   728  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   729  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   730  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController"},
   731  				MinReplicas:    utilpointer.Int32(1),
   732  				MaxReplicas:    5,
   733  				Metrics: []autoscaling.MetricSpec{{
   734  					Type: autoscaling.ContainerResourceMetricSourceType,
   735  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   736  						Name:      api.ResourceCPU,
   737  						Container: "test-application",
   738  						Target: autoscaling.MetricTarget{
   739  							Type:               autoscaling.UtilizationMetricType,
   740  							AverageUtilization: utilpointer.Int32(70),
   741  						},
   742  					},
   743  				}},
   744  			},
   745  		},
   746  		msg: "scaleTargetRef.name: Required",
   747  	}, {
   748  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   749  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   750  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   751  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
   752  				MinReplicas:    utilpointer.Int32(1),
   753  				MaxReplicas:    5,
   754  				Metrics: []autoscaling.MetricSpec{{
   755  					Type: autoscaling.ResourceMetricSourceType,
   756  					Resource: &autoscaling.ResourceMetricSource{
   757  						Name: api.ResourceCPU,
   758  						Target: autoscaling.MetricTarget{
   759  							Type:               autoscaling.UtilizationMetricType,
   760  							AverageUtilization: utilpointer.Int32(70),
   761  						},
   762  					},
   763  				}},
   764  			},
   765  		},
   766  		msg: "scaleTargetRef.name: Invalid",
   767  	}, {
   768  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   769  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   770  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   771  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Kind: "ReplicationController", Name: ".."},
   772  				MinReplicas:    utilpointer.Int32(1),
   773  				MaxReplicas:    5,
   774  				Metrics: []autoscaling.MetricSpec{{
   775  					Type: autoscaling.ContainerResourceMetricSourceType,
   776  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   777  						Name:      api.ResourceCPU,
   778  						Container: "test-application",
   779  						Target: autoscaling.MetricTarget{
   780  							Type:               autoscaling.UtilizationMetricType,
   781  							AverageUtilization: utilpointer.Int32(70),
   782  						},
   783  					},
   784  				}},
   785  			},
   786  		},
   787  		msg: "scaleTargetRef.name: Invalid",
   788  	}, {
   789  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   790  			ObjectMeta: metav1.ObjectMeta{
   791  				Name:      "myautoscaler",
   792  				Namespace: metav1.NamespaceDefault,
   793  			},
   794  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   795  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
   796  				MinReplicas:    utilpointer.Int32(-1),
   797  				MaxReplicas:    5,
   798  			},
   799  		},
   800  		msg: "must be greater than or equal to 1",
   801  	}, {
   802  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   803  			ObjectMeta: metav1.ObjectMeta{
   804  				Name:      "myautoscaler",
   805  				Namespace: metav1.NamespaceDefault,
   806  			},
   807  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   808  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{},
   809  				MinReplicas:    utilpointer.Int32(7),
   810  				MaxReplicas:    5,
   811  			},
   812  		},
   813  		msg: "must be greater than or equal to `minReplicas`",
   814  	}, {
   815  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   816  			ObjectMeta: metav1.ObjectMeta{
   817  				Name:      "myautoscaler",
   818  				Namespace: metav1.NamespaceDefault,
   819  			},
   820  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   821  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   822  				MinReplicas:    utilpointer.Int32(1),
   823  				MaxReplicas:    5,
   824  				Metrics: []autoscaling.MetricSpec{{
   825  					Type: autoscaling.ResourceMetricSourceType,
   826  					Resource: &autoscaling.ResourceMetricSource{
   827  						Name: api.ResourceCPU,
   828  						Target: autoscaling.MetricTarget{
   829  							Type:               autoscaling.UtilizationMetricType,
   830  							AverageUtilization: utilpointer.Int32(70),
   831  							AverageValue:       resource.NewMilliQuantity(300, resource.DecimalSI),
   832  						},
   833  					},
   834  				}},
   835  			},
   836  		},
   837  		msg: "may not set both a target raw value and a target utilization",
   838  	}, {
   839  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   840  			ObjectMeta: metav1.ObjectMeta{
   841  				Name:      "myautoscaler",
   842  				Namespace: metav1.NamespaceDefault,
   843  			},
   844  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   845  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   846  				MinReplicas:    utilpointer.Int32(1),
   847  				MaxReplicas:    5,
   848  				Metrics: []autoscaling.MetricSpec{{
   849  					Type: autoscaling.ContainerResourceMetricSourceType,
   850  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   851  						Name:      api.ResourceCPU,
   852  						Container: "test-application",
   853  						Target: autoscaling.MetricTarget{
   854  							Type:               autoscaling.UtilizationMetricType,
   855  							AverageUtilization: utilpointer.Int32(70),
   856  							AverageValue:       resource.NewMilliQuantity(300, resource.DecimalSI),
   857  						},
   858  					},
   859  				}},
   860  			},
   861  		},
   862  		msg: "may not set both a target raw value and a target utilization",
   863  	}, {
   864  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   865  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   866  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   867  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   868  				MinReplicas:    utilpointer.Int32(1),
   869  				MaxReplicas:    5,
   870  				Metrics: []autoscaling.MetricSpec{{
   871  					Type: autoscaling.ResourceMetricSourceType,
   872  					Resource: &autoscaling.ResourceMetricSource{
   873  						Target: autoscaling.MetricTarget{
   874  							Type:               autoscaling.UtilizationMetricType,
   875  							AverageUtilization: utilpointer.Int32(70),
   876  						},
   877  					},
   878  				}},
   879  			},
   880  		},
   881  		msg: "must specify a resource name",
   882  	}, {
   883  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   884  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   885  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   886  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   887  				MinReplicas:    utilpointer.Int32(1),
   888  				MaxReplicas:    5,
   889  				Metrics: []autoscaling.MetricSpec{{
   890  					Type: autoscaling.ContainerResourceMetricSourceType,
   891  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   892  						Container: "test-application",
   893  						Target: autoscaling.MetricTarget{
   894  							Type:               autoscaling.UtilizationMetricType,
   895  							AverageUtilization: utilpointer.Int32(70),
   896  						},
   897  					},
   898  				}},
   899  			},
   900  		},
   901  		msg: "must specify a resource name",
   902  	}, {
   903  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   904  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   905  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   906  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   907  				MinReplicas:    utilpointer.Int32(1),
   908  				MaxReplicas:    5,
   909  				Metrics: []autoscaling.MetricSpec{{
   910  					Type: autoscaling.ContainerResourceMetricSourceType,
   911  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   912  						Name:      "InvalidResource",
   913  						Container: "test-application",
   914  						Target: autoscaling.MetricTarget{
   915  							Type:               autoscaling.UtilizationMetricType,
   916  							AverageUtilization: utilpointer.Int32(70),
   917  						},
   918  					},
   919  				}},
   920  			},
   921  		},
   922  		msg: "Invalid value: InvalidResource: must be a standard resource type or fully qualified",
   923  	}, {
   924  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   925  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   926  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   927  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   928  				MinReplicas:    utilpointer.Int32(1),
   929  				MaxReplicas:    5,
   930  				Metrics: []autoscaling.MetricSpec{{
   931  					Type: autoscaling.ResourceMetricSourceType,
   932  					Resource: &autoscaling.ResourceMetricSource{
   933  						Name: api.ResourceCPU,
   934  						Target: autoscaling.MetricTarget{
   935  							Type:               autoscaling.UtilizationMetricType,
   936  							AverageUtilization: utilpointer.Int32(-10),
   937  						},
   938  					},
   939  				}},
   940  			},
   941  		},
   942  		msg: "must be greater than 0",
   943  	}, {
   944  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   945  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   946  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   947  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   948  				MinReplicas:    utilpointer.Int32(1),
   949  				MaxReplicas:    5,
   950  				Metrics: []autoscaling.MetricSpec{{
   951  					Type: autoscaling.ContainerResourceMetricSourceType,
   952  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   953  						Name:      api.ResourceCPU,
   954  						Container: "test-application",
   955  						Target: autoscaling.MetricTarget{
   956  							Type:               autoscaling.UtilizationMetricType,
   957  							AverageUtilization: utilpointer.Int32(-10),
   958  						},
   959  					},
   960  				}},
   961  			},
   962  		},
   963  		msg: "must be greater than 0",
   964  	}, {
   965  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   966  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   967  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   968  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   969  				MinReplicas:    utilpointer.Int32(1),
   970  				MaxReplicas:    5,
   971  				Metrics: []autoscaling.MetricSpec{{
   972  					Type: autoscaling.ContainerResourceMetricSourceType,
   973  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   974  						Name: api.ResourceCPU,
   975  						Target: autoscaling.MetricTarget{
   976  							Type:               autoscaling.UtilizationMetricType,
   977  							AverageUtilization: utilpointer.Int32(-10),
   978  						},
   979  					},
   980  				}},
   981  			},
   982  		},
   983  		msg: "must specify a container",
   984  	}, {
   985  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
   986  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
   987  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
   988  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
   989  				MinReplicas:    utilpointer.Int32(1),
   990  				MaxReplicas:    5,
   991  				Metrics: []autoscaling.MetricSpec{{
   992  					Type: autoscaling.ContainerResourceMetricSourceType,
   993  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
   994  						Name:      api.ResourceCPU,
   995  						Container: "---***",
   996  						Target: autoscaling.MetricTarget{
   997  							Type:               autoscaling.UtilizationMetricType,
   998  							AverageUtilization: utilpointer.Int32(-10),
   999  						},
  1000  					},
  1001  				}},
  1002  			},
  1003  		},
  1004  		msg: "Invalid value: \"---***\"",
  1005  	}, {
  1006  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1007  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1008  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1009  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1010  				MinReplicas:    utilpointer.Int32(1),
  1011  				MaxReplicas:    5,
  1012  				Metrics: []autoscaling.MetricSpec{{
  1013  					Type: autoscaling.ResourceMetricSourceType,
  1014  					Resource: &autoscaling.ResourceMetricSource{
  1015  						Name: api.ResourceCPU,
  1016  						Target: autoscaling.MetricTarget{
  1017  							Type: autoscaling.ValueMetricType,
  1018  						},
  1019  					},
  1020  				}},
  1021  			},
  1022  		},
  1023  		msg: "must set either a target raw value or a target utilization",
  1024  	}, {
  1025  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1026  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1027  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1028  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1029  				MinReplicas:    utilpointer.Int32(1),
  1030  				MaxReplicas:    5,
  1031  				Metrics: []autoscaling.MetricSpec{{
  1032  					Type: autoscaling.ContainerResourceMetricSourceType,
  1033  					ContainerResource: &autoscaling.ContainerResourceMetricSource{
  1034  						Name:      api.ResourceCPU,
  1035  						Container: "test-application",
  1036  						Target: autoscaling.MetricTarget{
  1037  							Type: autoscaling.ValueMetricType,
  1038  						},
  1039  					},
  1040  				}},
  1041  			},
  1042  		},
  1043  		msg: "must set either a target raw value or a target utilization",
  1044  	}, {
  1045  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1046  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1047  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1048  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1049  				MinReplicas:    utilpointer.Int32(1),
  1050  				MaxReplicas:    5,
  1051  				Metrics: []autoscaling.MetricSpec{{
  1052  					Type: autoscaling.PodsMetricSourceType,
  1053  					Pods: &autoscaling.PodsMetricSource{
  1054  						Metric: autoscaling.MetricIdentifier{},
  1055  						Target: autoscaling.MetricTarget{
  1056  							Type:         autoscaling.ValueMetricType,
  1057  							AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1058  						},
  1059  					},
  1060  				}},
  1061  			},
  1062  		},
  1063  		msg: "must specify a metric name",
  1064  	}, {
  1065  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1066  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1067  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1068  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1069  				MinReplicas:    utilpointer.Int32(1),
  1070  				MaxReplicas:    5,
  1071  				Metrics: []autoscaling.MetricSpec{{
  1072  					Type: autoscaling.PodsMetricSourceType,
  1073  					Pods: &autoscaling.PodsMetricSource{
  1074  						Metric: autoscaling.MetricIdentifier{
  1075  							Name: "somemetric",
  1076  						},
  1077  						Target: autoscaling.MetricTarget{
  1078  							Type: autoscaling.ValueMetricType,
  1079  						},
  1080  					},
  1081  				}},
  1082  			},
  1083  		},
  1084  		msg: "must specify a positive target averageValue",
  1085  	}, {
  1086  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1087  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1088  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1089  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1090  				MinReplicas:    utilpointer.Int32(1),
  1091  				MaxReplicas:    5,
  1092  				Metrics: []autoscaling.MetricSpec{{
  1093  					Type: autoscaling.ObjectMetricSourceType,
  1094  					Object: &autoscaling.ObjectMetricSource{
  1095  						DescribedObject: autoscaling.CrossVersionObjectReference{
  1096  							Kind: "ReplicationController",
  1097  							Name: "myrc",
  1098  						},
  1099  						Metric: autoscaling.MetricIdentifier{
  1100  							Name: "somemetric",
  1101  						},
  1102  						Target: autoscaling.MetricTarget{
  1103  							Type: autoscaling.ValueMetricType,
  1104  						},
  1105  					},
  1106  				}},
  1107  			},
  1108  		},
  1109  		msg: "must set either a target value or averageValue",
  1110  	}, {
  1111  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1112  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1113  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1114  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1115  				MinReplicas:    utilpointer.Int32(1),
  1116  				MaxReplicas:    5,
  1117  				Metrics: []autoscaling.MetricSpec{{
  1118  					Type: autoscaling.ObjectMetricSourceType,
  1119  					Object: &autoscaling.ObjectMetricSource{
  1120  						DescribedObject: autoscaling.CrossVersionObjectReference{
  1121  							Name: "myrc",
  1122  						},
  1123  						Metric: autoscaling.MetricIdentifier{
  1124  							Name: "somemetric",
  1125  						},
  1126  						Target: autoscaling.MetricTarget{
  1127  							Type:  autoscaling.ValueMetricType,
  1128  							Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  1129  						},
  1130  					},
  1131  				}},
  1132  			},
  1133  		},
  1134  		msg: "object.describedObject.kind: Required",
  1135  	}, {
  1136  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1137  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1138  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1139  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1140  				MinReplicas:    utilpointer.Int32(1),
  1141  				MaxReplicas:    5,
  1142  				Metrics: []autoscaling.MetricSpec{{
  1143  					Type: autoscaling.ObjectMetricSourceType,
  1144  					Object: &autoscaling.ObjectMetricSource{
  1145  						DescribedObject: autoscaling.CrossVersionObjectReference{
  1146  							Kind: "ReplicationController",
  1147  							Name: "myrc",
  1148  						},
  1149  						Target: autoscaling.MetricTarget{
  1150  							Type:  autoscaling.ValueMetricType,
  1151  							Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  1152  						},
  1153  					},
  1154  				}},
  1155  			},
  1156  		},
  1157  		msg: "must specify a metric name",
  1158  	}, {
  1159  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1160  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1161  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1162  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1163  				MinReplicas:    utilpointer.Int32(1),
  1164  				MaxReplicas:    5,
  1165  				Metrics: []autoscaling.MetricSpec{{
  1166  					Type: autoscaling.ExternalMetricSourceType,
  1167  					External: &autoscaling.ExternalMetricSource{
  1168  						Metric: autoscaling.MetricIdentifier{
  1169  							Selector: metricLabelSelector,
  1170  						},
  1171  						Target: autoscaling.MetricTarget{
  1172  							Type:  autoscaling.ValueMetricType,
  1173  							Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  1174  						},
  1175  					},
  1176  				}},
  1177  			},
  1178  		},
  1179  		msg: "must specify a metric name",
  1180  	}, {
  1181  		horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1182  			ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1183  			Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1184  				ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1185  				MinReplicas:    utilpointer.Int32(1),
  1186  				MaxReplicas:    5,
  1187  				Metrics: []autoscaling.MetricSpec{{
  1188  					Type: autoscaling.ExternalMetricSourceType,
  1189  					External: &autoscaling.ExternalMetricSource{
  1190  						Metric: autoscaling.MetricIdentifier{
  1191  							Name:     "foo/../",
  1192  							Selector: metricLabelSelector,
  1193  						},
  1194  						Target: autoscaling.MetricTarget{
  1195  							Type:  autoscaling.ValueMetricType,
  1196  							Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  1197  						},
  1198  					},
  1199  				}},
  1200  			},
  1201  		},
  1202  		msg: "'/'",
  1203  	},
  1204  
  1205  		{
  1206  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1207  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1208  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1209  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1210  					MinReplicas:    utilpointer.Int32(1),
  1211  					MaxReplicas:    5,
  1212  					Metrics: []autoscaling.MetricSpec{{
  1213  						Type: autoscaling.ExternalMetricSourceType,
  1214  						External: &autoscaling.ExternalMetricSource{
  1215  							Metric: autoscaling.MetricIdentifier{
  1216  								Name:     "somemetric",
  1217  								Selector: metricLabelSelector,
  1218  							},
  1219  							Target: autoscaling.MetricTarget{
  1220  								Type: autoscaling.ValueMetricType,
  1221  							},
  1222  						},
  1223  					}},
  1224  				},
  1225  			},
  1226  			msg: "must set either a target value for metric or a per-pod target",
  1227  		}, {
  1228  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1229  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1230  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1231  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1232  					MinReplicas:    utilpointer.Int32(1),
  1233  					MaxReplicas:    5,
  1234  					Metrics: []autoscaling.MetricSpec{{
  1235  						Type: autoscaling.ExternalMetricSourceType,
  1236  						External: &autoscaling.ExternalMetricSource{
  1237  							Metric: autoscaling.MetricIdentifier{
  1238  								Name:     "somemetric",
  1239  								Selector: metricLabelSelector,
  1240  							},
  1241  							Target: autoscaling.MetricTarget{
  1242  								Type:  autoscaling.ValueMetricType,
  1243  								Value: resource.NewMilliQuantity(-300, resource.DecimalSI),
  1244  							},
  1245  						},
  1246  					}},
  1247  				},
  1248  			},
  1249  			msg: "must be positive",
  1250  		}, {
  1251  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1252  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1253  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1254  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1255  					MinReplicas:    utilpointer.Int32(1),
  1256  					MaxReplicas:    5,
  1257  					Metrics: []autoscaling.MetricSpec{{
  1258  						Type: autoscaling.ExternalMetricSourceType,
  1259  						External: &autoscaling.ExternalMetricSource{
  1260  							Metric: autoscaling.MetricIdentifier{
  1261  								Name:     "somemetric",
  1262  								Selector: metricLabelSelector,
  1263  							},
  1264  							Target: autoscaling.MetricTarget{
  1265  								Type:         autoscaling.ValueMetricType,
  1266  								AverageValue: resource.NewMilliQuantity(-300, resource.DecimalSI),
  1267  							},
  1268  						},
  1269  					}},
  1270  				},
  1271  			},
  1272  			msg: "must be positive",
  1273  		}, {
  1274  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1275  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1276  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1277  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1278  					MinReplicas:    utilpointer.Int32(1),
  1279  					MaxReplicas:    5,
  1280  					Metrics: []autoscaling.MetricSpec{{
  1281  						Type: autoscaling.ExternalMetricSourceType,
  1282  						External: &autoscaling.ExternalMetricSource{
  1283  							Metric: autoscaling.MetricIdentifier{
  1284  								Name:     "somemetric",
  1285  								Selector: metricLabelSelector,
  1286  							},
  1287  							Target: autoscaling.MetricTarget{
  1288  								Type:         autoscaling.ValueMetricType,
  1289  								Value:        resource.NewMilliQuantity(300, resource.DecimalSI),
  1290  								AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  1291  							},
  1292  						},
  1293  					}},
  1294  				},
  1295  			},
  1296  			msg: "may not set both a target value for metric and a per-pod target",
  1297  		}, {
  1298  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1299  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1300  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1301  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1302  					MinReplicas:    utilpointer.Int32(1),
  1303  					MaxReplicas:    5,
  1304  					Metrics: []autoscaling.MetricSpec{{
  1305  						Type: autoscaling.ExternalMetricSourceType,
  1306  						External: &autoscaling.ExternalMetricSource{
  1307  							Metric: autoscaling.MetricIdentifier{
  1308  								Name:     "somemetric",
  1309  								Selector: metricLabelSelector,
  1310  							},
  1311  							Target: autoscaling.MetricTarget{
  1312  								Type:  "boogity",
  1313  								Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  1314  							},
  1315  						},
  1316  					}},
  1317  				},
  1318  			},
  1319  			msg: "must be either Utilization, Value, or AverageValue",
  1320  		}, {
  1321  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1322  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1323  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1324  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1325  					MinReplicas:    utilpointer.Int32(1),
  1326  					MaxReplicas:    5,
  1327  					Metrics: []autoscaling.MetricSpec{{
  1328  						Type: autoscaling.ExternalMetricSourceType,
  1329  						External: &autoscaling.ExternalMetricSource{
  1330  							Metric: autoscaling.MetricIdentifier{
  1331  								Name:     "somemetric",
  1332  								Selector: metricLabelSelector,
  1333  							},
  1334  							Target: autoscaling.MetricTarget{
  1335  								Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  1336  							},
  1337  						},
  1338  					}},
  1339  				},
  1340  			},
  1341  			msg: "must specify a metric target type",
  1342  		}, {
  1343  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1344  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1345  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1346  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1347  					MinReplicas:    utilpointer.Int32(1),
  1348  					MaxReplicas:    5,
  1349  					Metrics: []autoscaling.MetricSpec{{
  1350  						Type: autoscaling.ExternalMetricSourceType,
  1351  						External: &autoscaling.ExternalMetricSource{
  1352  							Metric: autoscaling.MetricIdentifier{
  1353  								Name:     "somemetric",
  1354  								Selector: metricLabelSelector,
  1355  							},
  1356  						},
  1357  					}},
  1358  				},
  1359  			},
  1360  			msg: "must specify a metric target",
  1361  		}, {
  1362  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1363  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1364  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1365  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1366  					MinReplicas:    utilpointer.Int32(1),
  1367  					MaxReplicas:    5,
  1368  					Metrics: []autoscaling.MetricSpec{
  1369  						{},
  1370  					},
  1371  				},
  1372  			},
  1373  			msg: "must specify a metric source type",
  1374  		}, {
  1375  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1376  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1377  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1378  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1379  					MinReplicas:    utilpointer.Int32(1),
  1380  					MaxReplicas:    5,
  1381  					Metrics: []autoscaling.MetricSpec{{
  1382  						Type: autoscaling.MetricSourceType("InvalidType"),
  1383  					}},
  1384  				},
  1385  			},
  1386  			msg: "type: Unsupported value",
  1387  		}, {
  1388  			horizontalPodAutoscaler: autoscaling.HorizontalPodAutoscaler{
  1389  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1390  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1391  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1392  					MinReplicas:    utilpointer.Int32(1),
  1393  					MaxReplicas:    5,
  1394  					Metrics: []autoscaling.MetricSpec{{
  1395  						Type: autoscaling.ResourceMetricSourceType,
  1396  						Resource: &autoscaling.ResourceMetricSource{
  1397  							Name: api.ResourceCPU,
  1398  							Target: autoscaling.MetricTarget{
  1399  								Type:         autoscaling.AverageValueMetricType,
  1400  								AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1401  							},
  1402  						},
  1403  						Pods: &autoscaling.PodsMetricSource{
  1404  							Metric: autoscaling.MetricIdentifier{
  1405  								Name: "somemetric",
  1406  							},
  1407  							Target: autoscaling.MetricTarget{
  1408  								Type:         autoscaling.AverageValueMetricType,
  1409  								AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1410  							},
  1411  						},
  1412  					}},
  1413  				},
  1414  			},
  1415  			msg: "must populate the given metric source only",
  1416  		},
  1417  	}
  1418  
  1419  	for _, c := range errorCases {
  1420  		errs := ValidateHorizontalPodAutoscaler(&c.horizontalPodAutoscaler)
  1421  		if len(errs) == 0 {
  1422  			t.Errorf("expected failure for %q", c.msg)
  1423  		} else if !strings.Contains(errs[0].Error(), c.msg) {
  1424  			t.Errorf("unexpected error: %q, expected: %q", errs[0], c.msg)
  1425  		}
  1426  	}
  1427  
  1428  	sourceTypes := map[autoscaling.MetricSourceType]autoscaling.MetricSpec{
  1429  		autoscaling.ResourceMetricSourceType: {
  1430  			Resource: &autoscaling.ResourceMetricSource{
  1431  				Name: api.ResourceCPU,
  1432  				Target: autoscaling.MetricTarget{
  1433  					Type:         autoscaling.AverageValueMetricType,
  1434  					AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1435  				},
  1436  			},
  1437  		},
  1438  		autoscaling.ContainerResourceMetricSourceType: {
  1439  			ContainerResource: &autoscaling.ContainerResourceMetricSource{
  1440  				Name:      api.ResourceCPU,
  1441  				Container: "test-application",
  1442  				Target: autoscaling.MetricTarget{
  1443  					Type:         autoscaling.AverageValueMetricType,
  1444  					AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1445  				},
  1446  			},
  1447  		},
  1448  		autoscaling.PodsMetricSourceType: {
  1449  			Pods: &autoscaling.PodsMetricSource{
  1450  				Metric: autoscaling.MetricIdentifier{
  1451  					Name: "somemetric",
  1452  				},
  1453  				Target: autoscaling.MetricTarget{
  1454  					Type:         autoscaling.AverageValueMetricType,
  1455  					AverageValue: resource.NewMilliQuantity(100, resource.DecimalSI),
  1456  				},
  1457  			},
  1458  		},
  1459  		autoscaling.ObjectMetricSourceType: {
  1460  			Object: &autoscaling.ObjectMetricSource{
  1461  				DescribedObject: autoscaling.CrossVersionObjectReference{
  1462  					Kind: "ReplicationController",
  1463  					Name: "myrc",
  1464  				},
  1465  				Metric: autoscaling.MetricIdentifier{
  1466  					Name: "somemetric",
  1467  				},
  1468  				Target: autoscaling.MetricTarget{
  1469  					Type:  autoscaling.ValueMetricType,
  1470  					Value: resource.NewMilliQuantity(100, resource.DecimalSI),
  1471  				},
  1472  			},
  1473  		},
  1474  	}
  1475  
  1476  	for correctType, spec := range sourceTypes {
  1477  		for incorrectType := range sourceTypes {
  1478  			if correctType == incorrectType {
  1479  				continue
  1480  			}
  1481  
  1482  			spec.Type = incorrectType
  1483  
  1484  			errs := ValidateHorizontalPodAutoscaler(&autoscaling.HorizontalPodAutoscaler{
  1485  				ObjectMeta: metav1.ObjectMeta{Name: "myautoscaler", Namespace: metav1.NamespaceDefault},
  1486  				Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1487  					ScaleTargetRef: autoscaling.CrossVersionObjectReference{Name: "myrc", Kind: "ReplicationController"},
  1488  					MinReplicas:    utilpointer.Int32(1),
  1489  					MaxReplicas:    5, Metrics: []autoscaling.MetricSpec{spec},
  1490  				},
  1491  			})
  1492  
  1493  			expectedMsg := "must populate information for the given metric source"
  1494  
  1495  			if len(errs) == 0 {
  1496  				t.Errorf("expected failure with type of %v and spec for %v", incorrectType, correctType)
  1497  			} else if !strings.Contains(errs[0].Error(), expectedMsg) {
  1498  				t.Errorf("unexpected error: %q, expected %q", errs[0], expectedMsg)
  1499  			}
  1500  		}
  1501  	}
  1502  }
  1503  
  1504  func prepareMinReplicasCases(t *testing.T, minReplicas int32) []autoscaling.HorizontalPodAutoscaler {
  1505  	metricLabelSelector, err := metav1.ParseToLabelSelector("label=value")
  1506  	if err != nil {
  1507  		t.Errorf("unable to parse label selector: %v", err)
  1508  	}
  1509  	minReplicasCases := []autoscaling.HorizontalPodAutoscaler{{
  1510  		ObjectMeta: metav1.ObjectMeta{
  1511  			Name:            "myautoscaler",
  1512  			Namespace:       metav1.NamespaceDefault,
  1513  			ResourceVersion: "theversion",
  1514  		},
  1515  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1516  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  1517  				Kind: "ReplicationController",
  1518  				Name: "myrc",
  1519  			},
  1520  			MinReplicas: utilpointer.Int32(minReplicas),
  1521  			MaxReplicas: 5,
  1522  			Metrics: []autoscaling.MetricSpec{{
  1523  				Type: autoscaling.ObjectMetricSourceType,
  1524  				Object: &autoscaling.ObjectMetricSource{
  1525  					DescribedObject: autoscaling.CrossVersionObjectReference{
  1526  						Kind: "ReplicationController",
  1527  						Name: "myrc",
  1528  					},
  1529  					Metric: autoscaling.MetricIdentifier{
  1530  						Name: "somemetric",
  1531  					},
  1532  					Target: autoscaling.MetricTarget{
  1533  						Type:  autoscaling.ValueMetricType,
  1534  						Value: resource.NewMilliQuantity(300, resource.DecimalSI),
  1535  					},
  1536  				},
  1537  			}},
  1538  		},
  1539  	}, {
  1540  		ObjectMeta: metav1.ObjectMeta{
  1541  			Name:            "myautoscaler",
  1542  			Namespace:       metav1.NamespaceDefault,
  1543  			ResourceVersion: "theversion",
  1544  		},
  1545  		Spec: autoscaling.HorizontalPodAutoscalerSpec{
  1546  			ScaleTargetRef: autoscaling.CrossVersionObjectReference{
  1547  				Kind: "ReplicationController",
  1548  				Name: "myrc",
  1549  			},
  1550  			MinReplicas: utilpointer.Int32(minReplicas),
  1551  			MaxReplicas: 5,
  1552  			Metrics: []autoscaling.MetricSpec{{
  1553  				Type: autoscaling.ExternalMetricSourceType,
  1554  				External: &autoscaling.ExternalMetricSource{
  1555  					Metric: autoscaling.MetricIdentifier{
  1556  						Name:     "somemetric",
  1557  						Selector: metricLabelSelector,
  1558  					},
  1559  					Target: autoscaling.MetricTarget{
  1560  						Type:         autoscaling.AverageValueMetricType,
  1561  						AverageValue: resource.NewMilliQuantity(300, resource.DecimalSI),
  1562  					},
  1563  				},
  1564  			}},
  1565  		},
  1566  	}}
  1567  	return minReplicasCases
  1568  }
  1569  
  1570  func TestValidateHorizontalPodAutoscalerScaleToZeroEnabled(t *testing.T) {
  1571  	// Enable HPAScaleToZero feature gate.
  1572  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, true)()
  1573  
  1574  	zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
  1575  	for _, successCase := range zeroMinReplicasCases {
  1576  		if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
  1577  			t.Errorf("expected success: %v", errs)
  1578  		}
  1579  	}
  1580  }
  1581  
  1582  func TestValidateHorizontalPodAutoscalerScaleToZeroDisabled(t *testing.T) {
  1583  	// Disable HPAScaleToZero feature gate.
  1584  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, false)()
  1585  
  1586  	zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
  1587  	errorMsg := "must be greater than or equal to 1"
  1588  
  1589  	for _, errorCase := range zeroMinReplicasCases {
  1590  		errs := ValidateHorizontalPodAutoscaler(&errorCase)
  1591  		if len(errs) == 0 {
  1592  			t.Errorf("expected failure for %q", errorMsg)
  1593  		} else if !strings.Contains(errs[0].Error(), errorMsg) {
  1594  			t.Errorf("unexpected error: %q, expected: %q", errs[0], errorMsg)
  1595  		}
  1596  	}
  1597  
  1598  	nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
  1599  
  1600  	for _, successCase := range nonZeroMinReplicasCases {
  1601  		successCase.Spec.MinReplicas = utilpointer.Int32(1)
  1602  		if errs := ValidateHorizontalPodAutoscaler(&successCase); len(errs) != 0 {
  1603  			t.Errorf("expected success: %v", errs)
  1604  		}
  1605  	}
  1606  }
  1607  
  1608  func TestValidateHorizontalPodAutoscalerUpdateScaleToZeroEnabled(t *testing.T) {
  1609  	// Enable HPAScaleToZero feature gate.
  1610  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, true)()
  1611  
  1612  	zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
  1613  	nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
  1614  
  1615  	for i, zeroCase := range zeroMinReplicasCases {
  1616  		nonZeroCase := nonZeroMinReplicasCases[i]
  1617  
  1618  		if errs := ValidateHorizontalPodAutoscalerUpdate(&nonZeroCase, &zeroCase); len(errs) != 0 {
  1619  			t.Errorf("expected success: %v", errs)
  1620  		}
  1621  
  1622  		if errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &nonZeroCase); len(errs) != 0 {
  1623  			t.Errorf("expected success: %v", errs)
  1624  		}
  1625  	}
  1626  }
  1627  
  1628  func TestValidateHorizontalPodAutoscalerScaleToZeroUpdateDisabled(t *testing.T) {
  1629  	// Disable HPAScaleToZero feature gate.
  1630  	defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, false)()
  1631  
  1632  	zeroMinReplicasCases := prepareMinReplicasCases(t, 0)
  1633  	nonZeroMinReplicasCases := prepareMinReplicasCases(t, 1)
  1634  	errorMsg := "must be greater than or equal to 1"
  1635  
  1636  	for i, zeroCase := range zeroMinReplicasCases {
  1637  		nonZeroCase := nonZeroMinReplicasCases[i]
  1638  		errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &nonZeroCase)
  1639  
  1640  		if len(errs) == 0 {
  1641  			t.Errorf("expected failure for %q", errorMsg)
  1642  		} else if !strings.Contains(errs[0].Error(), errorMsg) {
  1643  			t.Errorf("unexpected error: %q, expected: %q", errs[0], errorMsg)
  1644  		}
  1645  
  1646  		if errs := ValidateHorizontalPodAutoscalerUpdate(&zeroCase, &zeroCase); len(errs) != 0 {
  1647  			t.Errorf("expected success: %v", errs)
  1648  		}
  1649  
  1650  		if errs := ValidateHorizontalPodAutoscalerUpdate(&nonZeroCase, &zeroCase); len(errs) != 0 {
  1651  			t.Errorf("expected success: %v", errs)
  1652  		}
  1653  	}
  1654  }
  1655  

View as plain text