Files
podman/pkg/specgen/generate/ports_test.go
Paul Holzinger 495884b319 use libnetwork from c/common
The libpod/network packages were moved to c/common so that buildah can
use it as well. To prevent duplication use it in podman as well and
remove it from here.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2022-01-12 17:07:30 +01:00

990 lines
18 KiB
Go

package generate
import (
"testing"
"github.com/containers/common/libnetwork/types"
"github.com/stretchr/testify/assert"
)
func TestParsePortMappingWithHostPort(t *testing.T) {
tests := []struct {
name string
arg []types.PortMapping
arg2 map[uint16][]string
want []types.PortMapping
}{
{
name: "no ports",
arg: nil,
want: nil,
},
{
name: "one tcp port",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "one tcp port no proto",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "one udp port",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "udp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "udp",
Range: 1,
},
},
},
{
name: "one sctp port",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "sctp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "sctp",
Range: 1,
},
},
},
{
name: "one port two protocols",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp,udp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "udp",
Range: 1,
},
},
},
{
name: "one port three protocols",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp,udp,sctp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "udp",
Range: 1,
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "sctp",
Range: 1,
},
},
},
{
name: "one port with range 1",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "one port with range 5",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 5,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 5,
},
},
},
{
name: "two ports joined",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
},
{
HostPort: 8081,
ContainerPort: 81,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 2,
},
},
},
{
name: "two ports joined with range",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 2,
},
{
HostPort: 8081,
ContainerPort: 81,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 2,
},
},
},
{
name: "two ports with no overlapping range",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 9090,
ContainerPort: 9090,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 9090,
ContainerPort: 9090,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
},
},
{
name: "four ports with two overlapping ranges",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 8085,
ContainerPort: 85,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 100,
ContainerPort: 5,
Protocol: "tcp",
},
{
HostPort: 101,
ContainerPort: 6,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 15,
},
{
HostPort: 100,
ContainerPort: 5,
Protocol: "tcp",
Range: 2,
},
},
},
{
name: "two overlapping ranges",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 8085,
ContainerPort: 85,
Protocol: "tcp",
Range: 2,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
},
},
{
name: "four overlapping ranges",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 8085,
ContainerPort: 85,
Protocol: "tcp",
Range: 2,
},
{
HostPort: 8090,
ContainerPort: 90,
Protocol: "tcp",
Range: 7,
},
{
HostPort: 8095,
ContainerPort: 95,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 17,
},
},
},
{
name: "one port range overlaps 5 ports",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Range: 20,
},
{
HostPort: 8085,
ContainerPort: 85,
Range: 2,
},
{
HostPort: 8090,
ContainerPort: 90,
},
{
HostPort: 8095,
ContainerPort: 95,
},
{
HostPort: 8096,
ContainerPort: 96,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
Range: 20,
},
},
},
{
name: "different host ip same port",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
HostIP: "192.168.1.1",
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
HostIP: "192.168.2.1",
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
HostIP: "192.168.1.1",
Range: 1,
},
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "tcp",
HostIP: "192.168.2.1",
Range: 1,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, err := ParsePortMapping(tt.arg, tt.arg2)
assert.NoError(t, err, "error is not nil")
// use ElementsMatch instead of Equal because the order is not consistent
assert.ElementsMatch(t, tt.want, got, "got unexpected port mapping")
})
}
}
func TestParsePortMappingWithoutHostPort(t *testing.T) {
tests := []struct {
name string
arg []types.PortMapping
arg2 map[uint16][]string
want []types.PortMapping
}{
{
name: "one tcp port",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "one port with two protocols",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp,udp",
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "udp",
Range: 1,
},
},
},
{
name: "same port twice",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "neighbor ports are not joined",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
},
{
HostPort: 0,
ContainerPort: 81,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 81,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "overlapping range ports are joined",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 2,
},
{
HostPort: 0,
ContainerPort: 81,
Protocol: "tcp",
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 2,
},
},
},
{
name: "four overlapping range ports are joined",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 3,
},
{
HostPort: 0,
ContainerPort: 81,
Protocol: "tcp",
},
{
HostPort: 0,
ContainerPort: 82,
Protocol: "tcp",
Range: 10,
},
{
HostPort: 0,
ContainerPort: 90,
Protocol: "tcp",
Range: 5,
},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 15,
},
},
},
{
name: "expose one tcp port",
arg2: map[uint16][]string{
8080: {"tcp"},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "expose already defined port",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "tcp",
},
},
arg2: map[uint16][]string{
8080: {"tcp"},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
},
},
{
name: "expose different proto",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "tcp",
},
},
arg2: map[uint16][]string{
8080: {"udp"},
},
want: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 8080,
Protocol: "udp",
Range: 1,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, err := ParsePortMapping(tt.arg, tt.arg2)
assert.NoError(t, err, "error is not nil")
// because we always get random host ports when it is set to 0 we cannot check that exactly
// check if it is not 0 and set to to 0 afterwards
for i := range got {
assert.Greater(t, got[i].HostPort, uint16(0), "host port is zero")
got[i].HostPort = 0
}
// use ElementsMatch instead of Equal because the order is not consistent
assert.ElementsMatch(t, tt.want, got, "got unexpected port mapping")
})
}
}
func TestParsePortMappingMixedHostPort(t *testing.T) {
tests := []struct {
name string
arg []types.PortMapping
want []types.PortMapping
resetHostPorts []int
}{
{
name: "two ports one without a hostport set",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
},
{
HostPort: 8080,
ContainerPort: 8080,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
resetHostPorts: []int{1},
},
{
name: "two ports one without a hostport set, inverted order",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
},
{
HostPort: 0,
ContainerPort: 80,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
},
resetHostPorts: []int{1},
},
{
name: "three ports without host ports, one with a hostport set, , inverted order",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
},
{
HostPort: 0,
ContainerPort: 85,
},
{
HostPort: 0,
ContainerPort: 90,
},
{
HostPort: 8080,
ContainerPort: 8080,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 85,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 90,
Protocol: "tcp",
Range: 1,
},
},
resetHostPorts: []int{1, 2, 3},
},
{
name: "three ports without host ports, one with a hostport set",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
},
{
HostPort: 0,
ContainerPort: 90,
},
{
HostPort: 0,
ContainerPort: 85,
},
{
HostPort: 0,
ContainerPort: 80,
},
},
want: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 8080,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 80,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 85,
Protocol: "tcp",
Range: 1,
},
{
HostPort: 0,
ContainerPort: 90,
Protocol: "tcp",
Range: 1,
},
},
resetHostPorts: []int{1, 2, 3},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
got, err := ParsePortMapping(tt.arg, nil)
assert.NoError(t, err, "error is not nil")
// because we always get random host ports when it is set to 0 we cannot check that exactly
// use resetHostPorts to know which port element is 0
for _, num := range tt.resetHostPorts {
assert.Greater(t, got[num].HostPort, uint16(0), "host port is zero")
got[num].HostPort = 0
}
assert.Equal(t, tt.want, got, "got unexpected port mapping")
})
}
}
func TestParsePortMappingError(t *testing.T) {
tests := []struct {
name string
arg []types.PortMapping
err string
}{
{
name: "container port is 0",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 0,
Protocol: "tcp",
},
},
err: "container port number must be non-0",
},
{
name: "container port range exceeds max",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 65000,
Protocol: "tcp",
Range: 10000,
},
},
err: "container port range exceeds maximum allowable port number",
},
{
name: "host port range exceeds max",
arg: []types.PortMapping{
{
HostPort: 60000,
ContainerPort: 1,
Protocol: "tcp",
Range: 10000,
},
},
err: "host port range exceeds maximum allowable port number",
},
{
name: "invalid protocol",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "1",
},
},
err: "unrecognized protocol \"1\" in port mapping",
},
{
name: "invalid protocol 2",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Protocol: "udp,u",
},
},
err: "unrecognized protocol \"u\" in port mapping",
},
{
name: "invalid ip address",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
HostIP: "blah",
},
},
err: "invalid IP address \"blah\" in port mapping",
},
{
name: "invalid overalpping range",
arg: []types.PortMapping{
{
HostPort: 8080,
ContainerPort: 80,
Range: 5,
},
{
HostPort: 8081,
ContainerPort: 60,
},
},
err: "conflicting port mappings for host port 8081 (protocol tcp)",
},
{
name: "big port range with host port zero does not fit",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 1,
Range: 65535,
},
},
err: "failed to find an open port to expose container port 1 with range 65535 on the host",
},
{
name: "big port range with host port zero does not fit",
arg: []types.PortMapping{
{
HostPort: 0,
ContainerPort: 80,
Range: 1,
},
{
HostPort: 0,
ContainerPort: 1000,
Range: 64535,
},
},
err: "failed to find an open port to expose container port 1000 with range 64535 on the host",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
_, err := ParsePortMapping(tt.arg, nil)
assert.EqualError(t, err, tt.err, "error does not match")
})
}
}