k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/apis/discovery/validation/validation_test.go (about) 1 /* 2 Copyright 2019 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 "strings" 22 "testing" 23 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 api "k8s.io/kubernetes/pkg/apis/core" 27 "k8s.io/kubernetes/pkg/apis/discovery" 28 utilpointer "k8s.io/utils/pointer" 29 ) 30 31 func TestValidateEndpointSlice(t *testing.T) { 32 standardMeta := metav1.ObjectMeta{ 33 Name: "hello", 34 Namespace: "world", 35 } 36 37 testCases := map[string]struct { 38 expectedErrors int 39 endpointSlice *discovery.EndpointSlice 40 }{ 41 "good-slice": { 42 expectedErrors: 0, 43 endpointSlice: &discovery.EndpointSlice{ 44 ObjectMeta: standardMeta, 45 AddressType: discovery.AddressTypeIPv4, 46 Ports: []discovery.EndpointPort{{ 47 Name: utilpointer.String("http"), 48 Protocol: protocolPtr(api.ProtocolTCP), 49 }}, 50 Endpoints: []discovery.Endpoint{{ 51 Addresses: generateIPAddresses(1), 52 Hostname: utilpointer.String("valid-123"), 53 }}, 54 }, 55 }, 56 "good-ipv6": { 57 expectedErrors: 0, 58 endpointSlice: &discovery.EndpointSlice{ 59 ObjectMeta: standardMeta, 60 AddressType: discovery.AddressTypeIPv6, 61 Ports: []discovery.EndpointPort{{ 62 Name: utilpointer.String("http"), 63 Protocol: protocolPtr(api.ProtocolTCP), 64 }}, 65 Endpoints: []discovery.Endpoint{{ 66 Addresses: []string{"a00:100::4"}, 67 Hostname: utilpointer.String("valid-123"), 68 }}, 69 }, 70 }, 71 "good-fqdns": { 72 expectedErrors: 0, 73 endpointSlice: &discovery.EndpointSlice{ 74 ObjectMeta: standardMeta, 75 AddressType: discovery.AddressTypeFQDN, 76 Ports: []discovery.EndpointPort{{ 77 Name: utilpointer.String("http"), 78 Protocol: protocolPtr(api.ProtocolTCP), 79 }}, 80 Endpoints: []discovery.Endpoint{{ 81 Addresses: []string{"foo.example.com", "example.com", "example.com.", "hyphens-are-good.example.com"}, 82 Hostname: utilpointer.String("valid-123"), 83 }}, 84 }, 85 }, 86 "all-protocols": { 87 expectedErrors: 0, 88 endpointSlice: &discovery.EndpointSlice{ 89 ObjectMeta: standardMeta, 90 AddressType: discovery.AddressTypeIPv4, 91 Ports: []discovery.EndpointPort{{ 92 Name: utilpointer.String("tcp"), 93 Protocol: protocolPtr(api.ProtocolTCP), 94 }, { 95 Name: utilpointer.String("udp"), 96 Protocol: protocolPtr(api.ProtocolUDP), 97 }, { 98 Name: utilpointer.String("sctp"), 99 Protocol: protocolPtr(api.ProtocolSCTP), 100 }}, 101 Endpoints: []discovery.Endpoint{{ 102 Addresses: generateIPAddresses(1), 103 Hostname: utilpointer.String("valid-123"), 104 }}, 105 }, 106 }, 107 "app-protocols": { 108 expectedErrors: 0, 109 endpointSlice: &discovery.EndpointSlice{ 110 ObjectMeta: standardMeta, 111 AddressType: discovery.AddressTypeIPv4, 112 Ports: []discovery.EndpointPort{{ 113 Name: utilpointer.String("one"), 114 Protocol: protocolPtr(api.ProtocolTCP), 115 AppProtocol: utilpointer.String("HTTP"), 116 }, { 117 Name: utilpointer.String("two"), 118 Protocol: protocolPtr(api.ProtocolTCP), 119 AppProtocol: utilpointer.String("https"), 120 }, { 121 Name: utilpointer.String("three"), 122 Protocol: protocolPtr(api.ProtocolTCP), 123 AppProtocol: utilpointer.String("my-protocol"), 124 }, { 125 Name: utilpointer.String("four"), 126 Protocol: protocolPtr(api.ProtocolTCP), 127 AppProtocol: utilpointer.String("example.com/custom-protocol"), 128 }}, 129 Endpoints: []discovery.Endpoint{{ 130 Addresses: generateIPAddresses(1), 131 Hostname: utilpointer.String("valid-123"), 132 }}, 133 }, 134 }, 135 "empty-port-name": { 136 expectedErrors: 0, 137 endpointSlice: &discovery.EndpointSlice{ 138 ObjectMeta: standardMeta, 139 AddressType: discovery.AddressTypeIPv4, 140 Ports: []discovery.EndpointPort{{ 141 Name: utilpointer.String(""), 142 Protocol: protocolPtr(api.ProtocolTCP), 143 }, { 144 Name: utilpointer.String("http"), 145 Protocol: protocolPtr(api.ProtocolTCP), 146 }}, 147 Endpoints: []discovery.Endpoint{{ 148 Addresses: generateIPAddresses(1), 149 }}, 150 }, 151 }, 152 "long-port-name": { 153 expectedErrors: 0, 154 endpointSlice: &discovery.EndpointSlice{ 155 ObjectMeta: standardMeta, 156 AddressType: discovery.AddressTypeIPv4, 157 Ports: []discovery.EndpointPort{{ 158 Name: utilpointer.String(strings.Repeat("a", 63)), 159 Protocol: protocolPtr(api.ProtocolTCP), 160 }}, 161 Endpoints: []discovery.Endpoint{{ 162 Addresses: generateIPAddresses(1), 163 }}, 164 }, 165 }, 166 "empty-ports-and-endpoints": { 167 expectedErrors: 0, 168 endpointSlice: &discovery.EndpointSlice{ 169 ObjectMeta: standardMeta, 170 AddressType: discovery.AddressTypeIPv4, 171 Ports: []discovery.EndpointPort{}, 172 Endpoints: []discovery.Endpoint{}, 173 }, 174 }, 175 "max-endpoints": { 176 expectedErrors: 0, 177 endpointSlice: &discovery.EndpointSlice{ 178 ObjectMeta: standardMeta, 179 AddressType: discovery.AddressTypeIPv4, 180 Ports: generatePorts(1), 181 Endpoints: generateEndpoints(maxEndpoints), 182 }, 183 }, 184 "max-ports": { 185 expectedErrors: 0, 186 endpointSlice: &discovery.EndpointSlice{ 187 ObjectMeta: standardMeta, 188 AddressType: discovery.AddressTypeIPv4, 189 Ports: generatePorts(maxPorts), 190 }, 191 }, 192 "max-addresses": { 193 expectedErrors: 0, 194 endpointSlice: &discovery.EndpointSlice{ 195 ObjectMeta: standardMeta, 196 AddressType: discovery.AddressTypeIPv4, 197 Ports: []discovery.EndpointPort{{ 198 Name: utilpointer.String("http"), 199 Protocol: protocolPtr(api.ProtocolTCP), 200 }}, 201 Endpoints: []discovery.Endpoint{{ 202 Addresses: generateIPAddresses(maxAddresses), 203 }}, 204 }, 205 }, 206 "max-topology-keys": { 207 expectedErrors: 0, 208 endpointSlice: &discovery.EndpointSlice{ 209 ObjectMeta: standardMeta, 210 AddressType: discovery.AddressTypeIPv4, 211 Ports: []discovery.EndpointPort{{ 212 Name: utilpointer.String("http"), 213 Protocol: protocolPtr(api.ProtocolTCP), 214 }}, 215 Endpoints: []discovery.Endpoint{{ 216 Addresses: generateIPAddresses(1), 217 DeprecatedTopology: generateTopology(maxTopologyLabels), 218 }}, 219 }, 220 }, 221 "valid-hints": { 222 expectedErrors: 0, 223 endpointSlice: &discovery.EndpointSlice{ 224 ObjectMeta: standardMeta, 225 AddressType: discovery.AddressTypeIPv4, 226 Ports: []discovery.EndpointPort{{ 227 Name: utilpointer.String("http"), 228 Protocol: protocolPtr(api.ProtocolTCP), 229 }}, 230 Endpoints: []discovery.Endpoint{{ 231 Addresses: generateIPAddresses(1), 232 Hints: &discovery.EndpointHints{ 233 ForZones: []discovery.ForZone{{Name: "zone-a"}}, 234 }, 235 }}, 236 }, 237 }, 238 239 // expected failures 240 "duplicate-port-name": { 241 expectedErrors: 1, 242 endpointSlice: &discovery.EndpointSlice{ 243 ObjectMeta: standardMeta, 244 AddressType: discovery.AddressTypeIPv4, 245 Ports: []discovery.EndpointPort{{ 246 Name: utilpointer.String(""), 247 Protocol: protocolPtr(api.ProtocolTCP), 248 }, { 249 Name: utilpointer.String(""), 250 Protocol: protocolPtr(api.ProtocolTCP), 251 }}, 252 Endpoints: []discovery.Endpoint{}, 253 }, 254 }, 255 "bad-port-name-caps": { 256 expectedErrors: 1, 257 endpointSlice: &discovery.EndpointSlice{ 258 ObjectMeta: standardMeta, 259 AddressType: discovery.AddressTypeIPv4, 260 Ports: []discovery.EndpointPort{{ 261 Name: utilpointer.String("aCapital"), 262 Protocol: protocolPtr(api.ProtocolTCP), 263 }}, 264 Endpoints: []discovery.Endpoint{}, 265 }, 266 }, 267 "bad-port-name-chars": { 268 expectedErrors: 1, 269 endpointSlice: &discovery.EndpointSlice{ 270 ObjectMeta: standardMeta, 271 AddressType: discovery.AddressTypeIPv4, 272 Ports: []discovery.EndpointPort{{ 273 Name: utilpointer.String("almost_valid"), 274 Protocol: protocolPtr(api.ProtocolTCP), 275 }}, 276 Endpoints: []discovery.Endpoint{}, 277 }, 278 }, 279 "bad-port-name-length": { 280 expectedErrors: 1, 281 endpointSlice: &discovery.EndpointSlice{ 282 ObjectMeta: standardMeta, 283 AddressType: discovery.AddressTypeIPv4, 284 Ports: []discovery.EndpointPort{{ 285 Name: utilpointer.String(strings.Repeat("a", 64)), 286 Protocol: protocolPtr(api.ProtocolTCP), 287 }}, 288 Endpoints: []discovery.Endpoint{}, 289 }, 290 }, 291 "invalid-port-protocol": { 292 expectedErrors: 1, 293 endpointSlice: &discovery.EndpointSlice{ 294 ObjectMeta: standardMeta, 295 AddressType: discovery.AddressTypeIPv4, 296 Ports: []discovery.EndpointPort{{ 297 Name: utilpointer.String("http"), 298 Protocol: protocolPtr(api.Protocol("foo")), 299 }}, 300 }, 301 }, 302 "too-many-ports": { 303 expectedErrors: 1, 304 endpointSlice: &discovery.EndpointSlice{ 305 ObjectMeta: standardMeta, 306 AddressType: discovery.AddressTypeIPv4, 307 Ports: generatePorts(maxPorts + 1), 308 }, 309 }, 310 "too-many-endpoints": { 311 expectedErrors: 1, 312 endpointSlice: &discovery.EndpointSlice{ 313 ObjectMeta: standardMeta, 314 AddressType: discovery.AddressTypeIPv4, 315 Ports: generatePorts(1), 316 Endpoints: generateEndpoints(maxEndpoints + 1), 317 }, 318 }, 319 "no-endpoint-addresses": { 320 expectedErrors: 1, 321 endpointSlice: &discovery.EndpointSlice{ 322 ObjectMeta: standardMeta, 323 AddressType: discovery.AddressTypeIPv4, 324 Ports: []discovery.EndpointPort{{ 325 Name: utilpointer.String("http"), 326 Protocol: protocolPtr(api.ProtocolTCP), 327 }}, 328 Endpoints: []discovery.Endpoint{{ 329 Addresses: generateIPAddresses(0), 330 }}, 331 }, 332 }, 333 "too-many-addresses": { 334 expectedErrors: 1, 335 endpointSlice: &discovery.EndpointSlice{ 336 ObjectMeta: standardMeta, 337 AddressType: discovery.AddressTypeIPv4, 338 Ports: []discovery.EndpointPort{{ 339 Name: utilpointer.String("http"), 340 Protocol: protocolPtr(api.ProtocolTCP), 341 }}, 342 Endpoints: []discovery.Endpoint{{ 343 Addresses: generateIPAddresses(maxAddresses + 1), 344 }}, 345 }, 346 }, 347 "bad-topology-key": { 348 expectedErrors: 1, 349 endpointSlice: &discovery.EndpointSlice{ 350 ObjectMeta: standardMeta, 351 AddressType: discovery.AddressTypeIPv4, 352 Ports: []discovery.EndpointPort{{ 353 Name: utilpointer.String("http"), 354 Protocol: protocolPtr(api.ProtocolTCP), 355 }}, 356 Endpoints: []discovery.Endpoint{{ 357 Addresses: generateIPAddresses(1), 358 DeprecatedTopology: map[string]string{"--INVALID": "example"}, 359 }}, 360 }, 361 }, 362 "too-many-topology-keys": { 363 expectedErrors: 1, 364 endpointSlice: &discovery.EndpointSlice{ 365 ObjectMeta: standardMeta, 366 AddressType: discovery.AddressTypeIPv4, 367 Ports: []discovery.EndpointPort{{ 368 Name: utilpointer.String("http"), 369 Protocol: protocolPtr(api.ProtocolTCP), 370 }}, 371 Endpoints: []discovery.Endpoint{{ 372 Addresses: generateIPAddresses(1), 373 DeprecatedTopology: generateTopology(maxTopologyLabels + 1), 374 }}, 375 }, 376 }, 377 "bad-hostname": { 378 expectedErrors: 1, 379 endpointSlice: &discovery.EndpointSlice{ 380 ObjectMeta: standardMeta, 381 AddressType: discovery.AddressTypeIPv4, 382 Ports: []discovery.EndpointPort{{ 383 Name: utilpointer.String("http"), 384 Protocol: protocolPtr(api.ProtocolTCP), 385 }}, 386 Endpoints: []discovery.Endpoint{{ 387 Addresses: generateIPAddresses(1), 388 Hostname: utilpointer.String("--INVALID"), 389 }}, 390 }, 391 }, 392 "bad-meta": { 393 expectedErrors: 1, 394 endpointSlice: &discovery.EndpointSlice{ 395 ObjectMeta: metav1.ObjectMeta{ 396 Name: "*&^", 397 Namespace: "foo", 398 }, 399 AddressType: discovery.AddressTypeIPv4, 400 Ports: []discovery.EndpointPort{{ 401 Name: utilpointer.String("http"), 402 Protocol: protocolPtr(api.ProtocolTCP), 403 }}, 404 Endpoints: []discovery.Endpoint{{ 405 Addresses: generateIPAddresses(1), 406 Hostname: utilpointer.String("valid-123"), 407 }}, 408 }, 409 }, 410 "bad-ip": { 411 expectedErrors: 2, 412 endpointSlice: &discovery.EndpointSlice{ 413 ObjectMeta: standardMeta, 414 AddressType: discovery.AddressTypeIPv4, 415 Ports: []discovery.EndpointPort{{ 416 Name: utilpointer.String("http"), 417 Protocol: protocolPtr(api.ProtocolTCP), 418 }}, 419 Endpoints: []discovery.Endpoint{{ 420 Addresses: []string{"123.456.789.012"}, 421 Hostname: utilpointer.String("valid-123"), 422 }}, 423 }, 424 }, 425 "bad-ipv4": { 426 expectedErrors: 3, 427 endpointSlice: &discovery.EndpointSlice{ 428 ObjectMeta: standardMeta, 429 AddressType: discovery.AddressTypeIPv4, 430 Ports: []discovery.EndpointPort{{ 431 Name: utilpointer.String("http"), 432 Protocol: protocolPtr(api.ProtocolTCP), 433 }}, 434 Endpoints: []discovery.Endpoint{{ 435 Addresses: []string{"123.456.789.012", "2001:4860:4860::8888"}, 436 Hostname: utilpointer.String("valid-123"), 437 }}, 438 }, 439 }, 440 "bad-ipv6": { 441 expectedErrors: 4, 442 endpointSlice: &discovery.EndpointSlice{ 443 ObjectMeta: standardMeta, 444 AddressType: discovery.AddressTypeIPv6, 445 Ports: []discovery.EndpointPort{{ 446 Name: utilpointer.String("http"), 447 Protocol: protocolPtr(api.ProtocolTCP), 448 }}, 449 Endpoints: []discovery.Endpoint{{ 450 Addresses: []string{"123.456.789.012", "2001:4860:4860:defg"}, 451 Hostname: utilpointer.String("valid-123"), 452 }}, 453 }, 454 }, 455 "bad-fqdns": { 456 expectedErrors: 4, 457 endpointSlice: &discovery.EndpointSlice{ 458 ObjectMeta: standardMeta, 459 AddressType: discovery.AddressTypeFQDN, 460 Ports: []discovery.EndpointPort{{ 461 Name: utilpointer.String("http"), 462 Protocol: protocolPtr(api.ProtocolTCP), 463 }}, 464 Endpoints: []discovery.Endpoint{{ 465 Addresses: []string{"foo.*", "FOO.example.com", "underscores_are_bad.example.com", "*.example.com"}, 466 Hostname: utilpointer.String("valid-123"), 467 }}, 468 }, 469 }, 470 "bad-app-protocol": { 471 expectedErrors: 1, 472 endpointSlice: &discovery.EndpointSlice{ 473 ObjectMeta: standardMeta, 474 AddressType: discovery.AddressTypeIPv4, 475 Ports: []discovery.EndpointPort{{ 476 Name: utilpointer.String("http"), 477 Protocol: protocolPtr(api.ProtocolTCP), 478 AppProtocol: utilpointer.String("--"), 479 }}, 480 Endpoints: []discovery.Endpoint{{ 481 Addresses: generateIPAddresses(1), 482 Hostname: utilpointer.String("valid-123"), 483 }}, 484 }, 485 }, 486 "invalid-hints": { 487 expectedErrors: 1, 488 endpointSlice: &discovery.EndpointSlice{ 489 ObjectMeta: standardMeta, 490 AddressType: discovery.AddressTypeIPv4, 491 Ports: []discovery.EndpointPort{{ 492 Name: utilpointer.String("http"), 493 Protocol: protocolPtr(api.ProtocolTCP), 494 }}, 495 Endpoints: []discovery.Endpoint{{ 496 Addresses: generateIPAddresses(1), 497 Hints: &discovery.EndpointHints{ 498 ForZones: []discovery.ForZone{{Name: "inv@lid"}}, 499 }, 500 }}, 501 }, 502 }, 503 "overlapping-hints": { 504 expectedErrors: 1, 505 endpointSlice: &discovery.EndpointSlice{ 506 ObjectMeta: standardMeta, 507 AddressType: discovery.AddressTypeIPv4, 508 Ports: []discovery.EndpointPort{{ 509 Name: utilpointer.String("http"), 510 Protocol: protocolPtr(api.ProtocolTCP), 511 }}, 512 Endpoints: []discovery.Endpoint{{ 513 Addresses: generateIPAddresses(1), 514 Hints: &discovery.EndpointHints{ 515 ForZones: []discovery.ForZone{ 516 {Name: "zone-a"}, 517 {Name: "zone-b"}, 518 {Name: "zone-a"}, 519 }, 520 }, 521 }}, 522 }, 523 }, 524 "too-many-hints": { 525 expectedErrors: 1, 526 endpointSlice: &discovery.EndpointSlice{ 527 ObjectMeta: standardMeta, 528 AddressType: discovery.AddressTypeIPv4, 529 Ports: []discovery.EndpointPort{{ 530 Name: utilpointer.String("http"), 531 Protocol: protocolPtr(api.ProtocolTCP), 532 }}, 533 Endpoints: []discovery.Endpoint{{ 534 Addresses: generateIPAddresses(1), 535 Hints: &discovery.EndpointHints{ 536 ForZones: []discovery.ForZone{ 537 {Name: "zone-a"}, 538 {Name: "zone-b"}, 539 {Name: "zone-c"}, 540 {Name: "zone-d"}, 541 {Name: "zone-e"}, 542 {Name: "zone-f"}, 543 {Name: "zone-g"}, 544 {Name: "zone-h"}, 545 {Name: "zone-i"}, 546 }, 547 }, 548 }}, 549 }, 550 }, 551 "empty-everything": { 552 expectedErrors: 3, 553 endpointSlice: &discovery.EndpointSlice{}, 554 }, 555 "zone-key-topology": { 556 expectedErrors: 1, 557 endpointSlice: &discovery.EndpointSlice{ 558 ObjectMeta: standardMeta, 559 AddressType: discovery.AddressTypeIPv4, 560 Ports: []discovery.EndpointPort{{ 561 Name: utilpointer.String("http"), 562 Protocol: protocolPtr(api.ProtocolTCP), 563 }}, 564 Endpoints: []discovery.Endpoint{{ 565 Addresses: generateIPAddresses(1), 566 DeprecatedTopology: map[string]string{corev1.LabelTopologyZone: "zone1"}, 567 }}, 568 }, 569 }, 570 "special-ipv4": { 571 expectedErrors: 1, 572 endpointSlice: &discovery.EndpointSlice{ 573 ObjectMeta: standardMeta, 574 AddressType: discovery.AddressTypeIPv4, 575 Ports: []discovery.EndpointPort{{ 576 Name: utilpointer.String("http"), 577 Protocol: protocolPtr(api.ProtocolTCP), 578 }}, 579 Endpoints: []discovery.Endpoint{{ 580 Addresses: []string{"127.0.0.1"}, 581 Hostname: utilpointer.String("valid-123"), 582 }}, 583 }, 584 }, 585 "special-ipv6": { 586 expectedErrors: 1, 587 endpointSlice: &discovery.EndpointSlice{ 588 ObjectMeta: standardMeta, 589 AddressType: discovery.AddressTypeIPv6, 590 Ports: []discovery.EndpointPort{{ 591 Name: utilpointer.String("http"), 592 Protocol: protocolPtr(api.ProtocolTCP), 593 }}, 594 Endpoints: []discovery.Endpoint{{ 595 Addresses: []string{"fe80::9656:d028:8652:66b6"}, 596 Hostname: utilpointer.String("valid-123"), 597 }}, 598 }, 599 }, 600 } 601 602 for name, testCase := range testCases { 603 t.Run(name, func(t *testing.T) { 604 errs := ValidateEndpointSlice(testCase.endpointSlice) 605 if len(errs) != testCase.expectedErrors { 606 t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) 607 } 608 }) 609 } 610 } 611 612 func TestValidateEndpointSliceCreate(t *testing.T) { 613 standardMeta := metav1.ObjectMeta{ 614 Name: "hello", 615 Namespace: "world", 616 } 617 618 testCases := map[string]struct { 619 expectedErrors int 620 endpointSlice *discovery.EndpointSlice 621 nodeNameGateEnabled bool 622 }{ 623 "good-slice": { 624 expectedErrors: 0, 625 endpointSlice: &discovery.EndpointSlice{ 626 ObjectMeta: standardMeta, 627 AddressType: discovery.AddressTypeIPv4, 628 Ports: []discovery.EndpointPort{{ 629 Name: utilpointer.String("http"), 630 Protocol: protocolPtr(api.ProtocolTCP), 631 }}, 632 Endpoints: []discovery.Endpoint{{ 633 Addresses: generateIPAddresses(1), 634 Hostname: utilpointer.String("valid-123"), 635 }}, 636 }, 637 }, 638 "good-slice-node-name": { 639 expectedErrors: 0, 640 endpointSlice: &discovery.EndpointSlice{ 641 ObjectMeta: standardMeta, 642 AddressType: discovery.AddressTypeIPv4, 643 Ports: []discovery.EndpointPort{{ 644 Name: utilpointer.String("http"), 645 Protocol: protocolPtr(api.ProtocolTCP), 646 }}, 647 Endpoints: []discovery.Endpoint{{ 648 Addresses: generateIPAddresses(1), 649 Hostname: utilpointer.String("valid-123"), 650 NodeName: utilpointer.String("valid-node-name"), 651 }}, 652 }, 653 }, 654 655 // expected failures 656 "bad-node-name": { 657 expectedErrors: 1, 658 endpointSlice: &discovery.EndpointSlice{ 659 ObjectMeta: standardMeta, 660 AddressType: discovery.AddressTypeIPv4, 661 Ports: []discovery.EndpointPort{{ 662 Name: utilpointer.String("http"), 663 Protocol: protocolPtr(api.ProtocolTCP), 664 }}, 665 Endpoints: []discovery.Endpoint{{ 666 Addresses: generateIPAddresses(1), 667 Hostname: utilpointer.String("valid-123"), 668 NodeName: utilpointer.String("INvalid-node-name"), 669 }}, 670 }, 671 }, 672 "deprecated-address-type": { 673 expectedErrors: 1, 674 endpointSlice: &discovery.EndpointSlice{ 675 ObjectMeta: standardMeta, 676 AddressType: discovery.AddressType("IP"), 677 Ports: []discovery.EndpointPort{{ 678 Name: utilpointer.String("http"), 679 Protocol: protocolPtr(api.ProtocolTCP), 680 }}, 681 Endpoints: []discovery.Endpoint{{ 682 Addresses: generateIPAddresses(1), 683 }}, 684 }, 685 }, 686 "bad-address-type": { 687 expectedErrors: 1, 688 endpointSlice: &discovery.EndpointSlice{ 689 ObjectMeta: standardMeta, 690 AddressType: discovery.AddressType("other"), 691 Ports: []discovery.EndpointPort{{ 692 Name: utilpointer.String("http"), 693 Protocol: protocolPtr(api.ProtocolTCP), 694 }}, 695 Endpoints: []discovery.Endpoint{{ 696 Addresses: generateIPAddresses(1), 697 }}, 698 }, 699 }, 700 } 701 702 for name, testCase := range testCases { 703 t.Run(name, func(t *testing.T) { 704 errs := ValidateEndpointSliceCreate(testCase.endpointSlice) 705 if len(errs) != testCase.expectedErrors { 706 t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) 707 } 708 }) 709 } 710 } 711 712 func TestValidateEndpointSliceUpdate(t *testing.T) { 713 standardMeta := metav1.ObjectMeta{Name: "es1", Namespace: "test"} 714 715 testCases := map[string]struct { 716 expectedErrors int 717 nodeNameGateEnabled bool 718 oldEndpointSlice *discovery.EndpointSlice 719 newEndpointSlice *discovery.EndpointSlice 720 }{ 721 "valid and identical slices": { 722 oldEndpointSlice: &discovery.EndpointSlice{ 723 ObjectMeta: standardMeta, 724 AddressType: discovery.AddressTypeIPv6, 725 }, 726 newEndpointSlice: &discovery.EndpointSlice{ 727 ObjectMeta: standardMeta, 728 AddressType: discovery.AddressTypeIPv6, 729 }, 730 expectedErrors: 0, 731 }, 732 733 // expected errors 734 "invalid node name set": { 735 oldEndpointSlice: &discovery.EndpointSlice{ 736 ObjectMeta: standardMeta, 737 AddressType: discovery.AddressTypeIPv4, 738 Endpoints: []discovery.Endpoint{{ 739 Addresses: []string{"10.1.2.3"}, 740 }}, 741 }, 742 newEndpointSlice: &discovery.EndpointSlice{ 743 ObjectMeta: standardMeta, 744 AddressType: discovery.AddressTypeIPv4, 745 Endpoints: []discovery.Endpoint{{ 746 Addresses: []string{"10.1.2.3"}, 747 NodeName: utilpointer.String("INVALID foo"), 748 }}, 749 }, 750 expectedErrors: 1, 751 }, 752 753 "deprecated address type": { 754 expectedErrors: 1, 755 oldEndpointSlice: &discovery.EndpointSlice{ 756 ObjectMeta: standardMeta, 757 AddressType: discovery.AddressType("IP"), 758 }, 759 newEndpointSlice: &discovery.EndpointSlice{ 760 ObjectMeta: standardMeta, 761 AddressType: discovery.AddressType("IP"), 762 }, 763 }, 764 "valid and identical slices with different address types": { 765 oldEndpointSlice: &discovery.EndpointSlice{ 766 ObjectMeta: standardMeta, 767 AddressType: discovery.AddressType("other"), 768 }, 769 newEndpointSlice: &discovery.EndpointSlice{ 770 ObjectMeta: standardMeta, 771 AddressType: discovery.AddressTypeIPv4, 772 }, 773 expectedErrors: 1, 774 }, 775 "invalid slices with valid address types": { 776 oldEndpointSlice: &discovery.EndpointSlice{ 777 ObjectMeta: standardMeta, 778 AddressType: discovery.AddressTypeIPv4, 779 }, 780 newEndpointSlice: &discovery.EndpointSlice{ 781 ObjectMeta: standardMeta, 782 AddressType: discovery.AddressTypeIPv4, 783 Ports: []discovery.EndpointPort{{ 784 Name: utilpointer.String(""), 785 Protocol: protocolPtr(api.Protocol("invalid")), 786 }}, 787 }, 788 expectedErrors: 1, 789 }, 790 } 791 792 for name, testCase := range testCases { 793 t.Run(name, func(t *testing.T) { 794 errs := ValidateEndpointSliceUpdate(testCase.newEndpointSlice, testCase.oldEndpointSlice) 795 if len(errs) != testCase.expectedErrors { 796 t.Errorf("Expected %d errors, got %d errors: %v", testCase.expectedErrors, len(errs), errs) 797 } 798 }) 799 } 800 } 801 802 // Test helpers 803 804 func protocolPtr(protocol api.Protocol) *api.Protocol { 805 return &protocol 806 } 807 808 func generatePorts(n int) []discovery.EndpointPort { 809 ports := []discovery.EndpointPort{} 810 for i := 0; i < n; i++ { 811 ports = append(ports, discovery.EndpointPort{ 812 Name: utilpointer.String(fmt.Sprintf("http-%d", i)), 813 Protocol: protocolPtr(api.ProtocolTCP), 814 }) 815 } 816 return ports 817 } 818 819 func generateEndpoints(n int) []discovery.Endpoint { 820 endpoints := []discovery.Endpoint{} 821 for i := 0; i < n; i++ { 822 endpoints = append(endpoints, discovery.Endpoint{ 823 Addresses: []string{fmt.Sprintf("10.1.2.%d", i%255)}, 824 }) 825 } 826 return endpoints 827 } 828 829 func generateIPAddresses(n int) []string { 830 addresses := []string{} 831 for i := 0; i < n; i++ { 832 addresses = append(addresses, fmt.Sprintf("10.1.2.%d", i%255)) 833 } 834 return addresses 835 } 836 837 func generateTopology(n int) map[string]string { 838 topology := map[string]string{} 839 for i := 0; i < n; i++ { 840 topology[fmt.Sprintf("topology-%d", i)] = "example" 841 } 842 return topology 843 }