region_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. package allregions
  2. import (
  3. "net"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. func makeAddrSet(addrs []*EdgeAddr) AddrSet {
  9. addrSet := make(AddrSet, len(addrs))
  10. for _, addr := range addrs {
  11. addrSet[addr] = Unused()
  12. }
  13. return addrSet
  14. }
  15. func TestRegion_New(t *testing.T) {
  16. tests := []struct {
  17. name string
  18. addrs []*EdgeAddr
  19. mode ConfigIPVersion
  20. expectedAddrs int
  21. primary AddrSet
  22. secondary AddrSet
  23. }{
  24. {
  25. name: "IPv4 addresses with IPv4Only",
  26. addrs: v4Addrs,
  27. mode: IPv4Only,
  28. expectedAddrs: len(v4Addrs),
  29. primary: makeAddrSet(v4Addrs),
  30. secondary: AddrSet{},
  31. },
  32. {
  33. name: "IPv6 addresses with IPv4Only",
  34. addrs: v6Addrs,
  35. mode: IPv4Only,
  36. expectedAddrs: 0,
  37. primary: AddrSet{},
  38. secondary: AddrSet{},
  39. },
  40. {
  41. name: "IPv6 addresses with IPv6Only",
  42. addrs: v6Addrs,
  43. mode: IPv6Only,
  44. expectedAddrs: len(v6Addrs),
  45. primary: makeAddrSet(v6Addrs),
  46. secondary: AddrSet{},
  47. },
  48. {
  49. name: "IPv6 addresses with IPv4Only",
  50. addrs: v6Addrs,
  51. mode: IPv4Only,
  52. expectedAddrs: 0,
  53. primary: AddrSet{},
  54. secondary: AddrSet{},
  55. },
  56. {
  57. name: "IPv4 (first) and IPv6 addresses with Auto",
  58. addrs: append(v4Addrs, v6Addrs...),
  59. mode: Auto,
  60. expectedAddrs: len(v4Addrs),
  61. primary: makeAddrSet(v4Addrs),
  62. secondary: makeAddrSet(v6Addrs),
  63. },
  64. {
  65. name: "IPv6 (first) and IPv4 addresses with Auto",
  66. addrs: append(v6Addrs, v4Addrs...),
  67. mode: Auto,
  68. expectedAddrs: len(v6Addrs),
  69. primary: makeAddrSet(v6Addrs),
  70. secondary: makeAddrSet(v4Addrs),
  71. },
  72. {
  73. name: "IPv4 addresses with Auto",
  74. addrs: v4Addrs,
  75. mode: Auto,
  76. expectedAddrs: len(v4Addrs),
  77. primary: makeAddrSet(v4Addrs),
  78. secondary: AddrSet{},
  79. },
  80. {
  81. name: "IPv6 addresses with Auto",
  82. addrs: v6Addrs,
  83. mode: Auto,
  84. expectedAddrs: len(v6Addrs),
  85. primary: makeAddrSet(v6Addrs),
  86. secondary: AddrSet{},
  87. },
  88. }
  89. for _, tt := range tests {
  90. t.Run(tt.name, func(t *testing.T) {
  91. r := NewRegion(tt.addrs, tt.mode)
  92. assert.Equal(t, tt.expectedAddrs, r.AvailableAddrs())
  93. assert.Equal(t, tt.primary, r.primary)
  94. assert.Equal(t, tt.secondary, r.secondary)
  95. })
  96. }
  97. }
  98. func TestRegion_AnyAddress_EmptyActiveSet(t *testing.T) {
  99. tests := []struct {
  100. name string
  101. addrs []*EdgeAddr
  102. mode ConfigIPVersion
  103. }{
  104. {
  105. name: "IPv6 addresses with IPv4Only",
  106. addrs: v6Addrs,
  107. mode: IPv4Only,
  108. },
  109. {
  110. name: "IPv4 addresses with IPv6Only",
  111. addrs: v4Addrs,
  112. mode: IPv6Only,
  113. },
  114. }
  115. for _, tt := range tests {
  116. t.Run(tt.name, func(t *testing.T) {
  117. r := NewRegion(tt.addrs, tt.mode)
  118. addr := r.GetAnyAddress()
  119. assert.Nil(t, addr)
  120. addr = r.AssignAnyAddress(0, nil)
  121. assert.Nil(t, addr)
  122. })
  123. }
  124. }
  125. func TestRegion_AssignAnyAddress_FullyUsedActiveSet(t *testing.T) {
  126. tests := []struct {
  127. name string
  128. addrs []*EdgeAddr
  129. mode ConfigIPVersion
  130. }{
  131. {
  132. name: "IPv6 addresses with IPv6Only",
  133. addrs: v6Addrs,
  134. mode: IPv6Only,
  135. },
  136. {
  137. name: "IPv4 addresses with IPv4Only",
  138. addrs: v4Addrs,
  139. mode: IPv4Only,
  140. },
  141. }
  142. for _, tt := range tests {
  143. t.Run(tt.name, func(t *testing.T) {
  144. r := NewRegion(tt.addrs, tt.mode)
  145. total := r.active.AvailableAddrs()
  146. for i := 0; i < total; i++ {
  147. addr := r.AssignAnyAddress(i, nil)
  148. assert.NotNil(t, addr)
  149. }
  150. addr := r.AssignAnyAddress(9, nil)
  151. assert.Nil(t, addr)
  152. })
  153. }
  154. }
  155. var giveBackTests = []struct {
  156. name string
  157. addrs []*EdgeAddr
  158. mode ConfigIPVersion
  159. expectedAddrs int
  160. primary AddrSet
  161. secondary AddrSet
  162. primarySwap bool
  163. }{
  164. {
  165. name: "IPv4 addresses with IPv4Only",
  166. addrs: v4Addrs,
  167. mode: IPv4Only,
  168. expectedAddrs: len(v4Addrs),
  169. primary: makeAddrSet(v4Addrs),
  170. secondary: AddrSet{},
  171. primarySwap: false,
  172. },
  173. {
  174. name: "IPv6 addresses with IPv6Only",
  175. addrs: v6Addrs,
  176. mode: IPv6Only,
  177. expectedAddrs: len(v6Addrs),
  178. primary: makeAddrSet(v6Addrs),
  179. secondary: AddrSet{},
  180. primarySwap: false,
  181. },
  182. {
  183. name: "IPv4 (first) and IPv6 addresses with Auto",
  184. addrs: append(v4Addrs, v6Addrs...),
  185. mode: Auto,
  186. expectedAddrs: len(v4Addrs),
  187. primary: makeAddrSet(v4Addrs),
  188. secondary: makeAddrSet(v6Addrs),
  189. primarySwap: false,
  190. },
  191. {
  192. name: "IPv6 (first) and IPv4 addresses with Auto",
  193. addrs: append(v6Addrs, v4Addrs...),
  194. mode: Auto,
  195. expectedAddrs: len(v6Addrs),
  196. primary: makeAddrSet(v6Addrs),
  197. secondary: makeAddrSet(v4Addrs),
  198. primarySwap: true,
  199. },
  200. {
  201. name: "IPv4 addresses with Auto",
  202. addrs: v4Addrs,
  203. mode: Auto,
  204. expectedAddrs: len(v4Addrs),
  205. primary: makeAddrSet(v4Addrs),
  206. secondary: AddrSet{},
  207. primarySwap: false,
  208. },
  209. {
  210. name: "IPv6 addresses with Auto",
  211. addrs: v6Addrs,
  212. mode: Auto,
  213. expectedAddrs: len(v6Addrs),
  214. primary: makeAddrSet(v6Addrs),
  215. secondary: AddrSet{},
  216. primarySwap: false,
  217. },
  218. }
  219. func TestRegion_GiveBack_NoConnectivityError(t *testing.T) {
  220. for _, tt := range giveBackTests {
  221. t.Run(tt.name, func(t *testing.T) {
  222. r := NewRegion(tt.addrs, tt.mode)
  223. addr := r.AssignAnyAddress(0, nil)
  224. assert.NotNil(t, addr)
  225. assert.True(t, r.GiveBack(addr, false))
  226. })
  227. }
  228. }
  229. func TestRegion_GiveBack_ForeignAddr(t *testing.T) {
  230. invalid := EdgeAddr{
  231. TCP: &net.TCPAddr{
  232. IP: net.ParseIP("123.4.5.0"),
  233. Port: 8000,
  234. Zone: "",
  235. },
  236. UDP: &net.UDPAddr{
  237. IP: net.ParseIP("123.4.5.0"),
  238. Port: 8000,
  239. Zone: "",
  240. },
  241. IPVersion: V4,
  242. }
  243. for _, tt := range giveBackTests {
  244. t.Run(tt.name, func(t *testing.T) {
  245. r := NewRegion(tt.addrs, tt.mode)
  246. assert.False(t, r.GiveBack(&invalid, false))
  247. assert.False(t, r.GiveBack(&invalid, true))
  248. })
  249. }
  250. }
  251. func TestRegion_GiveBack_SwapPrimary(t *testing.T) {
  252. for _, tt := range giveBackTests {
  253. t.Run(tt.name, func(t *testing.T) {
  254. r := NewRegion(tt.addrs, tt.mode)
  255. addr := r.AssignAnyAddress(0, nil)
  256. assert.NotNil(t, addr)
  257. assert.True(t, r.GiveBack(addr, true))
  258. assert.Equal(t, tt.primarySwap, !r.primaryIsActive)
  259. if tt.primarySwap {
  260. assert.Equal(t, r.secondary, r.active)
  261. assert.False(t, r.primaryTimeout.IsZero())
  262. } else {
  263. assert.Equal(t, r.primary, r.active)
  264. assert.True(t, r.primaryTimeout.IsZero())
  265. }
  266. })
  267. }
  268. }
  269. func TestRegion_GiveBack_IPv4_ResetPrimary(t *testing.T) {
  270. r := NewRegion(append(v6Addrs, v4Addrs...), Auto)
  271. // Exhaust all IPv6 addresses
  272. a0 := r.AssignAnyAddress(0, nil)
  273. a1 := r.AssignAnyAddress(1, nil)
  274. a2 := r.AssignAnyAddress(2, nil)
  275. a3 := r.AssignAnyAddress(3, nil)
  276. assert.NotNil(t, a0)
  277. assert.NotNil(t, a1)
  278. assert.NotNil(t, a2)
  279. assert.NotNil(t, a3)
  280. // Give back the first IPv6 address to fallback to secondary IPv4 address set
  281. assert.True(t, r.GiveBack(a0, true))
  282. assert.False(t, r.primaryIsActive)
  283. // Give back another IPv6 address
  284. assert.True(t, r.GiveBack(a1, true))
  285. // Primary shouldn't change
  286. assert.False(t, r.primaryIsActive)
  287. // Request an address (should be IPv4 from secondary)
  288. a4_v4 := r.AssignAnyAddress(4, nil)
  289. assert.NotNil(t, a4_v4)
  290. assert.Equal(t, V4, a4_v4.IPVersion)
  291. a5_v4 := r.AssignAnyAddress(5, nil)
  292. assert.NotNil(t, a5_v4)
  293. assert.Equal(t, V4, a5_v4.IPVersion)
  294. a6_v4 := r.AssignAnyAddress(6, nil)
  295. assert.NotNil(t, a6_v4)
  296. assert.Equal(t, V4, a6_v4.IPVersion)
  297. // Return IPv4 address (without failure)
  298. // Primary shouldn't change because it is not a connectivity failure
  299. assert.True(t, r.GiveBack(a4_v4, false))
  300. assert.False(t, r.primaryIsActive)
  301. // Return IPv4 address (with failure)
  302. // Primary should change because it is a connectivity failure
  303. assert.True(t, r.GiveBack(a5_v4, true))
  304. assert.True(t, r.primaryIsActive)
  305. // Return IPv4 address (with failure)
  306. // Primary shouldn't change because the address is returned to the inactive
  307. // secondary address set
  308. assert.True(t, r.GiveBack(a6_v4, true))
  309. assert.True(t, r.primaryIsActive)
  310. // Return IPv6 address (without failure)
  311. // Primary shoudn't change because it is not a connectivity failure
  312. assert.True(t, r.GiveBack(a2, false))
  313. assert.True(t, r.primaryIsActive)
  314. }
  315. func TestRegion_GiveBack_Timeout(t *testing.T) {
  316. r := NewRegion(append(v6Addrs, v4Addrs...), Auto)
  317. a0 := r.AssignAnyAddress(0, nil)
  318. a1 := r.AssignAnyAddress(1, nil)
  319. a2 := r.AssignAnyAddress(2, nil)
  320. assert.NotNil(t, a0)
  321. assert.NotNil(t, a1)
  322. assert.NotNil(t, a2)
  323. // Give back IPv6 address to set timeout
  324. assert.True(t, r.GiveBack(a0, true))
  325. assert.False(t, r.primaryIsActive)
  326. assert.False(t, r.primaryTimeout.IsZero())
  327. // Request an address (should be IPv4 from secondary)
  328. a3_v4 := r.AssignAnyAddress(3, nil)
  329. assert.NotNil(t, a3_v4)
  330. assert.Equal(t, V4, a3_v4.IPVersion)
  331. assert.False(t, r.primaryIsActive)
  332. // Give back IPv6 address inside timeout (no change)
  333. assert.True(t, r.GiveBack(a2, true))
  334. assert.False(t, r.primaryIsActive)
  335. assert.False(t, r.primaryTimeout.IsZero())
  336. // Accelerate timeout
  337. r.primaryTimeout = time.Now().Add(-time.Minute)
  338. // Return IPv6 address
  339. assert.True(t, r.GiveBack(a1, true))
  340. assert.True(t, r.primaryIsActive)
  341. // Returning an IPv4 address after primary is active shouldn't change primary
  342. // even with a connectivity error
  343. assert.True(t, r.GiveBack(a3_v4, true))
  344. assert.True(t, r.primaryIsActive)
  345. }