mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 00:39:57 +00:00
TUN-6007: Implement new edge discovery algorithm
This commit is contained in:
@@ -1,284 +1,357 @@
|
||||
package allregions
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"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) {
|
||||
r := NewRegion([]*EdgeAddr{&addr0, &addr1, &addr2})
|
||||
if r.AvailableAddrs() != 3 {
|
||||
t.Errorf("r.AvailableAddrs() == %v but want 3", r.AvailableAddrs())
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegion_AddrUsedBy(t *testing.T) {
|
||||
type fields struct {
|
||||
connFor map[*EdgeAddr]UsedBy
|
||||
}
|
||||
type args struct {
|
||||
connID int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *EdgeAddr
|
||||
name string
|
||||
addrs []*EdgeAddr
|
||||
mode ConfigIPVersion
|
||||
expectedAddrs int
|
||||
primary AddrSet
|
||||
secondary AddrSet
|
||||
}{
|
||||
{
|
||||
name: "happy trivial test",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
}},
|
||||
args: args{connID: 0},
|
||||
want: &addr0,
|
||||
name: "IPv4 addresses with IPv4Only",
|
||||
addrs: v4Addrs,
|
||||
mode: IPv4Only,
|
||||
expectedAddrs: len(v4Addrs),
|
||||
primary: makeAddrSet(v4Addrs),
|
||||
secondary: AddrSet{},
|
||||
},
|
||||
{
|
||||
name: "sad trivial test",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
}},
|
||||
args: args{connID: 1},
|
||||
want: nil,
|
||||
name: "IPv6 addresses with IPv4Only",
|
||||
addrs: v6Addrs,
|
||||
mode: IPv4Only,
|
||||
expectedAddrs: 0,
|
||||
primary: AddrSet{},
|
||||
secondary: AddrSet{},
|
||||
},
|
||||
{
|
||||
name: "sad test",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: InUse(1),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{connID: 3},
|
||||
want: nil,
|
||||
name: "IPv6 addresses with IPv6Only",
|
||||
addrs: v6Addrs,
|
||||
mode: IPv6Only,
|
||||
expectedAddrs: len(v6Addrs),
|
||||
primary: makeAddrSet(v6Addrs),
|
||||
secondary: AddrSet{},
|
||||
},
|
||||
{
|
||||
name: "happy test",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: InUse(1),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{connID: 1},
|
||||
want: &addr1,
|
||||
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 := &Region{
|
||||
connFor: tt.fields.connFor,
|
||||
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)
|
||||
}
|
||||
if got := r.AddrUsedBy(tt.args.connID); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Region.AddrUsedBy() = %v, want %v", got, tt.want)
|
||||
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_AvailableAddrs(t *testing.T) {
|
||||
type fields struct {
|
||||
connFor map[*EdgeAddr]UsedBy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "contains addresses",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: Unused(),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
want: 1,
|
||||
},
|
||||
{
|
||||
name: "all free",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: Unused(),
|
||||
&addr1: Unused(),
|
||||
&addr2: Unused(),
|
||||
}},
|
||||
want: 3,
|
||||
},
|
||||
{
|
||||
name: "all used",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: InUse(1),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
want: 0,
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{}},
|
||||
want: 0,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := Region{
|
||||
connFor: tt.fields.connFor,
|
||||
}
|
||||
if got := r.AvailableAddrs(); got != tt.want {
|
||||
t.Errorf("Region.AvailableAddrs() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
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_GetUnusedIP(t *testing.T) {
|
||||
type fields struct {
|
||||
connFor map[*EdgeAddr]UsedBy
|
||||
}
|
||||
type args struct {
|
||||
excluding *EdgeAddr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want *EdgeAddr
|
||||
}{
|
||||
{
|
||||
name: "happy test with excluding set",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: Unused(),
|
||||
&addr1: Unused(),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{excluding: &addr0},
|
||||
want: &addr1,
|
||||
},
|
||||
{
|
||||
name: "happy test with no excluding",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: Unused(),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{excluding: nil},
|
||||
want: &addr1,
|
||||
},
|
||||
{
|
||||
name: "sad test with no excluding",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(0),
|
||||
&addr1: InUse(1),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{excluding: nil},
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "sad test with excluding",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: Unused(),
|
||||
&addr1: InUse(1),
|
||||
&addr2: InUse(2),
|
||||
}},
|
||||
args: args{excluding: &addr0},
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := Region{
|
||||
connFor: tt.fields.connFor,
|
||||
}
|
||||
if got := r.GetUnusedIP(tt.args.excluding); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("Region.GetUnusedIP() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegion_GiveBack(t *testing.T) {
|
||||
type fields struct {
|
||||
connFor map[*EdgeAddr]UsedBy
|
||||
}
|
||||
type args struct {
|
||||
addr *EdgeAddr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantOk bool
|
||||
availableAfter int
|
||||
}{
|
||||
{
|
||||
name: "sad test with excluding",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr1: InUse(1),
|
||||
}},
|
||||
args: args{addr: &addr1},
|
||||
wantOk: true,
|
||||
availableAfter: 1,
|
||||
},
|
||||
{
|
||||
name: "sad test with excluding",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr1: InUse(1),
|
||||
}},
|
||||
args: args{addr: &addr2},
|
||||
wantOk: false,
|
||||
availableAfter: 0,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := Region{
|
||||
connFor: tt.fields.connFor,
|
||||
}
|
||||
if gotOk := r.GiveBack(tt.args.addr); gotOk != tt.wantOk {
|
||||
t.Errorf("Region.GiveBack() = %v, want %v", gotOk, tt.wantOk)
|
||||
}
|
||||
if tt.availableAfter != r.AvailableAddrs() {
|
||||
t.Errorf("Region.AvailableAddrs() = %v, want %v", r.AvailableAddrs(), tt.availableAfter)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegion_GetAnyAddress(t *testing.T) {
|
||||
type fields struct {
|
||||
connFor map[*EdgeAddr]UsedBy
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantNil bool
|
||||
}{
|
||||
{
|
||||
name: "Sad test -- GetAnyAddress should only fail if the region is empty",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{}},
|
||||
wantNil: true,
|
||||
},
|
||||
{
|
||||
name: "Happy test (all addresses unused)",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: Unused(),
|
||||
}},
|
||||
wantNil: false,
|
||||
},
|
||||
{
|
||||
name: "Happy test (GetAnyAddress can still return addresses used by proxy conns)",
|
||||
fields: fields{connFor: map[*EdgeAddr]UsedBy{
|
||||
&addr0: InUse(2),
|
||||
}},
|
||||
wantNil: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
r := Region{
|
||||
connFor: tt.fields.connFor,
|
||||
}
|
||||
if got := r.GetAnyAddress(); tt.wantNil != (got == nil) {
|
||||
t.Errorf("Region.GetAnyAddress() = %v, but should it return nil? %v", got, tt.wantNil)
|
||||
}
|
||||
})
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
Reference in New Issue
Block a user