k8s.io/apiserver@v0.31.1/pkg/quota/v1/resources_test.go (about) 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 v1 18 19 import ( 20 "reflect" 21 "testing" 22 23 corev1 "k8s.io/api/core/v1" 24 "k8s.io/apimachinery/pkg/api/resource" 25 ) 26 27 func TestEquals(t *testing.T) { 28 testCases := map[string]struct { 29 a corev1.ResourceList 30 b corev1.ResourceList 31 expected bool 32 }{ 33 "isEqual": { 34 a: corev1.ResourceList{}, 35 b: corev1.ResourceList{}, 36 expected: true, 37 }, 38 "isEqualWithKeys": { 39 a: corev1.ResourceList{ 40 corev1.ResourceCPU: resource.MustParse("100m"), 41 corev1.ResourceMemory: resource.MustParse("1Gi"), 42 }, 43 b: corev1.ResourceList{ 44 corev1.ResourceCPU: resource.MustParse("100m"), 45 corev1.ResourceMemory: resource.MustParse("1Gi"), 46 }, 47 expected: true, 48 }, 49 "isNotEqualSameKeys": { 50 a: corev1.ResourceList{ 51 corev1.ResourceCPU: resource.MustParse("200m"), 52 corev1.ResourceMemory: resource.MustParse("1Gi"), 53 }, 54 b: corev1.ResourceList{ 55 corev1.ResourceCPU: resource.MustParse("100m"), 56 corev1.ResourceMemory: resource.MustParse("1Gi"), 57 }, 58 expected: false, 59 }, 60 "isNotEqualDiffKeys": { 61 a: corev1.ResourceList{ 62 corev1.ResourceCPU: resource.MustParse("100m"), 63 corev1.ResourceMemory: resource.MustParse("1Gi"), 64 }, 65 b: corev1.ResourceList{ 66 corev1.ResourceCPU: resource.MustParse("100m"), 67 corev1.ResourceMemory: resource.MustParse("1Gi"), 68 corev1.ResourcePods: resource.MustParse("1"), 69 }, 70 expected: false, 71 }, 72 } 73 for testName, testCase := range testCases { 74 if result := Equals(testCase.a, testCase.b); result != testCase.expected { 75 t.Errorf("%s expected: %v, actual: %v, a=%v, b=%v", testName, testCase.expected, result, testCase.a, testCase.b) 76 } 77 } 78 } 79 80 func TestLessThanOrEqual(t *testing.T) { 81 testCases := map[string]struct { 82 a corev1.ResourceList 83 b corev1.ResourceList 84 expected bool 85 out []corev1.ResourceName 86 }{ 87 "isEmpty": { 88 a: corev1.ResourceList{}, 89 b: corev1.ResourceList{}, 90 expected: true, 91 out: []corev1.ResourceName{}, 92 }, 93 "isEqual": { 94 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 95 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 96 expected: true, 97 out: []corev1.ResourceName{}, 98 }, 99 "isLessThan": { 100 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 101 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")}, 102 expected: true, 103 out: []corev1.ResourceName{}, 104 }, 105 "isGreaterThan": { 106 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")}, 107 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 108 expected: false, 109 out: []corev1.ResourceName{corev1.ResourceCPU}, 110 }, 111 } 112 for testName, testCase := range testCases { 113 if result, out := LessThanOrEqual(testCase.a, testCase.b); result != testCase.expected && !reflect.DeepEqual(out, testCase.out) { 114 t.Errorf("%s expected: %v/%v, actual: %v/%v", testName, testCase.expected, testCase.out, result, out) 115 } 116 } 117 } 118 119 func TestMax(t *testing.T) { 120 testCases := map[string]struct { 121 a corev1.ResourceList 122 b corev1.ResourceList 123 expected corev1.ResourceList 124 }{ 125 "noKeys": { 126 a: corev1.ResourceList{}, 127 b: corev1.ResourceList{}, 128 expected: corev1.ResourceList{}, 129 }, 130 "toEmpty": { 131 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 132 b: corev1.ResourceList{}, 133 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 134 }, 135 "matching": { 136 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 137 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")}, 138 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")}, 139 }, 140 "matching(reverse)": { 141 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")}, 142 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 143 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("150m")}, 144 }, 145 "matching-equal": { 146 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 147 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 148 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 149 }, 150 } 151 for testName, testCase := range testCases { 152 sum := Max(testCase.a, testCase.b) 153 if result := Equals(testCase.expected, sum); !result { 154 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum) 155 } 156 } 157 } 158 159 func TestAdd(t *testing.T) { 160 testCases := map[string]struct { 161 a corev1.ResourceList 162 b corev1.ResourceList 163 expected corev1.ResourceList 164 }{ 165 "noKeys": { 166 a: corev1.ResourceList{}, 167 b: corev1.ResourceList{}, 168 expected: corev1.ResourceList{}, 169 }, 170 "toEmpty": { 171 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 172 b: corev1.ResourceList{}, 173 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 174 }, 175 "matching": { 176 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 177 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 178 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")}, 179 }, 180 } 181 for testName, testCase := range testCases { 182 sum := Add(testCase.a, testCase.b) 183 if result := Equals(testCase.expected, sum); !result { 184 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sum) 185 } 186 } 187 } 188 189 func TestSubtract(t *testing.T) { 190 testCases := map[string]struct { 191 a corev1.ResourceList 192 b corev1.ResourceList 193 expected corev1.ResourceList 194 }{ 195 "noKeys": { 196 a: corev1.ResourceList{}, 197 b: corev1.ResourceList{}, 198 expected: corev1.ResourceList{}, 199 }, 200 "value-empty": { 201 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 202 b: corev1.ResourceList{}, 203 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 204 }, 205 "empty-value": { 206 a: corev1.ResourceList{}, 207 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 208 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("-100m")}, 209 }, 210 "value-value": { 211 a: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m")}, 212 b: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 213 expected: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m")}, 214 }, 215 } 216 for testName, testCase := range testCases { 217 sub := Subtract(testCase.a, testCase.b) 218 if result := Equals(testCase.expected, sub); !result { 219 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, sub) 220 } 221 } 222 } 223 224 func TestResourceNames(t *testing.T) { 225 testCases := map[string]struct { 226 a corev1.ResourceList 227 expected []corev1.ResourceName 228 }{ 229 "empty": { 230 a: corev1.ResourceList{}, 231 expected: []corev1.ResourceName{}, 232 }, 233 "values": { 234 a: corev1.ResourceList{ 235 corev1.ResourceCPU: resource.MustParse("100m"), 236 corev1.ResourceMemory: resource.MustParse("1Gi"), 237 }, 238 expected: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU}, 239 }, 240 } 241 for testName, testCase := range testCases { 242 actualSet := ToSet(ResourceNames(testCase.a)) 243 expectedSet := ToSet(testCase.expected) 244 if !actualSet.Equal(expectedSet) { 245 t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet) 246 } 247 } 248 } 249 250 func TestContains(t *testing.T) { 251 testCases := map[string]struct { 252 a []corev1.ResourceName 253 b corev1.ResourceName 254 expected bool 255 }{ 256 "does-not-contain": { 257 a: []corev1.ResourceName{corev1.ResourceMemory}, 258 b: corev1.ResourceCPU, 259 expected: false, 260 }, 261 "does-contain": { 262 a: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceCPU}, 263 b: corev1.ResourceCPU, 264 expected: true, 265 }, 266 } 267 for testName, testCase := range testCases { 268 if actual := Contains(testCase.a, testCase.b); actual != testCase.expected { 269 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual) 270 } 271 } 272 } 273 274 func TestContainsPrefix(t *testing.T) { 275 testCases := map[string]struct { 276 a []string 277 b corev1.ResourceName 278 expected bool 279 }{ 280 "does-not-contain": { 281 a: []string{corev1.ResourceHugePagesPrefix}, 282 b: corev1.ResourceCPU, 283 expected: false, 284 }, 285 "does-contain": { 286 a: []string{corev1.ResourceHugePagesPrefix}, 287 b: corev1.ResourceName(corev1.ResourceHugePagesPrefix + "2Mi"), 288 expected: true, 289 }, 290 } 291 for testName, testCase := range testCases { 292 if actual := ContainsPrefix(testCase.a, testCase.b); actual != testCase.expected { 293 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, actual) 294 } 295 } 296 } 297 298 func TestIsZero(t *testing.T) { 299 testCases := map[string]struct { 300 a corev1.ResourceList 301 expected bool 302 }{ 303 "empty": { 304 a: corev1.ResourceList{}, 305 expected: true, 306 }, 307 "zero": { 308 a: corev1.ResourceList{ 309 corev1.ResourceCPU: resource.MustParse("0"), 310 corev1.ResourceMemory: resource.MustParse("0"), 311 }, 312 expected: true, 313 }, 314 "non-zero": { 315 a: corev1.ResourceList{ 316 corev1.ResourceCPU: resource.MustParse("200m"), 317 corev1.ResourceMemory: resource.MustParse("1Gi"), 318 }, 319 expected: false, 320 }, 321 } 322 for testName, testCase := range testCases { 323 if result := IsZero(testCase.a); result != testCase.expected { 324 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result) 325 } 326 } 327 } 328 329 func TestRemoveZeros(t *testing.T) { 330 testCases := map[string]struct { 331 a corev1.ResourceList 332 expected corev1.ResourceList 333 }{ 334 "empty": { 335 a: corev1.ResourceList{}, 336 expected: corev1.ResourceList{}, 337 }, 338 "all-zeros": { 339 a: corev1.ResourceList{ 340 corev1.ResourceCPU: resource.MustParse("0"), 341 corev1.ResourceMemory: resource.MustParse("0"), 342 }, 343 expected: corev1.ResourceList{}, 344 }, 345 "some-zeros": { 346 a: corev1.ResourceList{ 347 corev1.ResourceCPU: resource.MustParse("0"), 348 corev1.ResourceMemory: resource.MustParse("0"), 349 corev1.ResourceStorage: resource.MustParse("100Gi"), 350 }, 351 expected: corev1.ResourceList{ 352 corev1.ResourceStorage: resource.MustParse("100Gi"), 353 }, 354 }, 355 "non-zero": { 356 a: corev1.ResourceList{ 357 corev1.ResourceCPU: resource.MustParse("200m"), 358 corev1.ResourceMemory: resource.MustParse("1Gi"), 359 }, 360 expected: corev1.ResourceList{ 361 corev1.ResourceCPU: resource.MustParse("200m"), 362 corev1.ResourceMemory: resource.MustParse("1Gi"), 363 }, 364 }, 365 } 366 for testName, testCase := range testCases { 367 if result := RemoveZeros(testCase.a); !Equals(result, testCase.expected) { 368 t.Errorf("%s expected: %v, actual: %v", testName, testCase.expected, result) 369 } 370 } 371 } 372 373 func TestIsNegative(t *testing.T) { 374 testCases := map[string]struct { 375 a corev1.ResourceList 376 expected []corev1.ResourceName 377 }{ 378 "empty": { 379 a: corev1.ResourceList{}, 380 expected: []corev1.ResourceName{}, 381 }, 382 "some-negative": { 383 a: corev1.ResourceList{ 384 corev1.ResourceCPU: resource.MustParse("-10"), 385 corev1.ResourceMemory: resource.MustParse("0"), 386 }, 387 expected: []corev1.ResourceName{corev1.ResourceCPU}, 388 }, 389 "all-negative": { 390 a: corev1.ResourceList{ 391 corev1.ResourceCPU: resource.MustParse("-200m"), 392 corev1.ResourceMemory: resource.MustParse("-1Gi"), 393 }, 394 expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 395 }, 396 } 397 for testName, testCase := range testCases { 398 actual := IsNegative(testCase.a) 399 actualSet := ToSet(actual) 400 expectedSet := ToSet(testCase.expected) 401 if !actualSet.Equal(expectedSet) { 402 t.Errorf("%s expected: %v, actual: %v", testName, expectedSet, actualSet) 403 } 404 } 405 } 406 407 func TestIntersection(t *testing.T) { 408 testCases := map[string]struct { 409 a []corev1.ResourceName 410 b []corev1.ResourceName 411 expected []corev1.ResourceName 412 }{ 413 "empty": { 414 a: []corev1.ResourceName{}, 415 b: []corev1.ResourceName{}, 416 expected: []corev1.ResourceName{}, 417 }, 418 "equal": { 419 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 420 b: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 421 expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 422 }, 423 "a has extra": { 424 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 425 b: []corev1.ResourceName{corev1.ResourceCPU}, 426 expected: []corev1.ResourceName{corev1.ResourceCPU}, 427 }, 428 "b has extra": { 429 a: []corev1.ResourceName{corev1.ResourceCPU}, 430 b: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 431 expected: []corev1.ResourceName{corev1.ResourceCPU}, 432 }, 433 "dedupes": { 434 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceCPU, corev1.ResourceMemory, corev1.ResourceMemory}, 435 b: []corev1.ResourceName{corev1.ResourceCPU}, 436 expected: []corev1.ResourceName{corev1.ResourceCPU}, 437 }, 438 "sorts": { 439 a: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU}, 440 b: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU}, 441 expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 442 }, 443 } 444 for testName, testCase := range testCases { 445 actual := Intersection(testCase.a, testCase.b) 446 if !reflect.DeepEqual(actual, testCase.expected) { 447 t.Errorf("%s expected: %#v, actual: %#v", testName, testCase.expected, actual) 448 } 449 } 450 } 451 452 func TestDifference(t *testing.T) { 453 testCases := map[string]struct { 454 a []corev1.ResourceName 455 b []corev1.ResourceName 456 expected []corev1.ResourceName 457 }{ 458 "empty": { 459 a: []corev1.ResourceName{}, 460 b: []corev1.ResourceName{}, 461 expected: []corev1.ResourceName{}, 462 }, 463 "equal": { 464 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 465 b: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 466 expected: []corev1.ResourceName{}, 467 }, 468 "a has extra": { 469 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 470 b: []corev1.ResourceName{corev1.ResourceCPU}, 471 expected: []corev1.ResourceName{corev1.ResourceMemory}, 472 }, 473 "b has extra": { 474 a: []corev1.ResourceName{corev1.ResourceCPU}, 475 b: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 476 expected: []corev1.ResourceName{}, 477 }, 478 "dedupes": { 479 a: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceCPU, corev1.ResourceMemory, corev1.ResourceMemory}, 480 b: []corev1.ResourceName{corev1.ResourceCPU}, 481 expected: []corev1.ResourceName{corev1.ResourceMemory}, 482 }, 483 "sorts": { 484 a: []corev1.ResourceName{corev1.ResourceMemory, corev1.ResourceMemory, corev1.ResourceCPU, corev1.ResourceCPU}, 485 b: []corev1.ResourceName{}, 486 expected: []corev1.ResourceName{corev1.ResourceCPU, corev1.ResourceMemory}, 487 }, 488 } 489 for testName, testCase := range testCases { 490 actual := Difference(testCase.a, testCase.b) 491 if !reflect.DeepEqual(actual, testCase.expected) { 492 t.Errorf("%s expected: %#v, actual: %#v", testName, testCase.expected, actual) 493 } 494 } 495 }