k8s.io/kubernetes@v1.29.3/pkg/apis/node/validation/validation_test.go (about) 1 /* 2 Copyright 2018 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 "testing" 21 22 "k8s.io/apimachinery/pkg/api/resource" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/kubernetes/pkg/apis/core" 25 "k8s.io/kubernetes/pkg/apis/node" 26 utilpointer "k8s.io/utils/pointer" 27 28 "github.com/stretchr/testify/assert" 29 ) 30 31 func TestValidateRuntimeClass(t *testing.T) { 32 tests := []struct { 33 name string 34 rc node.RuntimeClass 35 expectError bool 36 }{{ 37 name: "invalid name", 38 expectError: true, 39 rc: node.RuntimeClass{ 40 ObjectMeta: metav1.ObjectMeta{Name: "&!@#"}, 41 Handler: "foo", 42 }, 43 }, { 44 name: "invalid Handler name", 45 expectError: true, 46 rc: node.RuntimeClass{ 47 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 48 Handler: "&@#$", 49 }, 50 }, { 51 name: "invalid empty RuntimeClass", 52 expectError: true, 53 rc: node.RuntimeClass{ 54 ObjectMeta: metav1.ObjectMeta{Name: "empty"}, 55 }, 56 }, { 57 name: "valid Handler", 58 expectError: false, 59 rc: node.RuntimeClass{ 60 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 61 Handler: "bar-baz", 62 }, 63 }} 64 65 for _, test := range tests { 66 t.Run(test.name, func(t *testing.T) { 67 errs := ValidateRuntimeClass(&test.rc) 68 if test.expectError { 69 assert.NotEmpty(t, errs) 70 } else { 71 assert.Empty(t, errs) 72 } 73 }) 74 } 75 } 76 77 func TestValidateRuntimeUpdate(t *testing.T) { 78 old := node.RuntimeClass{ 79 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 80 Handler: "bar", 81 } 82 tests := []struct { 83 name string 84 expectError bool 85 old, new node.RuntimeClass 86 }{{ 87 name: "valid metadata update", 88 old: old, 89 new: node.RuntimeClass{ 90 ObjectMeta: metav1.ObjectMeta{ 91 Name: "foo", 92 Labels: map[string]string{"foo": "bar"}, 93 }, 94 Handler: "bar", 95 }, 96 }, { 97 name: "invalid metadata update", 98 expectError: true, 99 old: old, 100 new: node.RuntimeClass{ 101 ObjectMeta: metav1.ObjectMeta{ 102 Name: "empty", 103 Namespace: "somethingelse", // immutable 104 }, 105 Handler: "bar", 106 }, 107 }, { 108 name: "invalid Handler update", 109 expectError: true, 110 old: old, 111 new: node.RuntimeClass{ 112 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 113 Handler: "somethingelse", 114 }, 115 }} 116 117 for _, test := range tests { 118 t.Run(test.name, func(t *testing.T) { 119 // So we don't need to write it in every test case... 120 test.old.ObjectMeta.ResourceVersion = "1" 121 test.new.ObjectMeta.ResourceVersion = "1" 122 123 errs := ValidateRuntimeClassUpdate(&test.new, &test.old) 124 if test.expectError { 125 assert.NotEmpty(t, errs) 126 } else { 127 assert.Empty(t, errs) 128 } 129 }) 130 } 131 } 132 133 func TestValidateOverhead(t *testing.T) { 134 successCase := []struct { 135 Name string 136 overhead *node.Overhead 137 }{{ 138 Name: "Overhead with valid cpu and memory resources", 139 overhead: &node.Overhead{ 140 PodFixed: core.ResourceList{ 141 core.ResourceName(core.ResourceCPU): resource.MustParse("10"), 142 core.ResourceName(core.ResourceMemory): resource.MustParse("10G"), 143 }, 144 }, 145 }} 146 147 for _, tc := range successCase { 148 rc := &node.RuntimeClass{ 149 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 150 Handler: "bar", 151 Overhead: tc.overhead, 152 } 153 if errs := ValidateRuntimeClass(rc); len(errs) != 0 { 154 t.Errorf("%q unexpected error: %v", tc.Name, errs) 155 } 156 } 157 158 errorCase := []struct { 159 Name string 160 overhead *node.Overhead 161 }{{ 162 Name: "Invalid Resources", 163 overhead: &node.Overhead{ 164 PodFixed: core.ResourceList{ 165 core.ResourceName("my.org"): resource.MustParse("10m"), 166 }, 167 }, 168 }} 169 for _, tc := range errorCase { 170 rc := &node.RuntimeClass{ 171 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 172 Handler: "bar", 173 Overhead: tc.overhead, 174 } 175 if errs := ValidateRuntimeClass(rc); len(errs) == 0 { 176 t.Errorf("%q expected error", tc.Name) 177 } 178 } 179 } 180 181 func TestValidateScheduling(t *testing.T) { 182 tests := []struct { 183 name string 184 scheduling *node.Scheduling 185 expectErrs int 186 }{{ 187 name: "valid scheduling", 188 scheduling: &node.Scheduling{ 189 NodeSelector: map[string]string{"valid": "yes"}, 190 Tolerations: []core.Toleration{{ 191 Key: "valid", 192 Operator: core.TolerationOpExists, 193 Effect: core.TaintEffectNoSchedule, 194 }}, 195 }, 196 }, { 197 name: "empty scheduling", 198 scheduling: &node.Scheduling{}, 199 }, { 200 name: "invalid nodeSelector", 201 scheduling: &node.Scheduling{ 202 NodeSelector: map[string]string{"not a valid key!!!": "nope"}, 203 }, 204 expectErrs: 1, 205 }, { 206 name: "invalid toleration", 207 scheduling: &node.Scheduling{ 208 Tolerations: []core.Toleration{{ 209 Key: "valid", 210 Operator: core.TolerationOpExists, 211 Effect: core.TaintEffectNoSchedule, 212 }, { 213 Key: "not a valid key!!!", 214 Operator: core.TolerationOpExists, 215 Effect: core.TaintEffectNoSchedule, 216 }}, 217 }, 218 expectErrs: 1, 219 }, { 220 name: "duplicate tolerations", 221 scheduling: &node.Scheduling{ 222 Tolerations: []core.Toleration{{ 223 Key: "valid", 224 Operator: core.TolerationOpExists, 225 Effect: core.TaintEffectNoExecute, 226 TolerationSeconds: utilpointer.Int64(5), 227 }, { 228 Key: "valid", 229 Operator: core.TolerationOpExists, 230 Effect: core.TaintEffectNoExecute, 231 TolerationSeconds: utilpointer.Int64(10), 232 }}, 233 }, 234 expectErrs: 1, 235 }, { 236 name: "invalid scheduling", 237 scheduling: &node.Scheduling{ 238 NodeSelector: map[string]string{"not a valid key!!!": "nope"}, 239 Tolerations: []core.Toleration{{ 240 Key: "valid", 241 Operator: core.TolerationOpExists, 242 Effect: core.TaintEffectNoSchedule, 243 }, { 244 Key: "not a valid toleration key!!!", 245 Operator: core.TolerationOpExists, 246 Effect: core.TaintEffectNoSchedule, 247 }}, 248 }, 249 expectErrs: 2, 250 }} 251 252 for _, test := range tests { 253 t.Run(test.name, func(t *testing.T) { 254 rc := &node.RuntimeClass{ 255 ObjectMeta: metav1.ObjectMeta{Name: "foo"}, 256 Handler: "bar", 257 Scheduling: test.scheduling, 258 } 259 assert.Len(t, ValidateRuntimeClass(rc), test.expectErrs) 260 }) 261 } 262 }