Files
podman/pkg/specgen/generate/ports_test.go
Paul Holzinger f93fcf7dee bump go to 1.22
Many dependencies started using go 1.22 which means we have to follow in
order to update.

Disable the now depracted exportloopref linter as it was replaced by
copyloopvar as go fixed the loop copy problem in 1.22[1]

Another new chnage in go 1.22 is the for loop syntax over ints, the
intrange linter chacks for this but there a lot of loops that have to be
converted so I didn't do it here and disable th elinter for now, th eold
syntax is still fine.

[1] https://go.dev/blog/loopvar-preview

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2024-09-03 15:14:15 +02:00

988 lines
18 KiB
Go

//go:build !remote
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 {
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 {
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 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 {
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 {
t.Run(tt.name, func(t *testing.T) {
_, err := ParsePortMapping(tt.arg, nil)
assert.EqualError(t, err, tt.err, "error does not match")
})
}
}