k8s.io/kubernetes@v1.29.3/pkg/apis/core/helper/helpers_test.go (about) 1 /* 2 Copyright 2015 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 helper 18 19 import ( 20 "testing" 21 22 "k8s.io/apimachinery/pkg/api/resource" 23 "k8s.io/kubernetes/pkg/apis/core" 24 ) 25 26 func TestSemantic(t *testing.T) { 27 table := []struct { 28 a, b interface{} 29 shouldEqual bool 30 }{ 31 {resource.MustParse("0"), resource.Quantity{}, true}, 32 {resource.Quantity{}, resource.MustParse("0"), true}, 33 {resource.Quantity{}, resource.MustParse("1m"), false}, 34 { 35 resource.NewQuantity(5, resource.BinarySI), 36 resource.NewQuantity(5, resource.DecimalSI), 37 true, 38 }, 39 {resource.MustParse("2m"), resource.MustParse("1m"), false}, 40 } 41 42 for index, item := range table { 43 if e, a := item.shouldEqual, Semantic.DeepEqual(item.a, item.b); e != a { 44 t.Errorf("case[%d], expected %v, got %v.", index, e, a) 45 } 46 } 47 } 48 49 func TestIsStandardResource(t *testing.T) { 50 testCases := []struct { 51 input string 52 output bool 53 }{ 54 {"cpu", true}, 55 {"memory", true}, 56 {"disk", false}, 57 {"blah", false}, 58 {"x.y.z", false}, 59 {"hugepages-2Mi", true}, 60 {"requests.hugepages-2Mi", true}, 61 } 62 for i, tc := range testCases { 63 if IsStandardResourceName(core.ResourceName(tc.input)) != tc.output { 64 t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output) 65 } 66 } 67 } 68 69 func TestIsStandardContainerResource(t *testing.T) { 70 testCases := []struct { 71 input string 72 output bool 73 }{ 74 {"cpu", true}, 75 {"memory", true}, 76 {"disk", false}, 77 {"hugepages-2Mi", true}, 78 } 79 for i, tc := range testCases { 80 if IsStandardContainerResourceName(core.ResourceName(tc.input)) != tc.output { 81 t.Errorf("case[%d], input: %s, expected: %t, got: %t", i, tc.input, tc.output, !tc.output) 82 } 83 } 84 } 85 86 func TestGetAccessModesFromString(t *testing.T) { 87 modes := GetAccessModesFromString("ROX") 88 if !ContainsAccessMode(modes, core.ReadOnlyMany) { 89 t.Errorf("Expected mode %s, but got %+v", core.ReadOnlyMany, modes) 90 } 91 92 modes = GetAccessModesFromString("ROX,RWX") 93 if !ContainsAccessMode(modes, core.ReadOnlyMany) { 94 t.Errorf("Expected mode %s, but got %+v", core.ReadOnlyMany, modes) 95 } 96 if !ContainsAccessMode(modes, core.ReadWriteMany) { 97 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteMany, modes) 98 } 99 100 modes = GetAccessModesFromString("RWO,ROX,RWX") 101 if !ContainsAccessMode(modes, core.ReadWriteOnce) { 102 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteOnce, modes) 103 } 104 if !ContainsAccessMode(modes, core.ReadOnlyMany) { 105 t.Errorf("Expected mode %s, but got %+v", core.ReadOnlyMany, modes) 106 } 107 if !ContainsAccessMode(modes, core.ReadWriteMany) { 108 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteMany, modes) 109 } 110 111 modes = GetAccessModesFromString("RWO,ROX,RWX,RWOP") 112 if !ContainsAccessMode(modes, core.ReadWriteOnce) { 113 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteOnce, modes) 114 } 115 if !ContainsAccessMode(modes, core.ReadOnlyMany) { 116 t.Errorf("Expected mode %s, but got %+v", core.ReadOnlyMany, modes) 117 } 118 if !ContainsAccessMode(modes, core.ReadWriteMany) { 119 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteMany, modes) 120 } 121 if !ContainsAccessMode(modes, core.ReadWriteOncePod) { 122 t.Errorf("Expected mode %s, but got %+v", core.ReadWriteOncePod, modes) 123 } 124 } 125 126 func TestRemoveDuplicateAccessModes(t *testing.T) { 127 modes := []core.PersistentVolumeAccessMode{ 128 core.ReadWriteOnce, core.ReadOnlyMany, core.ReadOnlyMany, core.ReadOnlyMany, 129 } 130 modes = removeDuplicateAccessModes(modes) 131 if len(modes) != 2 { 132 t.Errorf("Expected 2 distinct modes in set but found %v", len(modes)) 133 } 134 } 135 136 func TestIsHugePageResourceName(t *testing.T) { 137 testCases := []struct { 138 name core.ResourceName 139 result bool 140 }{ 141 { 142 name: core.ResourceName("hugepages-2Mi"), 143 result: true, 144 }, 145 { 146 name: core.ResourceName("hugepages-1Gi"), 147 result: true, 148 }, 149 { 150 name: core.ResourceName("cpu"), 151 result: false, 152 }, 153 { 154 name: core.ResourceName("memory"), 155 result: false, 156 }, 157 } 158 for _, testCase := range testCases { 159 if testCase.result != IsHugePageResourceName(testCase.name) { 160 t.Errorf("resource: %v expected result: %v", testCase.name, testCase.result) 161 } 162 } 163 } 164 165 func TestIsHugePageResourceValueDivisible(t *testing.T) { 166 testCases := []struct { 167 name core.ResourceName 168 quantity resource.Quantity 169 result bool 170 }{ 171 { 172 name: core.ResourceName("hugepages-2Mi"), 173 quantity: resource.MustParse("4Mi"), 174 result: true, 175 }, 176 { 177 name: core.ResourceName("hugepages-2Mi"), 178 quantity: resource.MustParse("5Mi"), 179 result: false, 180 }, 181 { 182 name: core.ResourceName("hugepages-1Gi"), 183 quantity: resource.MustParse("2Gi"), 184 result: true, 185 }, 186 { 187 name: core.ResourceName("hugepages-1Gi"), 188 quantity: resource.MustParse("2.1Gi"), 189 result: false, 190 }, 191 { 192 name: core.ResourceName("hugepages-1Mi"), 193 quantity: resource.MustParse("2.1Mi"), 194 result: false, 195 }, 196 { 197 name: core.ResourceName("hugepages-64Ki"), 198 quantity: resource.MustParse("128Ki"), 199 result: true, 200 }, 201 { 202 name: core.ResourceName("hugepages-"), 203 quantity: resource.MustParse("128Ki"), 204 result: false, 205 }, 206 { 207 name: core.ResourceName("hugepages"), 208 quantity: resource.MustParse("128Ki"), 209 result: false, 210 }, 211 } 212 for _, testCase := range testCases { 213 if testCase.result != IsHugePageResourceValueDivisible(testCase.name, testCase.quantity) { 214 t.Errorf("resource: %v storage:%v expected result: %v", testCase.name, testCase.quantity, testCase.result) 215 } 216 } 217 } 218 219 func TestHugePageResourceName(t *testing.T) { 220 testCases := []struct { 221 pageSize resource.Quantity 222 name core.ResourceName 223 }{ 224 { 225 pageSize: resource.MustParse("2Mi"), 226 name: core.ResourceName("hugepages-2Mi"), 227 }, 228 { 229 pageSize: resource.MustParse("1Gi"), 230 name: core.ResourceName("hugepages-1Gi"), 231 }, 232 { 233 // verify we do not regress our canonical representation 234 pageSize: *resource.NewQuantity(int64(2097152), resource.BinarySI), 235 name: core.ResourceName("hugepages-2Mi"), 236 }, 237 } 238 for _, testCase := range testCases { 239 if result := HugePageResourceName(testCase.pageSize); result != testCase.name { 240 t.Errorf("pageSize: %v, expected: %v, but got: %v", testCase.pageSize.String(), testCase.name, result.String()) 241 } 242 } 243 } 244 245 func TestHugePageSizeFromResourceName(t *testing.T) { 246 testCases := []struct { 247 name core.ResourceName 248 expectErr bool 249 pageSize resource.Quantity 250 }{ 251 { 252 name: core.ResourceName("hugepages-2Mi"), 253 pageSize: resource.MustParse("2Mi"), 254 expectErr: false, 255 }, 256 { 257 name: core.ResourceName("hugepages-1Gi"), 258 pageSize: resource.MustParse("1Gi"), 259 expectErr: false, 260 }, 261 { 262 name: core.ResourceName("hugepages-bad"), 263 expectErr: true, 264 }, 265 } 266 for _, testCase := range testCases { 267 value, err := HugePageSizeFromResourceName(testCase.name) 268 if testCase.expectErr && err == nil { 269 t.Errorf("Expected an error for %v", testCase.name) 270 } else if !testCase.expectErr && err != nil { 271 t.Errorf("Unexpected error for %v, got %v", testCase.name, err) 272 } else if testCase.pageSize.Value() != value.Value() { 273 t.Errorf("Unexpected pageSize for resource %v got %v", testCase.name, value.String()) 274 } 275 } 276 } 277 278 func TestIsOvercommitAllowed(t *testing.T) { 279 testCases := []struct { 280 name core.ResourceName 281 allowed bool 282 }{ 283 { 284 name: core.ResourceCPU, 285 allowed: true, 286 }, 287 { 288 name: core.ResourceMemory, 289 allowed: true, 290 }, 291 { 292 name: HugePageResourceName(resource.MustParse("2Mi")), 293 allowed: false, 294 }, 295 } 296 for _, testCase := range testCases { 297 if testCase.allowed != IsOvercommitAllowed(testCase.name) { 298 t.Errorf("Unexpected result for %v", testCase.name) 299 } 300 } 301 } 302 303 func TestIsServiceIPSet(t *testing.T) { 304 testCases := []struct { 305 input core.ServiceSpec 306 output bool 307 name string 308 }{ 309 { 310 name: "nil cluster ip", 311 input: core.ServiceSpec{ 312 ClusterIPs: nil, 313 }, 314 315 output: false, 316 }, 317 { 318 name: "headless service", 319 input: core.ServiceSpec{ 320 ClusterIP: "None", 321 ClusterIPs: []string{"None"}, 322 }, 323 output: false, 324 }, 325 // true cases 326 { 327 name: "one ipv4", 328 input: core.ServiceSpec{ 329 ClusterIP: "1.2.3.4", 330 ClusterIPs: []string{"1.2.3.4"}, 331 }, 332 output: true, 333 }, 334 { 335 name: "one ipv6", 336 input: core.ServiceSpec{ 337 ClusterIP: "2001::1", 338 ClusterIPs: []string{"2001::1"}, 339 }, 340 output: true, 341 }, 342 { 343 name: "v4, v6", 344 input: core.ServiceSpec{ 345 ClusterIP: "1.2.3.4", 346 ClusterIPs: []string{"1.2.3.4", "2001::1"}, 347 }, 348 output: true, 349 }, 350 { 351 name: "v6, v4", 352 input: core.ServiceSpec{ 353 ClusterIP: "2001::1", 354 ClusterIPs: []string{"2001::1", "1.2.3.4"}, 355 }, 356 357 output: true, 358 }, 359 } 360 361 for _, tc := range testCases { 362 t.Run(tc.name, func(t *testing.T) { 363 s := core.Service{ 364 Spec: tc.input, 365 } 366 if IsServiceIPSet(&s) != tc.output { 367 t.Errorf("case, input: %v, expected: %v, got: %v", tc.input, tc.output, !tc.output) 368 } 369 }) 370 } 371 }