...

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

Documentation: k8s.io/kubernetes/pkg/apis/policy/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  	"fmt"
    21  	"testing"
    22  	"time"
    23  
    24  	policyv1beta1 "k8s.io/api/policy/v1beta1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime/schema"
    27  	"k8s.io/apimachinery/pkg/util/intstr"
    28  	"k8s.io/apimachinery/pkg/util/validation/field"
    29  	"k8s.io/kubernetes/pkg/apis/policy"
    30  )
    31  
    32  func TestValidatePodDisruptionBudgetSpec(t *testing.T) {
    33  	minAvailable := intstr.FromString("0%")
    34  	maxUnavailable := intstr.FromString("10%")
    35  
    36  	spec := policy.PodDisruptionBudgetSpec{
    37  		MinAvailable:   &minAvailable,
    38  		MaxUnavailable: &maxUnavailable,
    39  	}
    40  	errs := ValidatePodDisruptionBudgetSpec(spec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
    41  	if len(errs) == 0 {
    42  		t.Errorf("unexpected success for %v", spec)
    43  	}
    44  }
    45  
    46  func TestValidateMinAvailablePodDisruptionBudgetSpec(t *testing.T) {
    47  	successCases := []intstr.IntOrString{
    48  		intstr.FromString("0%"),
    49  		intstr.FromString("1%"),
    50  		intstr.FromString("100%"),
    51  		intstr.FromInt32(0),
    52  		intstr.FromInt32(1),
    53  		intstr.FromInt32(100),
    54  	}
    55  	for _, c := range successCases {
    56  		spec := policy.PodDisruptionBudgetSpec{
    57  			MinAvailable: &c,
    58  		}
    59  		errs := ValidatePodDisruptionBudgetSpec(spec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
    60  		if len(errs) != 0 {
    61  			t.Errorf("unexpected failure %v for %v", errs, spec)
    62  		}
    63  	}
    64  
    65  	failureCases := []intstr.IntOrString{
    66  		intstr.FromString("1.1%"),
    67  		intstr.FromString("nope"),
    68  		intstr.FromString("-1%"),
    69  		intstr.FromString("101%"),
    70  		intstr.FromInt32(-1),
    71  	}
    72  	for _, c := range failureCases {
    73  		spec := policy.PodDisruptionBudgetSpec{
    74  			MinAvailable: &c,
    75  		}
    76  		errs := ValidatePodDisruptionBudgetSpec(spec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
    77  		if len(errs) == 0 {
    78  			t.Errorf("unexpected success for %v", spec)
    79  		}
    80  	}
    81  }
    82  
    83  func TestValidateMinAvailablePodAndMaxUnavailableDisruptionBudgetSpec(t *testing.T) {
    84  	c1 := intstr.FromString("10%")
    85  	c2 := intstr.FromInt32(1)
    86  
    87  	spec := policy.PodDisruptionBudgetSpec{
    88  		MinAvailable:   &c1,
    89  		MaxUnavailable: &c2,
    90  	}
    91  	errs := ValidatePodDisruptionBudgetSpec(spec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
    92  	if len(errs) == 0 {
    93  		t.Errorf("unexpected success for %v", spec)
    94  	}
    95  }
    96  
    97  func TestValidateUnhealthyPodEvictionPolicyDisruptionBudgetSpec(t *testing.T) {
    98  	c1 := intstr.FromString("10%")
    99  	alwaysAllowPolicy := policy.AlwaysAllow
   100  	invalidPolicy := policy.UnhealthyPodEvictionPolicyType("Invalid")
   101  
   102  	testCases := []struct {
   103  		name      string
   104  		pdbSpec   policy.PodDisruptionBudgetSpec
   105  		expectErr bool
   106  	}{{
   107  		name: "valid nil UnhealthyPodEvictionPolicy",
   108  		pdbSpec: policy.PodDisruptionBudgetSpec{
   109  			MinAvailable:               &c1,
   110  			UnhealthyPodEvictionPolicy: nil,
   111  		},
   112  		expectErr: false,
   113  	}, {
   114  		name: "valid UnhealthyPodEvictionPolicy",
   115  		pdbSpec: policy.PodDisruptionBudgetSpec{
   116  			MinAvailable:               &c1,
   117  			UnhealthyPodEvictionPolicy: &alwaysAllowPolicy,
   118  		},
   119  		expectErr: false,
   120  	}, {
   121  		name: "empty UnhealthyPodEvictionPolicy",
   122  		pdbSpec: policy.PodDisruptionBudgetSpec{
   123  			MinAvailable:               &c1,
   124  			UnhealthyPodEvictionPolicy: new(policy.UnhealthyPodEvictionPolicyType),
   125  		},
   126  		expectErr: true,
   127  	}, {
   128  		name: "invalid UnhealthyPodEvictionPolicy",
   129  		pdbSpec: policy.PodDisruptionBudgetSpec{
   130  			MinAvailable:               &c1,
   131  			UnhealthyPodEvictionPolicy: &invalidPolicy,
   132  		},
   133  		expectErr: true,
   134  	}}
   135  
   136  	for _, tc := range testCases {
   137  		t.Run(tc.name, func(t *testing.T) {
   138  			errs := ValidatePodDisruptionBudgetSpec(tc.pdbSpec, PodDisruptionBudgetValidationOptions{true}, field.NewPath("foo"))
   139  			if len(errs) == 0 && tc.expectErr {
   140  				t.Errorf("unexpected success for %v", tc.pdbSpec)
   141  			}
   142  			if len(errs) != 0 && !tc.expectErr {
   143  				t.Errorf("unexpected failure for %v", tc.pdbSpec)
   144  			}
   145  		})
   146  	}
   147  }
   148  
   149  func TestValidatePodDisruptionBudgetStatus(t *testing.T) {
   150  	const expectNoErrors = false
   151  	const expectErrors = true
   152  	testCases := []struct {
   153  		name                string
   154  		pdbStatus           policy.PodDisruptionBudgetStatus
   155  		expectErrForVersion map[schema.GroupVersion]bool
   156  	}{{
   157  		name: "DisruptionsAllowed: 10",
   158  		pdbStatus: policy.PodDisruptionBudgetStatus{
   159  			DisruptionsAllowed: 10,
   160  		},
   161  		expectErrForVersion: map[schema.GroupVersion]bool{
   162  			policy.SchemeGroupVersion:        expectNoErrors,
   163  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   164  		},
   165  	}, {
   166  		name: "CurrentHealthy: 5",
   167  		pdbStatus: policy.PodDisruptionBudgetStatus{
   168  			CurrentHealthy: 5,
   169  		},
   170  		expectErrForVersion: map[schema.GroupVersion]bool{
   171  			policy.SchemeGroupVersion:        expectNoErrors,
   172  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   173  		},
   174  	}, {
   175  		name: "DesiredHealthy: 3",
   176  		pdbStatus: policy.PodDisruptionBudgetStatus{
   177  			DesiredHealthy: 3,
   178  		},
   179  		expectErrForVersion: map[schema.GroupVersion]bool{
   180  			policy.SchemeGroupVersion:        expectNoErrors,
   181  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   182  		},
   183  	}, {
   184  		name: "ExpectedPods: 2",
   185  		pdbStatus: policy.PodDisruptionBudgetStatus{
   186  			ExpectedPods: 2,
   187  		},
   188  		expectErrForVersion: map[schema.GroupVersion]bool{
   189  			policy.SchemeGroupVersion:        expectNoErrors,
   190  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   191  		},
   192  	}, {
   193  		name: "DisruptionsAllowed: -10",
   194  		pdbStatus: policy.PodDisruptionBudgetStatus{
   195  			DisruptionsAllowed: -10,
   196  		},
   197  		expectErrForVersion: map[schema.GroupVersion]bool{
   198  			policy.SchemeGroupVersion:        expectErrors,
   199  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   200  		},
   201  	}, {
   202  		name: "CurrentHealthy: -5",
   203  		pdbStatus: policy.PodDisruptionBudgetStatus{
   204  			CurrentHealthy: -5,
   205  		},
   206  		expectErrForVersion: map[schema.GroupVersion]bool{
   207  			policy.SchemeGroupVersion:        expectErrors,
   208  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   209  		},
   210  	}, {
   211  		name: "DesiredHealthy: -3",
   212  		pdbStatus: policy.PodDisruptionBudgetStatus{
   213  			DesiredHealthy: -3,
   214  		},
   215  		expectErrForVersion: map[schema.GroupVersion]bool{
   216  			policy.SchemeGroupVersion:        expectErrors,
   217  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   218  		},
   219  	}, {
   220  		name: "ExpectedPods: -2",
   221  		pdbStatus: policy.PodDisruptionBudgetStatus{
   222  			ExpectedPods: -2,
   223  		},
   224  		expectErrForVersion: map[schema.GroupVersion]bool{
   225  			policy.SchemeGroupVersion:        expectErrors,
   226  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   227  		},
   228  	}, {
   229  		name: "Conditions valid",
   230  		pdbStatus: policy.PodDisruptionBudgetStatus{
   231  			Conditions: []metav1.Condition{{
   232  				Type:   policyv1beta1.DisruptionAllowedCondition,
   233  				Status: metav1.ConditionTrue,
   234  				LastTransitionTime: metav1.Time{
   235  					Time: time.Now().Add(-5 * time.Minute),
   236  				},
   237  				Reason:             policyv1beta1.SufficientPodsReason,
   238  				Message:            "message",
   239  				ObservedGeneration: 3,
   240  			}},
   241  		},
   242  		expectErrForVersion: map[schema.GroupVersion]bool{
   243  			policy.SchemeGroupVersion:        expectNoErrors,
   244  			policyv1beta1.SchemeGroupVersion: expectNoErrors,
   245  		},
   246  	}, {
   247  		name: "Conditions not valid",
   248  		pdbStatus: policy.PodDisruptionBudgetStatus{
   249  			Conditions: []metav1.Condition{{
   250  				Type:   policyv1beta1.DisruptionAllowedCondition,
   251  				Status: metav1.ConditionTrue,
   252  			}, {
   253  				Type:   policyv1beta1.DisruptionAllowedCondition,
   254  				Status: metav1.ConditionFalse,
   255  			}},
   256  		},
   257  		expectErrForVersion: map[schema.GroupVersion]bool{
   258  			policy.SchemeGroupVersion:        expectErrors,
   259  			policyv1beta1.SchemeGroupVersion: expectErrors,
   260  		},
   261  	}}
   262  
   263  	for _, tc := range testCases {
   264  		for apiVersion, expectErrors := range tc.expectErrForVersion {
   265  			t.Run(fmt.Sprintf("apiVersion: %s, %s", apiVersion.String(), tc.name), func(t *testing.T) {
   266  				errors := ValidatePodDisruptionBudgetStatusUpdate(tc.pdbStatus, policy.PodDisruptionBudgetStatus{},
   267  					field.NewPath("status"), apiVersion)
   268  				errCount := len(errors)
   269  
   270  				if errCount > 0 && !expectErrors {
   271  					t.Errorf("unexpected failure %v for %v", errors, tc.pdbStatus)
   272  				}
   273  
   274  				if errCount == 0 && expectErrors {
   275  					t.Errorf("expected errors but didn't one for %v", tc.pdbStatus)
   276  				}
   277  			})
   278  		}
   279  	}
   280  }
   281  
   282  func TestIsValidSysctlPattern(t *testing.T) {
   283  	valid := []string{
   284  		"a.b.c.d",
   285  		"a",
   286  		"a_b",
   287  		"a-b",
   288  		"abc",
   289  		"abc.def",
   290  		"*",
   291  		"a.*",
   292  		"*",
   293  		"abc*",
   294  		"a.abc*",
   295  		"a.b.*",
   296  		"a/b/c/d",
   297  		"a/*",
   298  		"a/b/*",
   299  		"a.b/c*",
   300  		"a.b/c.d",
   301  		"a/b.c/d",
   302  	}
   303  	invalid := []string{
   304  		"",
   305  		"รค",
   306  		"a_",
   307  		"_",
   308  		"_a",
   309  		"_a._b",
   310  		"__",
   311  		"-",
   312  		".",
   313  		"a.",
   314  		".a",
   315  		"a.b.",
   316  		"a*.b",
   317  		"a*b",
   318  		"*a",
   319  		"Abc",
   320  		"/",
   321  		"a/",
   322  		"/a",
   323  		"a*/b",
   324  		func(n int) string {
   325  			x := make([]byte, n)
   326  			for i := range x {
   327  				x[i] = byte('a')
   328  			}
   329  			return string(x)
   330  		}(256),
   331  	}
   332  	for _, s := range valid {
   333  		if !IsValidSysctlPattern(s) {
   334  			t.Errorf("%q expected to be a valid sysctl pattern", s)
   335  		}
   336  	}
   337  	for _, s := range invalid {
   338  		if IsValidSysctlPattern(s) {
   339  			t.Errorf("%q expected to be an invalid sysctl pattern", s)
   340  		}
   341  	}
   342  }
   343  

View as plain text