123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- 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)
- }
|