github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/specgen/generate/ports_test.go (about) 1 package generate 2 3 import ( 4 "testing" 5 6 "github.com/containers/common/libnetwork/types" 7 "github.com/stretchr/testify/assert" 8 ) 9 10 func TestParsePortMappingWithHostPort(t *testing.T) { 11 tests := []struct { 12 name string 13 arg []types.PortMapping 14 arg2 map[uint16][]string 15 want []types.PortMapping 16 }{ 17 { 18 name: "no ports", 19 arg: nil, 20 want: nil, 21 }, 22 { 23 name: "one tcp port", 24 arg: []types.PortMapping{ 25 { 26 HostPort: 8080, 27 ContainerPort: 80, 28 Protocol: "tcp", 29 }, 30 }, 31 want: []types.PortMapping{ 32 { 33 HostPort: 8080, 34 ContainerPort: 80, 35 Protocol: "tcp", 36 Range: 1, 37 }, 38 }, 39 }, 40 { 41 name: "one tcp port no proto", 42 arg: []types.PortMapping{ 43 { 44 HostPort: 8080, 45 ContainerPort: 80, 46 }, 47 }, 48 want: []types.PortMapping{ 49 { 50 HostPort: 8080, 51 ContainerPort: 80, 52 Protocol: "tcp", 53 Range: 1, 54 }, 55 }, 56 }, 57 { 58 name: "one udp port", 59 arg: []types.PortMapping{ 60 { 61 HostPort: 8080, 62 ContainerPort: 80, 63 Protocol: "udp", 64 }, 65 }, 66 want: []types.PortMapping{ 67 { 68 HostPort: 8080, 69 ContainerPort: 80, 70 Protocol: "udp", 71 Range: 1, 72 }, 73 }, 74 }, 75 { 76 name: "one sctp port", 77 arg: []types.PortMapping{ 78 { 79 HostPort: 8080, 80 ContainerPort: 80, 81 Protocol: "sctp", 82 }, 83 }, 84 want: []types.PortMapping{ 85 { 86 HostPort: 8080, 87 ContainerPort: 80, 88 Protocol: "sctp", 89 Range: 1, 90 }, 91 }, 92 }, 93 { 94 name: "one port two protocols", 95 arg: []types.PortMapping{ 96 { 97 HostPort: 8080, 98 ContainerPort: 80, 99 Protocol: "tcp,udp", 100 }, 101 }, 102 want: []types.PortMapping{ 103 { 104 HostPort: 8080, 105 ContainerPort: 80, 106 Protocol: "tcp", 107 Range: 1, 108 }, 109 { 110 HostPort: 8080, 111 ContainerPort: 80, 112 Protocol: "udp", 113 Range: 1, 114 }, 115 }, 116 }, 117 { 118 name: "one port three protocols", 119 arg: []types.PortMapping{ 120 { 121 HostPort: 8080, 122 ContainerPort: 80, 123 Protocol: "tcp,udp,sctp", 124 }, 125 }, 126 want: []types.PortMapping{ 127 { 128 HostPort: 8080, 129 ContainerPort: 80, 130 Protocol: "tcp", 131 Range: 1, 132 }, 133 { 134 HostPort: 8080, 135 ContainerPort: 80, 136 Protocol: "udp", 137 Range: 1, 138 }, 139 { 140 HostPort: 8080, 141 ContainerPort: 80, 142 Protocol: "sctp", 143 Range: 1, 144 }, 145 }, 146 }, 147 { 148 name: "one port with range 1", 149 arg: []types.PortMapping{ 150 { 151 HostPort: 8080, 152 ContainerPort: 80, 153 Protocol: "tcp", 154 Range: 1, 155 }, 156 }, 157 want: []types.PortMapping{ 158 { 159 HostPort: 8080, 160 ContainerPort: 80, 161 Protocol: "tcp", 162 Range: 1, 163 }, 164 }, 165 }, 166 { 167 name: "one port with range 5", 168 arg: []types.PortMapping{ 169 { 170 HostPort: 8080, 171 ContainerPort: 80, 172 Protocol: "tcp", 173 Range: 5, 174 }, 175 }, 176 want: []types.PortMapping{ 177 { 178 HostPort: 8080, 179 ContainerPort: 80, 180 Protocol: "tcp", 181 Range: 5, 182 }, 183 }, 184 }, 185 { 186 name: "two ports joined", 187 arg: []types.PortMapping{ 188 { 189 HostPort: 8080, 190 ContainerPort: 80, 191 Protocol: "tcp", 192 }, 193 { 194 HostPort: 8081, 195 ContainerPort: 81, 196 Protocol: "tcp", 197 }, 198 }, 199 want: []types.PortMapping{ 200 { 201 HostPort: 8080, 202 ContainerPort: 80, 203 Protocol: "tcp", 204 Range: 2, 205 }, 206 }, 207 }, 208 { 209 name: "two ports joined with range", 210 arg: []types.PortMapping{ 211 { 212 HostPort: 8080, 213 ContainerPort: 80, 214 Protocol: "tcp", 215 Range: 2, 216 }, 217 { 218 HostPort: 8081, 219 ContainerPort: 81, 220 Protocol: "tcp", 221 }, 222 }, 223 want: []types.PortMapping{ 224 { 225 HostPort: 8080, 226 ContainerPort: 80, 227 Protocol: "tcp", 228 Range: 2, 229 }, 230 }, 231 }, 232 { 233 name: "two ports with no overlapping range", 234 arg: []types.PortMapping{ 235 { 236 HostPort: 8080, 237 ContainerPort: 80, 238 Protocol: "tcp", 239 Range: 10, 240 }, 241 { 242 HostPort: 9090, 243 ContainerPort: 9090, 244 Protocol: "tcp", 245 }, 246 }, 247 want: []types.PortMapping{ 248 { 249 HostPort: 9090, 250 ContainerPort: 9090, 251 Protocol: "tcp", 252 Range: 1, 253 }, 254 { 255 HostPort: 8080, 256 ContainerPort: 80, 257 Protocol: "tcp", 258 Range: 10, 259 }, 260 }, 261 }, 262 { 263 name: "four ports with two overlapping ranges", 264 arg: []types.PortMapping{ 265 { 266 HostPort: 8080, 267 ContainerPort: 80, 268 Protocol: "tcp", 269 Range: 10, 270 }, 271 { 272 HostPort: 8085, 273 ContainerPort: 85, 274 Protocol: "tcp", 275 Range: 10, 276 }, 277 { 278 HostPort: 100, 279 ContainerPort: 5, 280 Protocol: "tcp", 281 }, 282 { 283 HostPort: 101, 284 ContainerPort: 6, 285 Protocol: "tcp", 286 }, 287 }, 288 want: []types.PortMapping{ 289 { 290 HostPort: 8080, 291 ContainerPort: 80, 292 Protocol: "tcp", 293 Range: 15, 294 }, 295 { 296 HostPort: 100, 297 ContainerPort: 5, 298 Protocol: "tcp", 299 Range: 2, 300 }, 301 }, 302 }, 303 { 304 name: "two overlapping ranges", 305 arg: []types.PortMapping{ 306 { 307 HostPort: 8080, 308 ContainerPort: 80, 309 Protocol: "tcp", 310 Range: 10, 311 }, 312 { 313 HostPort: 8085, 314 ContainerPort: 85, 315 Protocol: "tcp", 316 Range: 2, 317 }, 318 }, 319 want: []types.PortMapping{ 320 { 321 HostPort: 8080, 322 ContainerPort: 80, 323 Protocol: "tcp", 324 Range: 10, 325 }, 326 }, 327 }, 328 { 329 name: "four overlapping ranges", 330 arg: []types.PortMapping{ 331 { 332 HostPort: 8080, 333 ContainerPort: 80, 334 Protocol: "tcp", 335 Range: 10, 336 }, 337 { 338 HostPort: 8085, 339 ContainerPort: 85, 340 Protocol: "tcp", 341 Range: 2, 342 }, 343 { 344 HostPort: 8090, 345 ContainerPort: 90, 346 Protocol: "tcp", 347 Range: 7, 348 }, 349 { 350 HostPort: 8095, 351 ContainerPort: 95, 352 Protocol: "tcp", 353 }, 354 }, 355 want: []types.PortMapping{ 356 { 357 HostPort: 8080, 358 ContainerPort: 80, 359 Protocol: "tcp", 360 Range: 17, 361 }, 362 }, 363 }, 364 { 365 name: "one port range overlaps 5 ports", 366 arg: []types.PortMapping{ 367 { 368 HostPort: 8080, 369 ContainerPort: 80, 370 Range: 20, 371 }, 372 { 373 HostPort: 8085, 374 ContainerPort: 85, 375 Range: 2, 376 }, 377 { 378 HostPort: 8090, 379 ContainerPort: 90, 380 }, 381 { 382 HostPort: 8095, 383 ContainerPort: 95, 384 }, 385 { 386 HostPort: 8096, 387 ContainerPort: 96, 388 }, 389 }, 390 want: []types.PortMapping{ 391 { 392 HostPort: 8080, 393 ContainerPort: 80, 394 Protocol: "tcp", 395 Range: 20, 396 }, 397 }, 398 }, 399 { 400 name: "different host ip same port", 401 arg: []types.PortMapping{ 402 { 403 HostPort: 8080, 404 ContainerPort: 80, 405 Protocol: "tcp", 406 HostIP: "192.168.1.1", 407 }, 408 { 409 HostPort: 8080, 410 ContainerPort: 80, 411 Protocol: "tcp", 412 HostIP: "192.168.2.1", 413 }, 414 }, 415 want: []types.PortMapping{ 416 { 417 HostPort: 8080, 418 ContainerPort: 80, 419 Protocol: "tcp", 420 HostIP: "192.168.1.1", 421 Range: 1, 422 }, 423 { 424 HostPort: 8080, 425 ContainerPort: 80, 426 Protocol: "tcp", 427 HostIP: "192.168.2.1", 428 Range: 1, 429 }, 430 }, 431 }, 432 } 433 for _, tt := range tests { 434 tt := tt 435 t.Run(tt.name, func(t *testing.T) { 436 got, err := ParsePortMapping(tt.arg, tt.arg2) 437 assert.NoError(t, err, "error is not nil") 438 // use ElementsMatch instead of Equal because the order is not consistent 439 assert.ElementsMatch(t, tt.want, got, "got unexpected port mapping") 440 }) 441 } 442 } 443 444 func TestParsePortMappingWithoutHostPort(t *testing.T) { 445 tests := []struct { 446 name string 447 arg []types.PortMapping 448 arg2 map[uint16][]string 449 want []types.PortMapping 450 }{ 451 { 452 name: "one tcp port", 453 arg: []types.PortMapping{ 454 { 455 HostPort: 0, 456 ContainerPort: 80, 457 Protocol: "tcp", 458 }, 459 }, 460 want: []types.PortMapping{ 461 { 462 HostPort: 0, 463 ContainerPort: 80, 464 Protocol: "tcp", 465 Range: 1, 466 }, 467 }, 468 }, 469 { 470 name: "one port with two protocols", 471 arg: []types.PortMapping{ 472 { 473 HostPort: 0, 474 ContainerPort: 80, 475 Protocol: "tcp,udp", 476 }, 477 }, 478 want: []types.PortMapping{ 479 { 480 HostPort: 0, 481 ContainerPort: 80, 482 Protocol: "tcp", 483 Range: 1, 484 }, 485 { 486 HostPort: 0, 487 ContainerPort: 80, 488 Protocol: "udp", 489 Range: 1, 490 }, 491 }, 492 }, 493 { 494 name: "same port twice", 495 arg: []types.PortMapping{ 496 { 497 HostPort: 0, 498 ContainerPort: 80, 499 Protocol: "tcp", 500 }, 501 { 502 HostPort: 0, 503 ContainerPort: 80, 504 Protocol: "tcp", 505 }, 506 }, 507 want: []types.PortMapping{ 508 { 509 HostPort: 0, 510 ContainerPort: 80, 511 Protocol: "tcp", 512 Range: 1, 513 }, 514 }, 515 }, 516 { 517 name: "neighbor ports are not joined", 518 arg: []types.PortMapping{ 519 { 520 HostPort: 0, 521 ContainerPort: 80, 522 Protocol: "tcp", 523 }, 524 { 525 HostPort: 0, 526 ContainerPort: 81, 527 Protocol: "tcp", 528 }, 529 }, 530 want: []types.PortMapping{ 531 { 532 HostPort: 0, 533 ContainerPort: 80, 534 Protocol: "tcp", 535 Range: 1, 536 }, 537 { 538 HostPort: 0, 539 ContainerPort: 81, 540 Protocol: "tcp", 541 Range: 1, 542 }, 543 }, 544 }, 545 { 546 name: "overlapping range ports are joined", 547 arg: []types.PortMapping{ 548 { 549 HostPort: 0, 550 ContainerPort: 80, 551 Protocol: "tcp", 552 Range: 2, 553 }, 554 { 555 HostPort: 0, 556 ContainerPort: 81, 557 Protocol: "tcp", 558 }, 559 }, 560 want: []types.PortMapping{ 561 { 562 HostPort: 0, 563 ContainerPort: 80, 564 Protocol: "tcp", 565 Range: 2, 566 }, 567 }, 568 }, 569 { 570 name: "four overlapping range ports are joined", 571 arg: []types.PortMapping{ 572 { 573 HostPort: 0, 574 ContainerPort: 80, 575 Protocol: "tcp", 576 Range: 3, 577 }, 578 { 579 HostPort: 0, 580 ContainerPort: 81, 581 Protocol: "tcp", 582 }, 583 { 584 HostPort: 0, 585 ContainerPort: 82, 586 Protocol: "tcp", 587 Range: 10, 588 }, 589 { 590 HostPort: 0, 591 ContainerPort: 90, 592 Protocol: "tcp", 593 Range: 5, 594 }, 595 }, 596 want: []types.PortMapping{ 597 { 598 HostPort: 0, 599 ContainerPort: 80, 600 Protocol: "tcp", 601 Range: 15, 602 }, 603 }, 604 }, 605 { 606 name: "expose one tcp port", 607 arg2: map[uint16][]string{ 608 8080: {"tcp"}, 609 }, 610 want: []types.PortMapping{ 611 { 612 HostPort: 0, 613 ContainerPort: 8080, 614 Protocol: "tcp", 615 Range: 1, 616 }, 617 }, 618 }, 619 { 620 name: "expose already defined port", 621 arg: []types.PortMapping{ 622 { 623 HostPort: 0, 624 ContainerPort: 8080, 625 Protocol: "tcp", 626 }, 627 }, 628 arg2: map[uint16][]string{ 629 8080: {"tcp"}, 630 }, 631 want: []types.PortMapping{ 632 { 633 HostPort: 0, 634 ContainerPort: 8080, 635 Protocol: "tcp", 636 Range: 1, 637 }, 638 }, 639 }, 640 { 641 name: "expose different proto", 642 arg: []types.PortMapping{ 643 { 644 HostPort: 0, 645 ContainerPort: 8080, 646 Protocol: "tcp", 647 }, 648 }, 649 arg2: map[uint16][]string{ 650 8080: {"udp"}, 651 }, 652 want: []types.PortMapping{ 653 { 654 HostPort: 0, 655 ContainerPort: 8080, 656 Protocol: "tcp", 657 Range: 1, 658 }, 659 { 660 HostPort: 0, 661 ContainerPort: 8080, 662 Protocol: "udp", 663 Range: 1, 664 }, 665 }, 666 }, 667 } 668 for _, tt := range tests { 669 tt := tt 670 t.Run(tt.name, func(t *testing.T) { 671 got, err := ParsePortMapping(tt.arg, tt.arg2) 672 assert.NoError(t, err, "error is not nil") 673 674 // because we always get random host ports when it is set to 0 we cannot check that exactly 675 // check if it is not 0 and set to to 0 afterwards 676 for i := range got { 677 assert.Greater(t, got[i].HostPort, uint16(0), "host port is zero") 678 got[i].HostPort = 0 679 } 680 681 // use ElementsMatch instead of Equal because the order is not consistent 682 assert.ElementsMatch(t, tt.want, got, "got unexpected port mapping") 683 }) 684 } 685 } 686 687 func TestParsePortMappingMixedHostPort(t *testing.T) { 688 tests := []struct { 689 name string 690 arg []types.PortMapping 691 want []types.PortMapping 692 resetHostPorts []int 693 }{ 694 { 695 name: "two ports one without a hostport set", 696 arg: []types.PortMapping{ 697 { 698 HostPort: 0, 699 ContainerPort: 80, 700 }, 701 { 702 HostPort: 8080, 703 ContainerPort: 8080, 704 }, 705 }, 706 want: []types.PortMapping{ 707 { 708 HostPort: 8080, 709 ContainerPort: 8080, 710 Protocol: "tcp", 711 Range: 1, 712 }, 713 { 714 HostPort: 0, 715 ContainerPort: 80, 716 Protocol: "tcp", 717 Range: 1, 718 }, 719 }, 720 resetHostPorts: []int{1}, 721 }, 722 { 723 name: "two ports one without a hostport set, inverted order", 724 arg: []types.PortMapping{ 725 { 726 HostPort: 8080, 727 ContainerPort: 8080, 728 }, 729 { 730 HostPort: 0, 731 ContainerPort: 80, 732 }, 733 }, 734 want: []types.PortMapping{ 735 { 736 HostPort: 8080, 737 ContainerPort: 8080, 738 Protocol: "tcp", 739 Range: 1, 740 }, 741 { 742 HostPort: 0, 743 ContainerPort: 80, 744 Protocol: "tcp", 745 Range: 1, 746 }, 747 }, 748 resetHostPorts: []int{1}, 749 }, 750 { 751 name: "three ports without host ports, one with a hostport set, , inverted order", 752 arg: []types.PortMapping{ 753 { 754 HostPort: 0, 755 ContainerPort: 80, 756 }, 757 { 758 HostPort: 0, 759 ContainerPort: 85, 760 }, 761 { 762 HostPort: 0, 763 ContainerPort: 90, 764 }, 765 { 766 HostPort: 8080, 767 ContainerPort: 8080, 768 }, 769 }, 770 want: []types.PortMapping{ 771 { 772 HostPort: 8080, 773 ContainerPort: 8080, 774 Protocol: "tcp", 775 Range: 1, 776 }, 777 { 778 HostPort: 0, 779 ContainerPort: 80, 780 Protocol: "tcp", 781 Range: 1, 782 }, 783 { 784 HostPort: 0, 785 ContainerPort: 85, 786 Protocol: "tcp", 787 Range: 1, 788 }, 789 { 790 HostPort: 0, 791 ContainerPort: 90, 792 Protocol: "tcp", 793 Range: 1, 794 }, 795 }, 796 resetHostPorts: []int{1, 2, 3}, 797 }, 798 { 799 name: "three ports without host ports, one with a hostport set", 800 arg: []types.PortMapping{ 801 { 802 HostPort: 8080, 803 ContainerPort: 8080, 804 }, 805 { 806 HostPort: 0, 807 ContainerPort: 90, 808 }, 809 { 810 HostPort: 0, 811 ContainerPort: 85, 812 }, 813 { 814 HostPort: 0, 815 ContainerPort: 80, 816 }, 817 }, 818 want: []types.PortMapping{ 819 { 820 HostPort: 8080, 821 ContainerPort: 8080, 822 Protocol: "tcp", 823 Range: 1, 824 }, 825 { 826 HostPort: 0, 827 ContainerPort: 80, 828 Protocol: "tcp", 829 Range: 1, 830 }, 831 { 832 HostPort: 0, 833 ContainerPort: 85, 834 Protocol: "tcp", 835 Range: 1, 836 }, 837 { 838 HostPort: 0, 839 ContainerPort: 90, 840 Protocol: "tcp", 841 Range: 1, 842 }, 843 }, 844 resetHostPorts: []int{1, 2, 3}, 845 }, 846 } 847 for _, tt := range tests { 848 tt := tt 849 t.Run(tt.name, func(t *testing.T) { 850 got, err := ParsePortMapping(tt.arg, nil) 851 assert.NoError(t, err, "error is not nil") 852 853 // because we always get random host ports when it is set to 0 we cannot check that exactly 854 // use resetHostPorts to know which port element is 0 855 for _, num := range tt.resetHostPorts { 856 assert.Greater(t, got[num].HostPort, uint16(0), "host port is zero") 857 got[num].HostPort = 0 858 } 859 860 assert.Equal(t, tt.want, got, "got unexpected port mapping") 861 }) 862 } 863 } 864 865 func TestParsePortMappingError(t *testing.T) { 866 tests := []struct { 867 name string 868 arg []types.PortMapping 869 err string 870 }{ 871 { 872 name: "container port is 0", 873 arg: []types.PortMapping{ 874 { 875 HostPort: 8080, 876 ContainerPort: 0, 877 Protocol: "tcp", 878 }, 879 }, 880 err: "container port number must be non-0", 881 }, 882 { 883 name: "container port range exceeds max", 884 arg: []types.PortMapping{ 885 { 886 HostPort: 8080, 887 ContainerPort: 65000, 888 Protocol: "tcp", 889 Range: 10000, 890 }, 891 }, 892 err: "container port range exceeds maximum allowable port number", 893 }, 894 { 895 name: "host port range exceeds max", 896 arg: []types.PortMapping{ 897 { 898 HostPort: 60000, 899 ContainerPort: 1, 900 Protocol: "tcp", 901 Range: 10000, 902 }, 903 }, 904 err: "host port range exceeds maximum allowable port number", 905 }, 906 { 907 name: "invalid protocol", 908 arg: []types.PortMapping{ 909 { 910 HostPort: 8080, 911 ContainerPort: 80, 912 Protocol: "1", 913 }, 914 }, 915 err: "unrecognized protocol \"1\" in port mapping", 916 }, 917 { 918 name: "invalid protocol 2", 919 arg: []types.PortMapping{ 920 { 921 HostPort: 8080, 922 ContainerPort: 80, 923 Protocol: "udp,u", 924 }, 925 }, 926 err: "unrecognized protocol \"u\" in port mapping", 927 }, 928 { 929 name: "invalid ip address", 930 arg: []types.PortMapping{ 931 { 932 HostPort: 8080, 933 ContainerPort: 80, 934 HostIP: "blah", 935 }, 936 }, 937 err: "invalid IP address \"blah\" in port mapping", 938 }, 939 { 940 name: "invalid overalpping range", 941 arg: []types.PortMapping{ 942 { 943 HostPort: 8080, 944 ContainerPort: 80, 945 Range: 5, 946 }, 947 { 948 HostPort: 8081, 949 ContainerPort: 60, 950 }, 951 }, 952 err: "conflicting port mappings for host port 8081 (protocol tcp)", 953 }, 954 { 955 name: "big port range with host port zero does not fit", 956 arg: []types.PortMapping{ 957 { 958 HostPort: 0, 959 ContainerPort: 1, 960 Range: 65535, 961 }, 962 }, 963 err: "failed to find an open port to expose container port 1 with range 65535 on the host", 964 }, 965 { 966 name: "big port range with host port zero does not fit", 967 arg: []types.PortMapping{ 968 { 969 HostPort: 0, 970 ContainerPort: 80, 971 Range: 1, 972 }, 973 { 974 HostPort: 0, 975 ContainerPort: 1000, 976 Range: 64535, 977 }, 978 }, 979 err: "failed to find an open port to expose container port 1000 with range 64535 on the host", 980 }, 981 } 982 for _, tt := range tests { 983 tt := tt 984 t.Run(tt.name, func(t *testing.T) { 985 _, err := ParsePortMapping(tt.arg, nil) 986 assert.EqualError(t, err, tt.err, "error does not match") 987 }) 988 } 989 }