358 lines
9.4 KiB
Go
358 lines
9.4 KiB
Go
package allregions
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func makeAddrSet(addrs []*EdgeAddr) AddrSet {
|
|
addrSet := make(AddrSet, len(addrs))
|
|
for _, addr := range addrs {
|
|
addrSet[addr] = Unused()
|
|
}
|
|
return addrSet
|
|
}
|
|
|
|
func TestRegion_New(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
addrs []*EdgeAddr
|
|
mode ConfigIPVersion
|
|
expectedAddrs int
|
|
primary AddrSet
|
|
secondary AddrSet
|
|
}{
|
|
{
|
|
name: "IPv4 addresses with IPv4Only",
|
|
addrs: v4Addrs,
|
|
mode: IPv4Only,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: AddrSet{},
|
|
},
|
|
{
|
|
name: "IPv6 addresses with IPv4Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv4Only,
|
|
expectedAddrs: 0,
|
|
primary: AddrSet{},
|
|
secondary: AddrSet{},
|
|
},
|
|
{
|
|
name: "IPv6 addresses with IPv6Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv6Only,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: AddrSet{},
|
|
},
|
|
{
|
|
name: "IPv6 addresses with IPv4Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv4Only,
|
|
expectedAddrs: 0,
|
|
primary: AddrSet{},
|
|
secondary: AddrSet{},
|
|
},
|
|
{
|
|
name: "IPv4 (first) and IPv6 addresses with Auto",
|
|
addrs: append(v4Addrs, v6Addrs...),
|
|
mode: Auto,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: makeAddrSet(v6Addrs),
|
|
},
|
|
{
|
|
name: "IPv6 (first) and IPv4 addresses with Auto",
|
|
addrs: append(v6Addrs, v4Addrs...),
|
|
mode: Auto,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: makeAddrSet(v4Addrs),
|
|
},
|
|
{
|
|
name: "IPv4 addresses with Auto",
|
|
addrs: v4Addrs,
|
|
mode: Auto,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: AddrSet{},
|
|
},
|
|
{
|
|
name: "IPv6 addresses with Auto",
|
|
addrs: v6Addrs,
|
|
mode: Auto,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: AddrSet{},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
assert.Equal(t, tt.expectedAddrs, r.AvailableAddrs())
|
|
assert.Equal(t, tt.primary, r.primary)
|
|
assert.Equal(t, tt.secondary, r.secondary)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegion_AnyAddress_EmptyActiveSet(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
addrs []*EdgeAddr
|
|
mode ConfigIPVersion
|
|
}{
|
|
{
|
|
name: "IPv6 addresses with IPv4Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv4Only,
|
|
},
|
|
{
|
|
name: "IPv4 addresses with IPv6Only",
|
|
addrs: v4Addrs,
|
|
mode: IPv6Only,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
addr := r.GetAnyAddress()
|
|
assert.Nil(t, addr)
|
|
addr = r.AssignAnyAddress(0, nil)
|
|
assert.Nil(t, addr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegion_AssignAnyAddress_FullyUsedActiveSet(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
addrs []*EdgeAddr
|
|
mode ConfigIPVersion
|
|
}{
|
|
{
|
|
name: "IPv6 addresses with IPv6Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv6Only,
|
|
},
|
|
{
|
|
name: "IPv4 addresses with IPv4Only",
|
|
addrs: v4Addrs,
|
|
mode: IPv4Only,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
total := r.active.AvailableAddrs()
|
|
for i := 0; i < total; i++ {
|
|
addr := r.AssignAnyAddress(i, nil)
|
|
assert.NotNil(t, addr)
|
|
}
|
|
addr := r.AssignAnyAddress(9, nil)
|
|
assert.Nil(t, addr)
|
|
})
|
|
}
|
|
}
|
|
|
|
var giveBackTests = []struct {
|
|
name string
|
|
addrs []*EdgeAddr
|
|
mode ConfigIPVersion
|
|
expectedAddrs int
|
|
primary AddrSet
|
|
secondary AddrSet
|
|
primarySwap bool
|
|
}{
|
|
{
|
|
name: "IPv4 addresses with IPv4Only",
|
|
addrs: v4Addrs,
|
|
mode: IPv4Only,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: AddrSet{},
|
|
primarySwap: false,
|
|
},
|
|
{
|
|
name: "IPv6 addresses with IPv6Only",
|
|
addrs: v6Addrs,
|
|
mode: IPv6Only,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: AddrSet{},
|
|
primarySwap: false,
|
|
},
|
|
{
|
|
name: "IPv4 (first) and IPv6 addresses with Auto",
|
|
addrs: append(v4Addrs, v6Addrs...),
|
|
mode: Auto,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: makeAddrSet(v6Addrs),
|
|
primarySwap: false,
|
|
},
|
|
{
|
|
name: "IPv6 (first) and IPv4 addresses with Auto",
|
|
addrs: append(v6Addrs, v4Addrs...),
|
|
mode: Auto,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: makeAddrSet(v4Addrs),
|
|
primarySwap: true,
|
|
},
|
|
{
|
|
name: "IPv4 addresses with Auto",
|
|
addrs: v4Addrs,
|
|
mode: Auto,
|
|
expectedAddrs: len(v4Addrs),
|
|
primary: makeAddrSet(v4Addrs),
|
|
secondary: AddrSet{},
|
|
primarySwap: false,
|
|
},
|
|
{
|
|
name: "IPv6 addresses with Auto",
|
|
addrs: v6Addrs,
|
|
mode: Auto,
|
|
expectedAddrs: len(v6Addrs),
|
|
primary: makeAddrSet(v6Addrs),
|
|
secondary: AddrSet{},
|
|
primarySwap: false,
|
|
},
|
|
}
|
|
|
|
func TestRegion_GiveBack_NoConnectivityError(t *testing.T) {
|
|
for _, tt := range giveBackTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
addr := r.AssignAnyAddress(0, nil)
|
|
assert.NotNil(t, addr)
|
|
assert.True(t, r.GiveBack(addr, false))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegion_GiveBack_ForeignAddr(t *testing.T) {
|
|
invalid := EdgeAddr{
|
|
TCP: &net.TCPAddr{
|
|
IP: net.ParseIP("123.4.5.0"),
|
|
Port: 8000,
|
|
Zone: "",
|
|
},
|
|
UDP: &net.UDPAddr{
|
|
IP: net.ParseIP("123.4.5.0"),
|
|
Port: 8000,
|
|
Zone: "",
|
|
},
|
|
IPVersion: V4,
|
|
}
|
|
for _, tt := range giveBackTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
assert.False(t, r.GiveBack(&invalid, false))
|
|
assert.False(t, r.GiveBack(&invalid, true))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegion_GiveBack_SwapPrimary(t *testing.T) {
|
|
for _, tt := range giveBackTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
r := NewRegion(tt.addrs, tt.mode)
|
|
addr := r.AssignAnyAddress(0, nil)
|
|
assert.NotNil(t, addr)
|
|
assert.True(t, r.GiveBack(addr, true))
|
|
assert.Equal(t, tt.primarySwap, !r.primaryIsActive)
|
|
if tt.primarySwap {
|
|
assert.Equal(t, r.secondary, r.active)
|
|
assert.False(t, r.primaryTimeout.IsZero())
|
|
} else {
|
|
assert.Equal(t, r.primary, r.active)
|
|
assert.True(t, r.primaryTimeout.IsZero())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRegion_GiveBack_IPv4_ResetPrimary(t *testing.T) {
|
|
r := NewRegion(append(v6Addrs, v4Addrs...), Auto)
|
|
// Exhaust all IPv6 addresses
|
|
a0 := r.AssignAnyAddress(0, nil)
|
|
a1 := r.AssignAnyAddress(1, nil)
|
|
a2 := r.AssignAnyAddress(2, nil)
|
|
a3 := r.AssignAnyAddress(3, nil)
|
|
assert.NotNil(t, a0)
|
|
assert.NotNil(t, a1)
|
|
assert.NotNil(t, a2)
|
|
assert.NotNil(t, a3)
|
|
// Give back the first IPv6 address to fallback to secondary IPv4 address set
|
|
assert.True(t, r.GiveBack(a0, true))
|
|
assert.False(t, r.primaryIsActive)
|
|
// Give back another IPv6 address
|
|
assert.True(t, r.GiveBack(a1, true))
|
|
// Primary shouldn't change
|
|
assert.False(t, r.primaryIsActive)
|
|
// Request an address (should be IPv4 from secondary)
|
|
a4_v4 := r.AssignAnyAddress(4, nil)
|
|
assert.NotNil(t, a4_v4)
|
|
assert.Equal(t, V4, a4_v4.IPVersion)
|
|
a5_v4 := r.AssignAnyAddress(5, nil)
|
|
assert.NotNil(t, a5_v4)
|
|
assert.Equal(t, V4, a5_v4.IPVersion)
|
|
a6_v4 := r.AssignAnyAddress(6, nil)
|
|
assert.NotNil(t, a6_v4)
|
|
assert.Equal(t, V4, a6_v4.IPVersion)
|
|
// Return IPv4 address (without failure)
|
|
// Primary shouldn't change because it is not a connectivity failure
|
|
assert.True(t, r.GiveBack(a4_v4, false))
|
|
assert.False(t, r.primaryIsActive)
|
|
// Return IPv4 address (with failure)
|
|
// Primary should change because it is a connectivity failure
|
|
assert.True(t, r.GiveBack(a5_v4, true))
|
|
assert.True(t, r.primaryIsActive)
|
|
// Return IPv4 address (with failure)
|
|
// Primary shouldn't change because the address is returned to the inactive
|
|
// secondary address set
|
|
assert.True(t, r.GiveBack(a6_v4, true))
|
|
assert.True(t, r.primaryIsActive)
|
|
// Return IPv6 address (without failure)
|
|
// Primary shoudn't change because it is not a connectivity failure
|
|
assert.True(t, r.GiveBack(a2, false))
|
|
assert.True(t, r.primaryIsActive)
|
|
}
|
|
|
|
func TestRegion_GiveBack_Timeout(t *testing.T) {
|
|
r := NewRegion(append(v6Addrs, v4Addrs...), Auto)
|
|
a0 := r.AssignAnyAddress(0, nil)
|
|
a1 := r.AssignAnyAddress(1, nil)
|
|
a2 := r.AssignAnyAddress(2, nil)
|
|
assert.NotNil(t, a0)
|
|
assert.NotNil(t, a1)
|
|
assert.NotNil(t, a2)
|
|
// Give back IPv6 address to set timeout
|
|
assert.True(t, r.GiveBack(a0, true))
|
|
assert.False(t, r.primaryIsActive)
|
|
assert.False(t, r.primaryTimeout.IsZero())
|
|
// Request an address (should be IPv4 from secondary)
|
|
a3_v4 := r.AssignAnyAddress(3, nil)
|
|
assert.NotNil(t, a3_v4)
|
|
assert.Equal(t, V4, a3_v4.IPVersion)
|
|
assert.False(t, r.primaryIsActive)
|
|
// Give back IPv6 address inside timeout (no change)
|
|
assert.True(t, r.GiveBack(a2, true))
|
|
assert.False(t, r.primaryIsActive)
|
|
assert.False(t, r.primaryTimeout.IsZero())
|
|
// Accelerate timeout
|
|
r.primaryTimeout = time.Now().Add(-time.Minute)
|
|
// Return IPv6 address
|
|
assert.True(t, r.GiveBack(a1, true))
|
|
assert.True(t, r.primaryIsActive)
|
|
// Returning an IPv4 address after primary is active shouldn't change primary
|
|
// even with a connectivity error
|
|
assert.True(t, r.GiveBack(a3_v4, true))
|
|
assert.True(t, r.primaryIsActive)
|
|
}
|