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