blob: d2e700be9e01aa14ffc97f056f36db1edbda0f37 [file]
package types
import (
"net"
"strconv"
"testing"
cerrdefs "github.com/containerd/errdefs"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestErrorConstructors(t *testing.T) {
var err error
var ok bool
err = InvalidParameterErrorf("Io ho %d uccello", 1)
assert.Check(t, is.Error(err, "Io ho 1 uccello"))
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = NotFoundErrorf("Can't find the %s", "keys")
assert.Check(t, is.Error(err, "Can't find the keys"))
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotFound))
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = ForbiddenErrorf("Can't open door %d", 2)
assert.Check(t, is.Error(err, "Can't open door 2"))
assert.Check(t, is.ErrorType(err, cerrdefs.IsPermissionDenied))
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = NotImplementedErrorf("Functionality %s is not implemented", "x")
assert.Check(t, is.Error(err, "Functionality x is not implemented"))
assert.Check(t, is.ErrorType(err, cerrdefs.IsNotImplemented))
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = UnavailableErrorf("Driver %s is not available", "mh")
assert.Check(t, is.Error(err, "Driver mh is not available"))
assert.Check(t, is.ErrorType(err, cerrdefs.IsUnavailable))
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = InternalErrorf("Not sure what happened")
assert.Check(t, is.Error(err, "Not sure what happened"))
_, ok = err.(InternalError)
assert.Check(t, ok, "error should be InternalError: %[1]v (%[1]T)", err)
_, ok = err.(MaskableError)
assert.Check(t, !ok, "error should not be maskable: %[1]v (%[1]T)", err)
err = InternalMaskableErrorf("Minor issue, it can be ignored")
assert.Check(t, is.Error(err, "Minor issue, it can be ignored"))
_, ok = err.(InternalError)
assert.Check(t, ok, "error should be InternalError: %[1]v (%[1]T)", err)
_, ok = err.(MaskableError)
assert.Check(t, ok, "error should be maskable: %[1]v (%[1]T)", err)
}
func TestCompareIPMask(t *testing.T) {
tests := []struct {
ip net.IP
mask net.IPMask
is int
ms int
isErr bool
}{
{ // ip in v4Inv6 representation, mask in v4 representation
ip: net.IPv4(172, 28, 30, 1),
mask: []byte{0xff, 0xff, 0xff, 0},
is: 12,
ms: 0,
},
{ // ip and mask in v4Inv6 representation
ip: net.IPv4(172, 28, 30, 2),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
is: 12,
ms: 12,
},
{ // ip in v4 representation, mask in v4Inv6 representation
ip: net.IPv4(172, 28, 30, 3)[12:],
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
is: 0,
ms: 12,
},
{ // ip and mask in v4 representation
ip: net.IPv4(172, 28, 30, 4)[12:],
mask: []byte{0xff, 0xff, 0xff, 0},
is: 0,
ms: 0,
},
{ // ip and mask as v6
ip: net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0},
is: 0,
ms: 0,
},
{
ip: net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"),
mask: []byte{0xff, 0xff, 0xff, 0},
isErr: true,
},
{
ip: net.ParseIP("173.32.4.5"),
mask: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0},
isErr: true,
},
{
ip: net.ParseIP("173.32.4.5"),
mask: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
isErr: true,
},
}
for i, tc := range tests {
t.Run(strconv.Itoa(i), func(t *testing.T) {
actualIs, actualMs, err := compareIPMask(tc.ip, tc.mask)
if tc.isErr {
const expectedErr = "ip and mask are not compatible"
assert.Check(t, is.ErrorContains(err, expectedErr))
} else {
assert.NilError(t, err)
assert.Check(t, is.Equal(actualIs, tc.is))
assert.Check(t, is.Equal(actualMs, tc.ms))
}
})
}
}
func TestGetHostPartIP(t *testing.T) {
tests := []struct {
ip net.IP
mask net.IPMask
host net.IP
err error
}{
{ // ip in v4Inv6 representation, mask in v4 representation
ip: net.IPv4(172, 28, 30, 1),
mask: []byte{0xff, 0xff, 0xff, 0},
host: net.IPv4(0, 0, 0, 1),
},
{ // ip and mask in v4Inv6 representation
ip: net.IPv4(172, 28, 30, 2),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
host: net.IPv4(0, 0, 0, 2),
},
{ // ip in v4 representation, mask in v4Inv6 representation
ip: net.IPv4(172, 28, 30, 3)[12:],
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
host: net.IPv4(0, 0, 0, 3)[12:],
},
{ // ip and mask in v4 representation
ip: net.IPv4(172, 28, 30, 4)[12:],
mask: []byte{0xff, 0xff, 0xff, 0},
host: net.IPv4(0, 0, 0, 4)[12:],
},
{ // ip and mask as v6
ip: net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0},
host: net.ParseIP("0::AB:00CD"),
},
}
for _, tc := range tests {
h, err := GetHostPartIP(tc.ip, tc.mask)
assert.NilError(t, err)
assert.Assert(t, tc.host.Equal(h), "Failed to return expected host ip. Expected: %s. Got: %s", tc.host, h)
}
const expectedErr = "cannot compute host portion ip address because ip and mask are not compatible"
// ip as v6 and mask as v4 are not compatible
_, err := GetHostPartIP(net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"), []byte{0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
// ip as v4 and non conventional mask
_, err = GetHostPartIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
// ip as v4 and non conventional mask
_, err = GetHostPartIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
}
func TestGetBroadcastIP(t *testing.T) {
tests := []struct {
ip net.IP
mask net.IPMask
bcast net.IP
err error
}{
// ip in v4Inv6 representation, mask in v4 representation
{
ip: net.IPv4(172, 28, 30, 1),
mask: []byte{0xff, 0xff, 0xff, 0},
bcast: net.IPv4(172, 28, 30, 255),
},
{
ip: net.IPv4(10, 28, 30, 1),
mask: []byte{0xff, 0, 0, 0},
bcast: net.IPv4(10, 255, 255, 255),
},
// ip and mask in v4Inv6 representation
{
ip: net.IPv4(172, 28, 30, 2),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
bcast: net.IPv4(172, 28, 30, 255),
},
{
ip: net.IPv4(172, 28, 30, 2),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0},
bcast: net.IPv4(172, 28, 255, 255),
},
// ip in v4 representation, mask in v4Inv6 representation
{
ip: net.IPv4(172, 28, 30, 3)[12:],
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0},
bcast: net.IPv4(172, 28, 30, 255)[12:],
},
{
ip: net.IPv4(172, 28, 30, 3)[12:],
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0},
bcast: net.IPv4(172, 255, 255, 255)[12:],
},
// ip and mask in v4 representation
{
ip: net.IPv4(172, 28, 30, 4)[12:],
mask: []byte{0xff, 0xff, 0xff, 0},
bcast: net.IPv4(172, 28, 30, 255)[12:],
},
{
ip: net.IPv4(172, 28, 30, 4)[12:],
mask: []byte{0xff, 0xff, 0, 0},
bcast: net.IPv4(172, 28, 255, 255)[12:],
},
{ // ip and mask as v6
ip: net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"),
mask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0},
bcast: net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEFF:FFFF"),
},
}
for _, tc := range tests {
h, err := GetBroadcastIP(tc.ip, tc.mask)
assert.NilError(t, err)
assert.Assert(t, tc.bcast.Equal(h), "Failed to return expected host ip. Expected: %s. Got: %s", tc.bcast, h)
}
const expectedErr = "cannot compute broadcast ip address because ip and mask are not compatible"
// ip as v6 and mask as v4 are not compatible
_, err := GetBroadcastIP(net.ParseIP("2001:DB8:2002:2001:FFFF:ABCD:EEAB:00CD"), []byte{0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
// ip as v4 and non conventional mask
_, err = GetBroadcastIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
// ip as v4 and non conventional mask
_, err = GetBroadcastIP(net.ParseIP("173.32.4.5"), []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0})
assert.Check(t, is.ErrorContains(err, expectedErr))
}
func TestParseCIDR(t *testing.T) {
input := []struct {
cidr string
ipnw *net.IPNet
}{
{"192.168.22.44/16", &net.IPNet{IP: net.IP{192, 168, 22, 44}, Mask: net.IPMask{255, 255, 0, 0}}},
{"10.10.2.0/24", &net.IPNet{IP: net.IP{10, 10, 2, 0}, Mask: net.IPMask{255, 255, 255, 0}}},
{"10.0.0.100/17", &net.IPNet{IP: net.IP{10, 0, 0, 100}, Mask: net.IPMask{255, 255, 128, 0}}},
}
for _, i := range input {
nw, err := ParseCIDR(i.cidr)
if err != nil {
t.Fatal(err)
}
if !CompareIPNet(nw, i.ipnw) {
t.Fatalf("network differ. Expected %v. Got: %v", i.ipnw, nw)
}
}
}