endpoints_test.go 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package proxy
  14. import (
  15. "reflect"
  16. "testing"
  17. "time"
  18. "github.com/davecgh/go-spew/spew"
  19. "k8s.io/api/core/v1"
  20. discovery "k8s.io/api/discovery/v1beta1"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. "k8s.io/apimachinery/pkg/util/sets"
  24. utilpointer "k8s.io/utils/pointer"
  25. )
  26. func (proxier *FakeProxier) addEndpoints(endpoints *v1.Endpoints) {
  27. proxier.endpointsChanges.Update(nil, endpoints)
  28. }
  29. func (proxier *FakeProxier) updateEndpoints(oldEndpoints, endpoints *v1.Endpoints) {
  30. proxier.endpointsChanges.Update(oldEndpoints, endpoints)
  31. }
  32. func (proxier *FakeProxier) deleteEndpoints(endpoints *v1.Endpoints) {
  33. proxier.endpointsChanges.Update(endpoints, nil)
  34. }
  35. func TestGetLocalEndpointIPs(t *testing.T) {
  36. testCases := []struct {
  37. endpointsMap EndpointsMap
  38. expected map[types.NamespacedName]sets.String
  39. }{{
  40. // Case[0]: nothing
  41. endpointsMap: EndpointsMap{},
  42. expected: map[types.NamespacedName]sets.String{},
  43. }, {
  44. // Case[1]: unnamed port
  45. endpointsMap: EndpointsMap{
  46. makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): []Endpoint{
  47. &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false},
  48. },
  49. },
  50. expected: map[types.NamespacedName]sets.String{},
  51. }, {
  52. // Case[2]: unnamed port local
  53. endpointsMap: EndpointsMap{
  54. makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): []Endpoint{
  55. &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true},
  56. },
  57. },
  58. expected: map[types.NamespacedName]sets.String{
  59. {Namespace: "ns1", Name: "ep1"}: sets.NewString("1.1.1.1"),
  60. },
  61. }, {
  62. // Case[3]: named local and non-local ports for the same IP.
  63. endpointsMap: EndpointsMap{
  64. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolTCP): []Endpoint{
  65. &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false},
  66. &BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true},
  67. },
  68. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolTCP): []Endpoint{
  69. &BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false},
  70. &BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true},
  71. },
  72. },
  73. expected: map[types.NamespacedName]sets.String{
  74. {Namespace: "ns1", Name: "ep1"}: sets.NewString("1.1.1.2"),
  75. },
  76. }, {
  77. // Case[4]: named local and non-local ports for different IPs.
  78. endpointsMap: EndpointsMap{
  79. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolTCP): []Endpoint{
  80. &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false},
  81. },
  82. makeServicePortName("ns2", "ep2", "p22", v1.ProtocolTCP): []Endpoint{
  83. &BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true},
  84. &BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true},
  85. },
  86. makeServicePortName("ns2", "ep2", "p23", v1.ProtocolTCP): []Endpoint{
  87. &BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true},
  88. },
  89. makeServicePortName("ns4", "ep4", "p44", v1.ProtocolTCP): []Endpoint{
  90. &BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true},
  91. &BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: false},
  92. },
  93. makeServicePortName("ns4", "ep4", "p45", v1.ProtocolTCP): []Endpoint{
  94. &BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true},
  95. },
  96. },
  97. expected: map[types.NamespacedName]sets.String{
  98. {Namespace: "ns2", Name: "ep2"}: sets.NewString("2.2.2.2", "2.2.2.22", "2.2.2.3"),
  99. {Namespace: "ns4", Name: "ep4"}: sets.NewString("4.4.4.4", "4.4.4.6"),
  100. },
  101. }}
  102. for tci, tc := range testCases {
  103. // outputs
  104. localIPs := tc.endpointsMap.getLocalEndpointIPs()
  105. if !reflect.DeepEqual(localIPs, tc.expected) {
  106. t.Errorf("[%d] expected %#v, got %#v", tci, tc.expected, localIPs)
  107. }
  108. }
  109. }
  110. func makeTestEndpoints(namespace, name string, eptFunc func(*v1.Endpoints)) *v1.Endpoints {
  111. ept := &v1.Endpoints{
  112. ObjectMeta: metav1.ObjectMeta{
  113. Name: name,
  114. Namespace: namespace,
  115. Annotations: make(map[string]string),
  116. },
  117. }
  118. eptFunc(ept)
  119. return ept
  120. }
  121. // This is a coarse test, but it offers some modicum of confidence as the code is evolved.
  122. func TestEndpointsToEndpointsMap(t *testing.T) {
  123. epTracker := NewEndpointChangeTracker("test-hostname", nil, nil, nil, false)
  124. trueVal := true
  125. falseVal := false
  126. testCases := []struct {
  127. desc string
  128. newEndpoints *v1.Endpoints
  129. expected map[ServicePortName][]*BaseEndpointInfo
  130. isIPv6Mode *bool
  131. }{
  132. {
  133. desc: "nothing",
  134. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {}),
  135. expected: map[ServicePortName][]*BaseEndpointInfo{},
  136. },
  137. {
  138. desc: "no changes, unnamed port",
  139. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  140. ept.Subsets = []v1.EndpointSubset{
  141. {
  142. Addresses: []v1.EndpointAddress{{
  143. IP: "1.1.1.1",
  144. }},
  145. Ports: []v1.EndpointPort{{
  146. Name: "",
  147. Port: 11,
  148. Protocol: v1.ProtocolTCP,
  149. }},
  150. },
  151. }
  152. }),
  153. expected: map[ServicePortName][]*BaseEndpointInfo{
  154. makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): {
  155. {Endpoint: "1.1.1.1:11", IsLocal: false},
  156. },
  157. },
  158. },
  159. {
  160. desc: "no changes, named port",
  161. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  162. ept.Subsets = []v1.EndpointSubset{
  163. {
  164. Addresses: []v1.EndpointAddress{{
  165. IP: "1.1.1.1",
  166. }},
  167. Ports: []v1.EndpointPort{{
  168. Name: "port",
  169. Port: 11,
  170. Protocol: v1.ProtocolTCP,
  171. }},
  172. },
  173. }
  174. }),
  175. expected: map[ServicePortName][]*BaseEndpointInfo{
  176. makeServicePortName("ns1", "ep1", "port", v1.ProtocolTCP): {
  177. {Endpoint: "1.1.1.1:11", IsLocal: false},
  178. },
  179. },
  180. },
  181. {
  182. desc: "new port",
  183. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  184. ept.Subsets = []v1.EndpointSubset{
  185. {
  186. Addresses: []v1.EndpointAddress{{
  187. IP: "1.1.1.1",
  188. }},
  189. Ports: []v1.EndpointPort{{
  190. Port: 11,
  191. Protocol: v1.ProtocolTCP,
  192. }},
  193. },
  194. }
  195. }),
  196. expected: map[ServicePortName][]*BaseEndpointInfo{
  197. makeServicePortName("ns1", "ep1", "", v1.ProtocolTCP): {
  198. {Endpoint: "1.1.1.1:11", IsLocal: false},
  199. },
  200. },
  201. },
  202. {
  203. desc: "remove port",
  204. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {}),
  205. expected: map[ServicePortName][]*BaseEndpointInfo{},
  206. },
  207. {
  208. desc: "new IP and port",
  209. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  210. ept.Subsets = []v1.EndpointSubset{
  211. {
  212. Addresses: []v1.EndpointAddress{{
  213. IP: "1.1.1.1",
  214. }, {
  215. IP: "2.2.2.2",
  216. }},
  217. Ports: []v1.EndpointPort{{
  218. Name: "p1",
  219. Port: 11,
  220. Protocol: v1.ProtocolTCP,
  221. }, {
  222. Name: "p2",
  223. Port: 22,
  224. Protocol: v1.ProtocolTCP,
  225. }},
  226. },
  227. }
  228. }),
  229. expected: map[ServicePortName][]*BaseEndpointInfo{
  230. makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): {
  231. {Endpoint: "1.1.1.1:11", IsLocal: false},
  232. {Endpoint: "2.2.2.2:11", IsLocal: false},
  233. },
  234. makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): {
  235. {Endpoint: "1.1.1.1:22", IsLocal: false},
  236. {Endpoint: "2.2.2.2:22", IsLocal: false},
  237. },
  238. },
  239. },
  240. {
  241. desc: "remove IP and port",
  242. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  243. ept.Subsets = []v1.EndpointSubset{
  244. {
  245. Addresses: []v1.EndpointAddress{{
  246. IP: "1.1.1.1",
  247. }},
  248. Ports: []v1.EndpointPort{{
  249. Name: "p1",
  250. Port: 11,
  251. Protocol: v1.ProtocolTCP,
  252. }},
  253. },
  254. }
  255. }),
  256. expected: map[ServicePortName][]*BaseEndpointInfo{
  257. makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): {
  258. {Endpoint: "1.1.1.1:11", IsLocal: false},
  259. },
  260. },
  261. },
  262. {
  263. desc: "rename port",
  264. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  265. ept.Subsets = []v1.EndpointSubset{
  266. {
  267. Addresses: []v1.EndpointAddress{{
  268. IP: "1.1.1.1",
  269. }},
  270. Ports: []v1.EndpointPort{{
  271. Name: "p2",
  272. Port: 11,
  273. Protocol: v1.ProtocolTCP,
  274. }},
  275. },
  276. }
  277. }),
  278. expected: map[ServicePortName][]*BaseEndpointInfo{
  279. makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): {
  280. {Endpoint: "1.1.1.1:11", IsLocal: false},
  281. },
  282. },
  283. },
  284. {
  285. desc: "renumber port",
  286. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  287. ept.Subsets = []v1.EndpointSubset{
  288. {
  289. Addresses: []v1.EndpointAddress{{
  290. IP: "1.1.1.1",
  291. }},
  292. Ports: []v1.EndpointPort{{
  293. Name: "p1",
  294. Port: 22,
  295. Protocol: v1.ProtocolTCP,
  296. }},
  297. },
  298. }
  299. }),
  300. expected: map[ServicePortName][]*BaseEndpointInfo{
  301. makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): {
  302. {Endpoint: "1.1.1.1:22", IsLocal: false},
  303. },
  304. },
  305. },
  306. {
  307. desc: "should omit IPv6 address in IPv4 mode",
  308. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  309. ept.Subsets = []v1.EndpointSubset{
  310. {
  311. Addresses: []v1.EndpointAddress{{
  312. IP: "1.1.1.1",
  313. }, {
  314. IP: "2001:db8:85a3:0:0:8a2e:370:7334",
  315. }},
  316. Ports: []v1.EndpointPort{{
  317. Name: "p1",
  318. Port: 11,
  319. Protocol: v1.ProtocolTCP,
  320. }, {
  321. Name: "p2",
  322. Port: 22,
  323. Protocol: v1.ProtocolTCP,
  324. }},
  325. },
  326. }
  327. }),
  328. expected: map[ServicePortName][]*BaseEndpointInfo{
  329. makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): {
  330. {Endpoint: "1.1.1.1:11", IsLocal: false},
  331. },
  332. makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): {
  333. {Endpoint: "1.1.1.1:22", IsLocal: false},
  334. },
  335. },
  336. isIPv6Mode: &falseVal,
  337. },
  338. {
  339. desc: "should omit IPv4 address in IPv6 mode",
  340. newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *v1.Endpoints) {
  341. ept.Subsets = []v1.EndpointSubset{
  342. {
  343. Addresses: []v1.EndpointAddress{{
  344. IP: "1.1.1.1",
  345. }, {
  346. IP: "2001:db8:85a3:0:0:8a2e:370:7334",
  347. }},
  348. Ports: []v1.EndpointPort{{
  349. Name: "p1",
  350. Port: 11,
  351. Protocol: v1.ProtocolTCP,
  352. }, {
  353. Name: "p2",
  354. Port: 22,
  355. Protocol: v1.ProtocolTCP,
  356. }},
  357. },
  358. }
  359. }),
  360. expected: map[ServicePortName][]*BaseEndpointInfo{
  361. makeServicePortName("ns1", "ep1", "p1", v1.ProtocolTCP): {
  362. {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:11", IsLocal: false},
  363. },
  364. makeServicePortName("ns1", "ep1", "p2", v1.ProtocolTCP): {
  365. {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:22", IsLocal: false},
  366. },
  367. },
  368. isIPv6Mode: &trueVal,
  369. },
  370. }
  371. for _, tc := range testCases {
  372. epTracker.isIPv6Mode = tc.isIPv6Mode
  373. // outputs
  374. newEndpoints := epTracker.endpointsToEndpointsMap(tc.newEndpoints)
  375. if len(newEndpoints) != len(tc.expected) {
  376. t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newEndpoints), spew.Sdump(newEndpoints))
  377. }
  378. for x := range tc.expected {
  379. if len(newEndpoints[x]) != len(tc.expected[x]) {
  380. t.Errorf("[%s] expected %d endpoints for %v, got %d", tc.desc, len(tc.expected[x]), x, len(newEndpoints[x]))
  381. } else {
  382. for i := range newEndpoints[x] {
  383. ep := newEndpoints[x][i].(*BaseEndpointInfo)
  384. if !(reflect.DeepEqual(*ep, *(tc.expected[x][i]))) {
  385. t.Errorf("[%s] expected new[%v][%d] to be %v, got %v", tc.desc, x, i, tc.expected[x][i], *ep)
  386. }
  387. }
  388. }
  389. }
  390. }
  391. }
  392. func TestUpdateEndpointsMap(t *testing.T) {
  393. var nodeName = testHostname
  394. emptyEndpoint := func(ept *v1.Endpoints) {
  395. ept.Subsets = []v1.EndpointSubset{}
  396. }
  397. unnamedPort := func(ept *v1.Endpoints) {
  398. ept.Subsets = []v1.EndpointSubset{{
  399. Addresses: []v1.EndpointAddress{{
  400. IP: "1.1.1.1",
  401. }},
  402. Ports: []v1.EndpointPort{{
  403. Port: 11,
  404. Protocol: v1.ProtocolUDP,
  405. }},
  406. }}
  407. }
  408. unnamedPortLocal := func(ept *v1.Endpoints) {
  409. ept.Subsets = []v1.EndpointSubset{{
  410. Addresses: []v1.EndpointAddress{{
  411. IP: "1.1.1.1",
  412. NodeName: &nodeName,
  413. }},
  414. Ports: []v1.EndpointPort{{
  415. Port: 11,
  416. Protocol: v1.ProtocolUDP,
  417. }},
  418. }}
  419. }
  420. namedPortLocal := func(ept *v1.Endpoints) {
  421. ept.Subsets = []v1.EndpointSubset{{
  422. Addresses: []v1.EndpointAddress{{
  423. IP: "1.1.1.1",
  424. NodeName: &nodeName,
  425. }},
  426. Ports: []v1.EndpointPort{{
  427. Name: "p11",
  428. Port: 11,
  429. Protocol: v1.ProtocolUDP,
  430. }},
  431. }}
  432. }
  433. namedPort := func(ept *v1.Endpoints) {
  434. ept.Subsets = []v1.EndpointSubset{{
  435. Addresses: []v1.EndpointAddress{{
  436. IP: "1.1.1.1",
  437. }},
  438. Ports: []v1.EndpointPort{{
  439. Name: "p11",
  440. Port: 11,
  441. Protocol: v1.ProtocolUDP,
  442. }},
  443. }}
  444. }
  445. namedPortRenamed := func(ept *v1.Endpoints) {
  446. ept.Subsets = []v1.EndpointSubset{{
  447. Addresses: []v1.EndpointAddress{{
  448. IP: "1.1.1.1",
  449. }},
  450. Ports: []v1.EndpointPort{{
  451. Name: "p11-2",
  452. Port: 11,
  453. Protocol: v1.ProtocolUDP,
  454. }},
  455. }}
  456. }
  457. namedPortRenumbered := func(ept *v1.Endpoints) {
  458. ept.Subsets = []v1.EndpointSubset{{
  459. Addresses: []v1.EndpointAddress{{
  460. IP: "1.1.1.1",
  461. }},
  462. Ports: []v1.EndpointPort{{
  463. Name: "p11",
  464. Port: 22,
  465. Protocol: v1.ProtocolUDP,
  466. }},
  467. }}
  468. }
  469. namedPortsLocalNoLocal := func(ept *v1.Endpoints) {
  470. ept.Subsets = []v1.EndpointSubset{{
  471. Addresses: []v1.EndpointAddress{{
  472. IP: "1.1.1.1",
  473. }, {
  474. IP: "1.1.1.2",
  475. NodeName: &nodeName,
  476. }},
  477. Ports: []v1.EndpointPort{{
  478. Name: "p11",
  479. Port: 11,
  480. Protocol: v1.ProtocolUDP,
  481. }, {
  482. Name: "p12",
  483. Port: 12,
  484. Protocol: v1.ProtocolUDP,
  485. }},
  486. }}
  487. }
  488. multipleSubsets := func(ept *v1.Endpoints) {
  489. ept.Subsets = []v1.EndpointSubset{{
  490. Addresses: []v1.EndpointAddress{{
  491. IP: "1.1.1.1",
  492. }},
  493. Ports: []v1.EndpointPort{{
  494. Name: "p11",
  495. Port: 11,
  496. Protocol: v1.ProtocolUDP,
  497. }},
  498. }, {
  499. Addresses: []v1.EndpointAddress{{
  500. IP: "1.1.1.2",
  501. }},
  502. Ports: []v1.EndpointPort{{
  503. Name: "p12",
  504. Port: 12,
  505. Protocol: v1.ProtocolUDP,
  506. }},
  507. }}
  508. }
  509. multipleSubsetsWithLocal := func(ept *v1.Endpoints) {
  510. ept.Subsets = []v1.EndpointSubset{{
  511. Addresses: []v1.EndpointAddress{{
  512. IP: "1.1.1.1",
  513. }},
  514. Ports: []v1.EndpointPort{{
  515. Name: "p11",
  516. Port: 11,
  517. Protocol: v1.ProtocolUDP,
  518. }},
  519. }, {
  520. Addresses: []v1.EndpointAddress{{
  521. IP: "1.1.1.2",
  522. NodeName: &nodeName,
  523. }},
  524. Ports: []v1.EndpointPort{{
  525. Name: "p12",
  526. Port: 12,
  527. Protocol: v1.ProtocolUDP,
  528. }},
  529. }}
  530. }
  531. multipleSubsetsMultiplePortsLocal := func(ept *v1.Endpoints) {
  532. ept.Subsets = []v1.EndpointSubset{{
  533. Addresses: []v1.EndpointAddress{{
  534. IP: "1.1.1.1",
  535. NodeName: &nodeName,
  536. }},
  537. Ports: []v1.EndpointPort{{
  538. Name: "p11",
  539. Port: 11,
  540. Protocol: v1.ProtocolUDP,
  541. }, {
  542. Name: "p12",
  543. Port: 12,
  544. Protocol: v1.ProtocolUDP,
  545. }},
  546. }, {
  547. Addresses: []v1.EndpointAddress{{
  548. IP: "1.1.1.3",
  549. }},
  550. Ports: []v1.EndpointPort{{
  551. Name: "p13",
  552. Port: 13,
  553. Protocol: v1.ProtocolUDP,
  554. }},
  555. }}
  556. }
  557. multipleSubsetsIPsPorts1 := func(ept *v1.Endpoints) {
  558. ept.Subsets = []v1.EndpointSubset{{
  559. Addresses: []v1.EndpointAddress{{
  560. IP: "1.1.1.1",
  561. }, {
  562. IP: "1.1.1.2",
  563. NodeName: &nodeName,
  564. }},
  565. Ports: []v1.EndpointPort{{
  566. Name: "p11",
  567. Port: 11,
  568. Protocol: v1.ProtocolUDP,
  569. }, {
  570. Name: "p12",
  571. Port: 12,
  572. Protocol: v1.ProtocolUDP,
  573. }},
  574. }, {
  575. Addresses: []v1.EndpointAddress{{
  576. IP: "1.1.1.3",
  577. }, {
  578. IP: "1.1.1.4",
  579. NodeName: &nodeName,
  580. }},
  581. Ports: []v1.EndpointPort{{
  582. Name: "p13",
  583. Port: 13,
  584. Protocol: v1.ProtocolUDP,
  585. }, {
  586. Name: "p14",
  587. Port: 14,
  588. Protocol: v1.ProtocolUDP,
  589. }},
  590. }}
  591. }
  592. multipleSubsetsIPsPorts2 := func(ept *v1.Endpoints) {
  593. ept.Subsets = []v1.EndpointSubset{{
  594. Addresses: []v1.EndpointAddress{{
  595. IP: "2.2.2.1",
  596. }, {
  597. IP: "2.2.2.2",
  598. NodeName: &nodeName,
  599. }},
  600. Ports: []v1.EndpointPort{{
  601. Name: "p21",
  602. Port: 21,
  603. Protocol: v1.ProtocolUDP,
  604. }, {
  605. Name: "p22",
  606. Port: 22,
  607. Protocol: v1.ProtocolUDP,
  608. }},
  609. }}
  610. }
  611. complexBefore1 := func(ept *v1.Endpoints) {
  612. ept.Subsets = []v1.EndpointSubset{{
  613. Addresses: []v1.EndpointAddress{{
  614. IP: "1.1.1.1",
  615. }},
  616. Ports: []v1.EndpointPort{{
  617. Name: "p11",
  618. Port: 11,
  619. Protocol: v1.ProtocolUDP,
  620. }},
  621. }}
  622. }
  623. complexBefore2 := func(ept *v1.Endpoints) {
  624. ept.Subsets = []v1.EndpointSubset{{
  625. Addresses: []v1.EndpointAddress{{
  626. IP: "2.2.2.2",
  627. NodeName: &nodeName,
  628. }, {
  629. IP: "2.2.2.22",
  630. NodeName: &nodeName,
  631. }},
  632. Ports: []v1.EndpointPort{{
  633. Name: "p22",
  634. Port: 22,
  635. Protocol: v1.ProtocolUDP,
  636. }},
  637. }, {
  638. Addresses: []v1.EndpointAddress{{
  639. IP: "2.2.2.3",
  640. NodeName: &nodeName,
  641. }},
  642. Ports: []v1.EndpointPort{{
  643. Name: "p23",
  644. Port: 23,
  645. Protocol: v1.ProtocolUDP,
  646. }},
  647. }}
  648. }
  649. complexBefore4 := func(ept *v1.Endpoints) {
  650. ept.Subsets = []v1.EndpointSubset{{
  651. Addresses: []v1.EndpointAddress{{
  652. IP: "4.4.4.4",
  653. NodeName: &nodeName,
  654. }, {
  655. IP: "4.4.4.5",
  656. NodeName: &nodeName,
  657. }},
  658. Ports: []v1.EndpointPort{{
  659. Name: "p44",
  660. Port: 44,
  661. Protocol: v1.ProtocolUDP,
  662. }},
  663. }, {
  664. Addresses: []v1.EndpointAddress{{
  665. IP: "4.4.4.6",
  666. NodeName: &nodeName,
  667. }},
  668. Ports: []v1.EndpointPort{{
  669. Name: "p45",
  670. Port: 45,
  671. Protocol: v1.ProtocolUDP,
  672. }},
  673. }}
  674. }
  675. complexAfter1 := func(ept *v1.Endpoints) {
  676. ept.Subsets = []v1.EndpointSubset{{
  677. Addresses: []v1.EndpointAddress{{
  678. IP: "1.1.1.1",
  679. }, {
  680. IP: "1.1.1.11",
  681. }},
  682. Ports: []v1.EndpointPort{{
  683. Name: "p11",
  684. Port: 11,
  685. Protocol: v1.ProtocolUDP,
  686. }},
  687. }, {
  688. Addresses: []v1.EndpointAddress{{
  689. IP: "1.1.1.2",
  690. }},
  691. Ports: []v1.EndpointPort{{
  692. Name: "p12",
  693. Port: 12,
  694. Protocol: v1.ProtocolUDP,
  695. }, {
  696. Name: "p122",
  697. Port: 122,
  698. Protocol: v1.ProtocolUDP,
  699. }},
  700. }}
  701. }
  702. complexAfter3 := func(ept *v1.Endpoints) {
  703. ept.Subsets = []v1.EndpointSubset{{
  704. Addresses: []v1.EndpointAddress{{
  705. IP: "3.3.3.3",
  706. }},
  707. Ports: []v1.EndpointPort{{
  708. Name: "p33",
  709. Port: 33,
  710. Protocol: v1.ProtocolUDP,
  711. }},
  712. }}
  713. }
  714. complexAfter4 := func(ept *v1.Endpoints) {
  715. ept.Subsets = []v1.EndpointSubset{{
  716. Addresses: []v1.EndpointAddress{{
  717. IP: "4.4.4.4",
  718. NodeName: &nodeName,
  719. }},
  720. Ports: []v1.EndpointPort{{
  721. Name: "p44",
  722. Port: 44,
  723. Protocol: v1.ProtocolUDP,
  724. }},
  725. }}
  726. }
  727. testCases := []struct {
  728. // previousEndpoints and currentEndpoints are used to call appropriate
  729. // handlers OnEndpoints* (based on whether corresponding values are nil
  730. // or non-nil) and must be of equal length.
  731. name string
  732. previousEndpoints []*v1.Endpoints
  733. currentEndpoints []*v1.Endpoints
  734. oldEndpoints map[ServicePortName][]*BaseEndpointInfo
  735. expectedResult map[ServicePortName][]*BaseEndpointInfo
  736. expectedStaleEndpoints []ServiceEndpoint
  737. expectedStaleServiceNames map[ServicePortName]bool
  738. expectedHealthchecks map[types.NamespacedName]int
  739. }{{
  740. name: "empty",
  741. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{},
  742. expectedResult: map[ServicePortName][]*BaseEndpointInfo{},
  743. expectedStaleEndpoints: []ServiceEndpoint{},
  744. expectedStaleServiceNames: map[ServicePortName]bool{},
  745. expectedHealthchecks: map[types.NamespacedName]int{},
  746. }, {
  747. name: "no change, unnamed port",
  748. previousEndpoints: []*v1.Endpoints{
  749. makeTestEndpoints("ns1", "ep1", unnamedPort),
  750. },
  751. currentEndpoints: []*v1.Endpoints{
  752. makeTestEndpoints("ns1", "ep1", unnamedPort),
  753. },
  754. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  755. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): {
  756. {Endpoint: "1.1.1.1:11", IsLocal: false},
  757. },
  758. },
  759. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  760. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): {
  761. {Endpoint: "1.1.1.1:11", IsLocal: false},
  762. },
  763. },
  764. expectedStaleEndpoints: []ServiceEndpoint{},
  765. expectedStaleServiceNames: map[ServicePortName]bool{},
  766. expectedHealthchecks: map[types.NamespacedName]int{},
  767. }, {
  768. name: "no change, named port, local",
  769. previousEndpoints: []*v1.Endpoints{
  770. makeTestEndpoints("ns1", "ep1", namedPortLocal),
  771. },
  772. currentEndpoints: []*v1.Endpoints{
  773. makeTestEndpoints("ns1", "ep1", namedPortLocal),
  774. },
  775. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  776. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  777. {Endpoint: "1.1.1.1:11", IsLocal: true},
  778. },
  779. },
  780. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  781. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  782. {Endpoint: "1.1.1.1:11", IsLocal: true},
  783. },
  784. },
  785. expectedStaleEndpoints: []ServiceEndpoint{},
  786. expectedStaleServiceNames: map[ServicePortName]bool{},
  787. expectedHealthchecks: map[types.NamespacedName]int{
  788. makeNSN("ns1", "ep1"): 1,
  789. },
  790. }, {
  791. name: "no change, multiple subsets",
  792. previousEndpoints: []*v1.Endpoints{
  793. makeTestEndpoints("ns1", "ep1", multipleSubsets),
  794. },
  795. currentEndpoints: []*v1.Endpoints{
  796. makeTestEndpoints("ns1", "ep1", multipleSubsets),
  797. },
  798. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  799. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  800. {Endpoint: "1.1.1.1:11", IsLocal: false},
  801. },
  802. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  803. {Endpoint: "1.1.1.2:12", IsLocal: false},
  804. },
  805. },
  806. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  807. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  808. {Endpoint: "1.1.1.1:11", IsLocal: false},
  809. },
  810. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  811. {Endpoint: "1.1.1.2:12", IsLocal: false},
  812. },
  813. },
  814. expectedStaleEndpoints: []ServiceEndpoint{},
  815. expectedStaleServiceNames: map[ServicePortName]bool{},
  816. expectedHealthchecks: map[types.NamespacedName]int{},
  817. }, {
  818. name: "no change, multiple subsets, multiple ports, local",
  819. previousEndpoints: []*v1.Endpoints{
  820. makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
  821. },
  822. currentEndpoints: []*v1.Endpoints{
  823. makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal),
  824. },
  825. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  826. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  827. {Endpoint: "1.1.1.1:11", IsLocal: true},
  828. },
  829. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  830. {Endpoint: "1.1.1.1:12", IsLocal: true},
  831. },
  832. makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  833. {Endpoint: "1.1.1.3:13", IsLocal: false},
  834. },
  835. },
  836. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  837. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  838. {Endpoint: "1.1.1.1:11", IsLocal: true},
  839. },
  840. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  841. {Endpoint: "1.1.1.1:12", IsLocal: true},
  842. },
  843. makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  844. {Endpoint: "1.1.1.3:13", IsLocal: false},
  845. },
  846. },
  847. expectedStaleEndpoints: []ServiceEndpoint{},
  848. expectedStaleServiceNames: map[ServicePortName]bool{},
  849. expectedHealthchecks: map[types.NamespacedName]int{
  850. makeNSN("ns1", "ep1"): 1,
  851. },
  852. }, {
  853. name: "no change, multiple endpoints, subsets, IPs, and ports",
  854. previousEndpoints: []*v1.Endpoints{
  855. makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
  856. makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
  857. },
  858. currentEndpoints: []*v1.Endpoints{
  859. makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1),
  860. makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2),
  861. },
  862. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  863. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  864. {Endpoint: "1.1.1.1:11", IsLocal: false},
  865. {Endpoint: "1.1.1.2:11", IsLocal: true},
  866. },
  867. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  868. {Endpoint: "1.1.1.1:12", IsLocal: false},
  869. {Endpoint: "1.1.1.2:12", IsLocal: true},
  870. },
  871. makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  872. {Endpoint: "1.1.1.3:13", IsLocal: false},
  873. {Endpoint: "1.1.1.4:13", IsLocal: true},
  874. },
  875. makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): {
  876. {Endpoint: "1.1.1.3:14", IsLocal: false},
  877. {Endpoint: "1.1.1.4:14", IsLocal: true},
  878. },
  879. makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): {
  880. {Endpoint: "2.2.2.1:21", IsLocal: false},
  881. {Endpoint: "2.2.2.2:21", IsLocal: true},
  882. },
  883. makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  884. {Endpoint: "2.2.2.1:22", IsLocal: false},
  885. {Endpoint: "2.2.2.2:22", IsLocal: true},
  886. },
  887. },
  888. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  889. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  890. {Endpoint: "1.1.1.1:11", IsLocal: false},
  891. {Endpoint: "1.1.1.2:11", IsLocal: true},
  892. },
  893. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  894. {Endpoint: "1.1.1.1:12", IsLocal: false},
  895. {Endpoint: "1.1.1.2:12", IsLocal: true},
  896. },
  897. makeServicePortName("ns1", "ep1", "p13", v1.ProtocolUDP): {
  898. {Endpoint: "1.1.1.3:13", IsLocal: false},
  899. {Endpoint: "1.1.1.4:13", IsLocal: true},
  900. },
  901. makeServicePortName("ns1", "ep1", "p14", v1.ProtocolUDP): {
  902. {Endpoint: "1.1.1.3:14", IsLocal: false},
  903. {Endpoint: "1.1.1.4:14", IsLocal: true},
  904. },
  905. makeServicePortName("ns2", "ep2", "p21", v1.ProtocolUDP): {
  906. {Endpoint: "2.2.2.1:21", IsLocal: false},
  907. {Endpoint: "2.2.2.2:21", IsLocal: true},
  908. },
  909. makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  910. {Endpoint: "2.2.2.1:22", IsLocal: false},
  911. {Endpoint: "2.2.2.2:22", IsLocal: true},
  912. },
  913. },
  914. expectedStaleEndpoints: []ServiceEndpoint{},
  915. expectedStaleServiceNames: map[ServicePortName]bool{},
  916. expectedHealthchecks: map[types.NamespacedName]int{
  917. makeNSN("ns1", "ep1"): 2,
  918. makeNSN("ns2", "ep2"): 1,
  919. },
  920. }, {
  921. name: "add an Endpoints",
  922. previousEndpoints: []*v1.Endpoints{
  923. nil,
  924. },
  925. currentEndpoints: []*v1.Endpoints{
  926. makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
  927. },
  928. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{},
  929. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  930. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): {
  931. {Endpoint: "1.1.1.1:11", IsLocal: true},
  932. },
  933. },
  934. expectedStaleEndpoints: []ServiceEndpoint{},
  935. expectedStaleServiceNames: map[ServicePortName]bool{
  936. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): true,
  937. },
  938. expectedHealthchecks: map[types.NamespacedName]int{
  939. makeNSN("ns1", "ep1"): 1,
  940. },
  941. }, {
  942. name: "remove an Endpoints",
  943. previousEndpoints: []*v1.Endpoints{
  944. makeTestEndpoints("ns1", "ep1", unnamedPortLocal),
  945. },
  946. currentEndpoints: []*v1.Endpoints{
  947. nil,
  948. },
  949. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  950. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): {
  951. {Endpoint: "1.1.1.1:11", IsLocal: true},
  952. },
  953. },
  954. expectedResult: map[ServicePortName][]*BaseEndpointInfo{},
  955. expectedStaleEndpoints: []ServiceEndpoint{{
  956. Endpoint: "1.1.1.1:11",
  957. ServicePortName: makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP),
  958. }},
  959. expectedStaleServiceNames: map[ServicePortName]bool{},
  960. expectedHealthchecks: map[types.NamespacedName]int{},
  961. }, {
  962. name: "add an IP and port",
  963. previousEndpoints: []*v1.Endpoints{
  964. makeTestEndpoints("ns1", "ep1", namedPort),
  965. },
  966. currentEndpoints: []*v1.Endpoints{
  967. makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
  968. },
  969. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  970. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  971. {Endpoint: "1.1.1.1:11", IsLocal: false},
  972. },
  973. },
  974. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  975. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  976. {Endpoint: "1.1.1.1:11", IsLocal: false},
  977. {Endpoint: "1.1.1.2:11", IsLocal: true},
  978. },
  979. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  980. {Endpoint: "1.1.1.1:12", IsLocal: false},
  981. {Endpoint: "1.1.1.2:12", IsLocal: true},
  982. },
  983. },
  984. expectedStaleEndpoints: []ServiceEndpoint{},
  985. expectedStaleServiceNames: map[ServicePortName]bool{
  986. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): true,
  987. },
  988. expectedHealthchecks: map[types.NamespacedName]int{
  989. makeNSN("ns1", "ep1"): 1,
  990. },
  991. }, {
  992. name: "remove an IP and port",
  993. previousEndpoints: []*v1.Endpoints{
  994. makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal),
  995. },
  996. currentEndpoints: []*v1.Endpoints{
  997. makeTestEndpoints("ns1", "ep1", namedPort),
  998. },
  999. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1000. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1001. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1002. {Endpoint: "1.1.1.2:11", IsLocal: true},
  1003. },
  1004. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  1005. {Endpoint: "1.1.1.1:12", IsLocal: false},
  1006. {Endpoint: "1.1.1.2:12", IsLocal: true},
  1007. },
  1008. },
  1009. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1010. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1011. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1012. },
  1013. },
  1014. expectedStaleEndpoints: []ServiceEndpoint{{
  1015. Endpoint: "1.1.1.2:11",
  1016. ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  1017. }, {
  1018. Endpoint: "1.1.1.1:12",
  1019. ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  1020. }, {
  1021. Endpoint: "1.1.1.2:12",
  1022. ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  1023. }},
  1024. expectedStaleServiceNames: map[ServicePortName]bool{},
  1025. expectedHealthchecks: map[types.NamespacedName]int{},
  1026. }, {
  1027. name: "add a subset",
  1028. previousEndpoints: []*v1.Endpoints{
  1029. makeTestEndpoints("ns1", "ep1", namedPort),
  1030. },
  1031. currentEndpoints: []*v1.Endpoints{
  1032. makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal),
  1033. },
  1034. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1035. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1036. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1037. },
  1038. },
  1039. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1040. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1041. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1042. },
  1043. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  1044. {Endpoint: "1.1.1.2:12", IsLocal: true},
  1045. },
  1046. },
  1047. expectedStaleEndpoints: []ServiceEndpoint{},
  1048. expectedStaleServiceNames: map[ServicePortName]bool{
  1049. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): true,
  1050. },
  1051. expectedHealthchecks: map[types.NamespacedName]int{
  1052. makeNSN("ns1", "ep1"): 1,
  1053. },
  1054. }, {
  1055. name: "remove a subset",
  1056. previousEndpoints: []*v1.Endpoints{
  1057. makeTestEndpoints("ns1", "ep1", multipleSubsets),
  1058. },
  1059. currentEndpoints: []*v1.Endpoints{
  1060. makeTestEndpoints("ns1", "ep1", namedPort),
  1061. },
  1062. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1063. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1064. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1065. },
  1066. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  1067. {Endpoint: "1.1.1.2:12", IsLocal: false},
  1068. },
  1069. },
  1070. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1071. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1072. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1073. },
  1074. },
  1075. expectedStaleEndpoints: []ServiceEndpoint{{
  1076. Endpoint: "1.1.1.2:12",
  1077. ServicePortName: makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP),
  1078. }},
  1079. expectedStaleServiceNames: map[ServicePortName]bool{},
  1080. expectedHealthchecks: map[types.NamespacedName]int{},
  1081. }, {
  1082. name: "rename a port",
  1083. previousEndpoints: []*v1.Endpoints{
  1084. makeTestEndpoints("ns1", "ep1", namedPort),
  1085. },
  1086. currentEndpoints: []*v1.Endpoints{
  1087. makeTestEndpoints("ns1", "ep1", namedPortRenamed),
  1088. },
  1089. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1090. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1091. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1092. },
  1093. },
  1094. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1095. makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): {
  1096. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1097. },
  1098. },
  1099. expectedStaleEndpoints: []ServiceEndpoint{{
  1100. Endpoint: "1.1.1.1:11",
  1101. ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  1102. }},
  1103. expectedStaleServiceNames: map[ServicePortName]bool{
  1104. makeServicePortName("ns1", "ep1", "p11-2", v1.ProtocolUDP): true,
  1105. },
  1106. expectedHealthchecks: map[types.NamespacedName]int{},
  1107. }, {
  1108. name: "renumber a port",
  1109. previousEndpoints: []*v1.Endpoints{
  1110. makeTestEndpoints("ns1", "ep1", namedPort),
  1111. },
  1112. currentEndpoints: []*v1.Endpoints{
  1113. makeTestEndpoints("ns1", "ep1", namedPortRenumbered),
  1114. },
  1115. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1116. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1117. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1118. },
  1119. },
  1120. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1121. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1122. {Endpoint: "1.1.1.1:22", IsLocal: false},
  1123. },
  1124. },
  1125. expectedStaleEndpoints: []ServiceEndpoint{{
  1126. Endpoint: "1.1.1.1:11",
  1127. ServicePortName: makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP),
  1128. }},
  1129. expectedStaleServiceNames: map[ServicePortName]bool{},
  1130. expectedHealthchecks: map[types.NamespacedName]int{},
  1131. }, {
  1132. name: "complex add and remove",
  1133. previousEndpoints: []*v1.Endpoints{
  1134. makeTestEndpoints("ns1", "ep1", complexBefore1),
  1135. makeTestEndpoints("ns2", "ep2", complexBefore2),
  1136. nil,
  1137. makeTestEndpoints("ns4", "ep4", complexBefore4),
  1138. },
  1139. currentEndpoints: []*v1.Endpoints{
  1140. makeTestEndpoints("ns1", "ep1", complexAfter1),
  1141. nil,
  1142. makeTestEndpoints("ns3", "ep3", complexAfter3),
  1143. makeTestEndpoints("ns4", "ep4", complexAfter4),
  1144. },
  1145. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{
  1146. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1147. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1148. },
  1149. makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP): {
  1150. {Endpoint: "2.2.2.2:22", IsLocal: true},
  1151. {Endpoint: "2.2.2.22:22", IsLocal: true},
  1152. },
  1153. makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP): {
  1154. {Endpoint: "2.2.2.3:23", IsLocal: true},
  1155. },
  1156. makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): {
  1157. {Endpoint: "4.4.4.4:44", IsLocal: true},
  1158. {Endpoint: "4.4.4.5:44", IsLocal: true},
  1159. },
  1160. makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP): {
  1161. {Endpoint: "4.4.4.6:45", IsLocal: true},
  1162. },
  1163. },
  1164. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1165. makeServicePortName("ns1", "ep1", "p11", v1.ProtocolUDP): {
  1166. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1167. {Endpoint: "1.1.1.11:11", IsLocal: false},
  1168. },
  1169. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): {
  1170. {Endpoint: "1.1.1.2:12", IsLocal: false},
  1171. },
  1172. makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): {
  1173. {Endpoint: "1.1.1.2:122", IsLocal: false},
  1174. },
  1175. makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): {
  1176. {Endpoint: "3.3.3.3:33", IsLocal: false},
  1177. },
  1178. makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP): {
  1179. {Endpoint: "4.4.4.4:44", IsLocal: true},
  1180. },
  1181. },
  1182. expectedStaleEndpoints: []ServiceEndpoint{{
  1183. Endpoint: "2.2.2.2:22",
  1184. ServicePortName: makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP),
  1185. }, {
  1186. Endpoint: "2.2.2.22:22",
  1187. ServicePortName: makeServicePortName("ns2", "ep2", "p22", v1.ProtocolUDP),
  1188. }, {
  1189. Endpoint: "2.2.2.3:23",
  1190. ServicePortName: makeServicePortName("ns2", "ep2", "p23", v1.ProtocolUDP),
  1191. }, {
  1192. Endpoint: "4.4.4.5:44",
  1193. ServicePortName: makeServicePortName("ns4", "ep4", "p44", v1.ProtocolUDP),
  1194. }, {
  1195. Endpoint: "4.4.4.6:45",
  1196. ServicePortName: makeServicePortName("ns4", "ep4", "p45", v1.ProtocolUDP),
  1197. }},
  1198. expectedStaleServiceNames: map[ServicePortName]bool{
  1199. makeServicePortName("ns1", "ep1", "p12", v1.ProtocolUDP): true,
  1200. makeServicePortName("ns1", "ep1", "p122", v1.ProtocolUDP): true,
  1201. makeServicePortName("ns3", "ep3", "p33", v1.ProtocolUDP): true,
  1202. },
  1203. expectedHealthchecks: map[types.NamespacedName]int{
  1204. makeNSN("ns4", "ep4"): 1,
  1205. },
  1206. }, {
  1207. name: "change from 0 endpoint address to 1 unnamed port",
  1208. previousEndpoints: []*v1.Endpoints{
  1209. makeTestEndpoints("ns1", "ep1", emptyEndpoint),
  1210. },
  1211. currentEndpoints: []*v1.Endpoints{
  1212. makeTestEndpoints("ns1", "ep1", unnamedPort),
  1213. },
  1214. oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{},
  1215. expectedResult: map[ServicePortName][]*BaseEndpointInfo{
  1216. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): {
  1217. {Endpoint: "1.1.1.1:11", IsLocal: false},
  1218. },
  1219. },
  1220. expectedStaleEndpoints: []ServiceEndpoint{},
  1221. expectedStaleServiceNames: map[ServicePortName]bool{
  1222. makeServicePortName("ns1", "ep1", "", v1.ProtocolUDP): true,
  1223. },
  1224. expectedHealthchecks: map[types.NamespacedName]int{},
  1225. },
  1226. }
  1227. for tci, tc := range testCases {
  1228. t.Run(tc.name, func(t *testing.T) {
  1229. fp := newFakeProxier()
  1230. fp.hostname = nodeName
  1231. // First check that after adding all previous versions of endpoints,
  1232. // the fp.oldEndpoints is as we expect.
  1233. for i := range tc.previousEndpoints {
  1234. if tc.previousEndpoints[i] != nil {
  1235. fp.addEndpoints(tc.previousEndpoints[i])
  1236. }
  1237. }
  1238. fp.endpointsMap.Update(fp.endpointsChanges)
  1239. compareEndpointsMapsStr(t, fp.endpointsMap, tc.oldEndpoints)
  1240. // Now let's call appropriate handlers to get to state we want to be.
  1241. if len(tc.previousEndpoints) != len(tc.currentEndpoints) {
  1242. t.Fatalf("[%d] different lengths of previous and current endpoints", tci)
  1243. return
  1244. }
  1245. for i := range tc.previousEndpoints {
  1246. prev, curr := tc.previousEndpoints[i], tc.currentEndpoints[i]
  1247. switch {
  1248. case prev == nil:
  1249. fp.addEndpoints(curr)
  1250. case curr == nil:
  1251. fp.deleteEndpoints(prev)
  1252. default:
  1253. fp.updateEndpoints(prev, curr)
  1254. }
  1255. }
  1256. result := fp.endpointsMap.Update(fp.endpointsChanges)
  1257. newMap := fp.endpointsMap
  1258. compareEndpointsMapsStr(t, newMap, tc.expectedResult)
  1259. if len(result.StaleEndpoints) != len(tc.expectedStaleEndpoints) {
  1260. t.Errorf("[%d] expected %d staleEndpoints, got %d: %v", tci, len(tc.expectedStaleEndpoints), len(result.StaleEndpoints), result.StaleEndpoints)
  1261. }
  1262. for _, x := range tc.expectedStaleEndpoints {
  1263. found := false
  1264. for _, stale := range result.StaleEndpoints {
  1265. if stale == x {
  1266. found = true
  1267. break
  1268. }
  1269. }
  1270. if !found {
  1271. t.Errorf("[%d] expected staleEndpoints[%v], but didn't find it: %v", tci, x, result.StaleEndpoints)
  1272. }
  1273. }
  1274. if len(result.StaleServiceNames) != len(tc.expectedStaleServiceNames) {
  1275. t.Errorf("[%d] expected %d staleServiceNames, got %d: %v", tci, len(tc.expectedStaleServiceNames), len(result.StaleServiceNames), result.StaleServiceNames)
  1276. }
  1277. for svcName := range tc.expectedStaleServiceNames {
  1278. found := false
  1279. for _, stale := range result.StaleServiceNames {
  1280. if stale == svcName {
  1281. found = true
  1282. }
  1283. }
  1284. if !found {
  1285. t.Errorf("[%d] expected staleServiceNames[%v], but didn't find it: %v", tci, svcName, result.StaleServiceNames)
  1286. }
  1287. }
  1288. if !reflect.DeepEqual(result.HCEndpointsLocalIPSize, tc.expectedHealthchecks) {
  1289. t.Errorf("[%d] expected healthchecks %v, got %v", tci, tc.expectedHealthchecks, result.HCEndpointsLocalIPSize)
  1290. }
  1291. })
  1292. }
  1293. }
  1294. func TestLastChangeTriggerTime(t *testing.T) {
  1295. t0 := time.Date(2018, 01, 01, 0, 0, 0, 0, time.UTC)
  1296. t1 := t0.Add(time.Second)
  1297. t2 := t1.Add(time.Second)
  1298. t3 := t2.Add(time.Second)
  1299. createEndpoints := func(namespace, name string, triggerTime time.Time) *v1.Endpoints {
  1300. e := makeTestEndpoints(namespace, name, func(ept *v1.Endpoints) {
  1301. ept.Subsets = []v1.EndpointSubset{{
  1302. Addresses: []v1.EndpointAddress{{IP: "1.1.1.1"}},
  1303. Ports: []v1.EndpointPort{{Port: 11}},
  1304. }}
  1305. })
  1306. e.Annotations[v1.EndpointsLastChangeTriggerTime] = triggerTime.Format(time.RFC3339Nano)
  1307. return e
  1308. }
  1309. createName := func(namespace, name string) types.NamespacedName {
  1310. return types.NamespacedName{Namespace: namespace, Name: name}
  1311. }
  1312. modifyEndpoints := func(endpoints *v1.Endpoints, triggerTime time.Time) *v1.Endpoints {
  1313. e := endpoints.DeepCopy()
  1314. e.Subsets[0].Ports[0].Port++
  1315. e.Annotations[v1.EndpointsLastChangeTriggerTime] = triggerTime.Format(time.RFC3339Nano)
  1316. return e
  1317. }
  1318. testCases := []struct {
  1319. name string
  1320. scenario func(fp *FakeProxier)
  1321. expected map[types.NamespacedName][]time.Time
  1322. }{
  1323. {
  1324. name: "Single addEndpoints",
  1325. scenario: func(fp *FakeProxier) {
  1326. e := createEndpoints("ns", "ep1", t0)
  1327. fp.addEndpoints(e)
  1328. },
  1329. expected: map[types.NamespacedName][]time.Time{createName("ns", "ep1"): {t0}},
  1330. },
  1331. {
  1332. name: "addEndpoints then updatedEndpoints",
  1333. scenario: func(fp *FakeProxier) {
  1334. e := createEndpoints("ns", "ep1", t0)
  1335. fp.addEndpoints(e)
  1336. e1 := modifyEndpoints(e, t1)
  1337. fp.updateEndpoints(e, e1)
  1338. },
  1339. expected: map[types.NamespacedName][]time.Time{createName("ns", "ep1"): {t0, t1}},
  1340. },
  1341. {
  1342. name: "Add two endpoints then modify one",
  1343. scenario: func(fp *FakeProxier) {
  1344. e1 := createEndpoints("ns", "ep1", t1)
  1345. fp.addEndpoints(e1)
  1346. e2 := createEndpoints("ns", "ep2", t2)
  1347. fp.addEndpoints(e2)
  1348. e11 := modifyEndpoints(e1, t3)
  1349. fp.updateEndpoints(e1, e11)
  1350. },
  1351. expected: map[types.NamespacedName][]time.Time{createName("ns", "ep1"): {t1, t3}, createName("ns", "ep2"): {t2}},
  1352. },
  1353. {
  1354. name: "Endpoints without annotation set",
  1355. scenario: func(fp *FakeProxier) {
  1356. e := createEndpoints("ns", "ep1", t1)
  1357. delete(e.Annotations, v1.EndpointsLastChangeTriggerTime)
  1358. fp.addEndpoints(e)
  1359. },
  1360. expected: map[types.NamespacedName][]time.Time{},
  1361. },
  1362. {
  1363. name: "addEndpoints then deleteEndpoints",
  1364. scenario: func(fp *FakeProxier) {
  1365. e := createEndpoints("ns", "ep1", t1)
  1366. fp.addEndpoints(e)
  1367. fp.deleteEndpoints(e)
  1368. },
  1369. expected: map[types.NamespacedName][]time.Time{},
  1370. },
  1371. {
  1372. name: "add then delete then add again",
  1373. scenario: func(fp *FakeProxier) {
  1374. e := createEndpoints("ns", "ep1", t1)
  1375. fp.addEndpoints(e)
  1376. fp.deleteEndpoints(e)
  1377. e = modifyEndpoints(e, t2)
  1378. fp.addEndpoints(e)
  1379. },
  1380. expected: map[types.NamespacedName][]time.Time{createName("ns", "ep1"): {t2}},
  1381. },
  1382. }
  1383. for _, tc := range testCases {
  1384. fp := newFakeProxier()
  1385. tc.scenario(fp)
  1386. result := fp.endpointsMap.Update(fp.endpointsChanges)
  1387. got := result.LastChangeTriggerTimes
  1388. if !reflect.DeepEqual(got, tc.expected) {
  1389. t.Errorf("%s: Invalid LastChangeTriggerTimes, expected: %v, got: %v",
  1390. tc.name, tc.expected, result.LastChangeTriggerTimes)
  1391. }
  1392. }
  1393. }
  1394. func TestEndpointSliceUpdate(t *testing.T) {
  1395. fqdnSlice := generateEndpointSlice("svc1", "ns1", 2, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)})
  1396. fqdnSlice.AddressType = discovery.AddressTypeFQDN
  1397. testCases := map[string]struct {
  1398. startingSlices []*discovery.EndpointSlice
  1399. endpointChangeTracker *EndpointChangeTracker
  1400. namespacedName types.NamespacedName
  1401. paramEndpointSlice *discovery.EndpointSlice
  1402. paramRemoveSlice bool
  1403. expectedReturnVal bool
  1404. expectedCurrentChange map[ServicePortName][]*BaseEndpointInfo
  1405. }{
  1406. // test starting from an empty state
  1407. "add a simple slice that doesn't already exist": {
  1408. startingSlices: []*discovery.EndpointSlice{},
  1409. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1410. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1411. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1412. paramRemoveSlice: false,
  1413. expectedReturnVal: true,
  1414. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1415. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1416. &BaseEndpointInfo{Endpoint: "10.0.1.1:80"},
  1417. &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true},
  1418. &BaseEndpointInfo{Endpoint: "10.0.1.3:80"},
  1419. },
  1420. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1421. &BaseEndpointInfo{Endpoint: "10.0.1.1:443"},
  1422. &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true},
  1423. &BaseEndpointInfo{Endpoint: "10.0.1.3:443"},
  1424. },
  1425. },
  1426. },
  1427. // test no modification to state - current change should be nil as nothing changes
  1428. "add the same slice that already exists": {
  1429. startingSlices: []*discovery.EndpointSlice{
  1430. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1431. },
  1432. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1433. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1434. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1435. paramRemoveSlice: false,
  1436. expectedReturnVal: false,
  1437. expectedCurrentChange: nil,
  1438. },
  1439. // ensure that only valide address types are processed
  1440. "add an FQDN slice (invalid address type)": {
  1441. startingSlices: []*discovery.EndpointSlice{
  1442. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1443. },
  1444. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1445. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1446. paramEndpointSlice: fqdnSlice,
  1447. paramRemoveSlice: false,
  1448. expectedReturnVal: false,
  1449. expectedCurrentChange: nil,
  1450. },
  1451. // test additions to existing state
  1452. "add a slice that overlaps with existing state": {
  1453. startingSlices: []*discovery.EndpointSlice{
  1454. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1455. generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1456. },
  1457. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1458. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1459. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1460. paramRemoveSlice: false,
  1461. expectedReturnVal: true,
  1462. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1463. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1464. &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true},
  1465. &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true},
  1466. &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true},
  1467. &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true},
  1468. &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true},
  1469. &BaseEndpointInfo{Endpoint: "10.0.2.1:80"},
  1470. &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true},
  1471. },
  1472. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1473. &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true},
  1474. &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true},
  1475. &BaseEndpointInfo{Endpoint: "10.0.1.3:443", IsLocal: true},
  1476. &BaseEndpointInfo{Endpoint: "10.0.1.4:443", IsLocal: true},
  1477. &BaseEndpointInfo{Endpoint: "10.0.1.5:443", IsLocal: true},
  1478. &BaseEndpointInfo{Endpoint: "10.0.2.1:443"},
  1479. &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true},
  1480. },
  1481. },
  1482. },
  1483. // test additions to existing state with partially overlapping slices and ports
  1484. "add a slice that overlaps with existing state and partial ports": {
  1485. startingSlices: []*discovery.EndpointSlice{
  1486. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1487. generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1488. },
  1489. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1490. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1491. paramEndpointSlice: generateEndpointSliceWithOffset("svc1", "ns1", 3, 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}),
  1492. paramRemoveSlice: false,
  1493. expectedReturnVal: true,
  1494. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1495. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1496. &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true},
  1497. &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true},
  1498. &BaseEndpointInfo{Endpoint: "10.0.1.3:80", IsLocal: true},
  1499. &BaseEndpointInfo{Endpoint: "10.0.1.4:80", IsLocal: true},
  1500. &BaseEndpointInfo{Endpoint: "10.0.1.5:80", IsLocal: true},
  1501. &BaseEndpointInfo{Endpoint: "10.0.2.1:80"},
  1502. &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true},
  1503. },
  1504. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1505. &BaseEndpointInfo{Endpoint: "10.0.1.1:443"},
  1506. &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true},
  1507. &BaseEndpointInfo{Endpoint: "10.0.1.3:443"},
  1508. &BaseEndpointInfo{Endpoint: "10.0.2.1:443"},
  1509. &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true},
  1510. },
  1511. },
  1512. },
  1513. // test deletions from existing state with partially overlapping slices and ports
  1514. "remove a slice that overlaps with existing state": {
  1515. startingSlices: []*discovery.EndpointSlice{
  1516. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1517. generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1518. },
  1519. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1520. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1521. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1522. paramRemoveSlice: true,
  1523. expectedReturnVal: true,
  1524. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1525. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1526. &BaseEndpointInfo{Endpoint: "10.0.2.1:80"},
  1527. &BaseEndpointInfo{Endpoint: "10.0.2.2:80", IsLocal: true},
  1528. },
  1529. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1530. &BaseEndpointInfo{Endpoint: "10.0.2.1:443"},
  1531. &BaseEndpointInfo{Endpoint: "10.0.2.2:443", IsLocal: true},
  1532. },
  1533. },
  1534. },
  1535. // ensure a removal that has no effect turns into a no-op
  1536. "remove a slice that doesn't even exist in current state": {
  1537. startingSlices: []*discovery.EndpointSlice{
  1538. generateEndpointSlice("svc1", "ns1", 1, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1539. generateEndpointSlice("svc1", "ns1", 2, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1540. },
  1541. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1542. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1543. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 3, 5, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1544. paramRemoveSlice: true,
  1545. expectedReturnVal: false,
  1546. expectedCurrentChange: nil,
  1547. },
  1548. // start with all endpoints ready, transition to no endpoints ready
  1549. "transition all endpoints to unready state": {
  1550. startingSlices: []*discovery.EndpointSlice{
  1551. generateEndpointSlice("svc1", "ns1", 1, 3, 999, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1552. },
  1553. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1554. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1555. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 1, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1556. paramRemoveSlice: false,
  1557. expectedReturnVal: true,
  1558. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{},
  1559. },
  1560. // start with no endpoints ready, transition to all endpoints ready
  1561. "transition all endpoints to ready state": {
  1562. startingSlices: []*discovery.EndpointSlice{
  1563. generateEndpointSlice("svc1", "ns1", 1, 2, 1, []string{"host1", "host2"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1564. },
  1565. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1566. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1567. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 2, 999, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1568. paramRemoveSlice: false,
  1569. expectedReturnVal: true,
  1570. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1571. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1572. &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true},
  1573. &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true},
  1574. },
  1575. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1576. &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true},
  1577. &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true},
  1578. },
  1579. },
  1580. },
  1581. // start with some endpoints ready, transition to more endpoints ready
  1582. "transition some endpoints to ready state": {
  1583. startingSlices: []*discovery.EndpointSlice{
  1584. generateEndpointSlice("svc1", "ns1", 1, 3, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1585. generateEndpointSlice("svc1", "ns1", 2, 2, 2, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1586. },
  1587. endpointChangeTracker: NewEndpointChangeTracker("host1", nil, nil, nil, true),
  1588. namespacedName: types.NamespacedName{Name: "svc1", Namespace: "ns1"},
  1589. paramEndpointSlice: generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1590. paramRemoveSlice: false,
  1591. expectedReturnVal: true,
  1592. expectedCurrentChange: map[ServicePortName][]*BaseEndpointInfo{
  1593. makeServicePortName("ns1", "svc1", "port-0", v1.ProtocolTCP): {
  1594. &BaseEndpointInfo{Endpoint: "10.0.1.1:80", IsLocal: true},
  1595. &BaseEndpointInfo{Endpoint: "10.0.1.2:80", IsLocal: true},
  1596. &BaseEndpointInfo{Endpoint: "10.0.2.1:80", IsLocal: true},
  1597. },
  1598. makeServicePortName("ns1", "svc1", "port-1", v1.ProtocolTCP): {
  1599. &BaseEndpointInfo{Endpoint: "10.0.1.1:443", IsLocal: true},
  1600. &BaseEndpointInfo{Endpoint: "10.0.1.2:443", IsLocal: true},
  1601. &BaseEndpointInfo{Endpoint: "10.0.2.1:443", IsLocal: true},
  1602. },
  1603. },
  1604. },
  1605. }
  1606. for name, tc := range testCases {
  1607. t.Run(name, func(t *testing.T) {
  1608. initializeCache(tc.endpointChangeTracker.endpointSliceCache, tc.startingSlices)
  1609. got := tc.endpointChangeTracker.EndpointSliceUpdate(tc.paramEndpointSlice, tc.paramRemoveSlice)
  1610. if !reflect.DeepEqual(got, tc.expectedReturnVal) {
  1611. t.Errorf("EndpointSliceUpdate return value got: %v, want %v", got, tc.expectedReturnVal)
  1612. }
  1613. if tc.endpointChangeTracker.items == nil {
  1614. t.Errorf("Expected ect.items to not be nil")
  1615. }
  1616. changes := tc.endpointChangeTracker.checkoutChanges()
  1617. if tc.expectedCurrentChange == nil {
  1618. if len(changes) != 0 {
  1619. t.Errorf("Expected %s to have no changes", tc.namespacedName)
  1620. }
  1621. } else {
  1622. if len(changes) == 0 || changes[0] == nil {
  1623. t.Fatalf("Expected %s to have changes", tc.namespacedName)
  1624. }
  1625. compareEndpointsMapsStr(t, changes[0].current, tc.expectedCurrentChange)
  1626. }
  1627. })
  1628. }
  1629. }
  1630. func TestCheckoutChanges(t *testing.T) {
  1631. svcPortName0 := ServicePortName{types.NamespacedName{Namespace: "ns1", Name: "svc1"}, "port-0", v1.ProtocolTCP}
  1632. svcPortName1 := ServicePortName{types.NamespacedName{Namespace: "ns1", Name: "svc1"}, "port-1", v1.ProtocolTCP}
  1633. testCases := map[string]struct {
  1634. endpointChangeTracker *EndpointChangeTracker
  1635. expectedChanges []*endpointsChange
  1636. useEndpointSlices bool
  1637. items map[types.NamespacedName]*endpointsChange
  1638. appliedSlices []*discovery.EndpointSlice
  1639. pendingSlices []*discovery.EndpointSlice
  1640. }{
  1641. "empty slices": {
  1642. endpointChangeTracker: NewEndpointChangeTracker("", nil, nil, nil, true),
  1643. expectedChanges: []*endpointsChange{},
  1644. useEndpointSlices: true,
  1645. appliedSlices: []*discovery.EndpointSlice{},
  1646. pendingSlices: []*discovery.EndpointSlice{},
  1647. },
  1648. "without slices, empty items": {
  1649. endpointChangeTracker: NewEndpointChangeTracker("", nil, nil, nil, false),
  1650. expectedChanges: []*endpointsChange{},
  1651. items: map[types.NamespacedName]*endpointsChange{},
  1652. useEndpointSlices: false,
  1653. },
  1654. "without slices, simple items": {
  1655. endpointChangeTracker: NewEndpointChangeTracker("", nil, nil, nil, false),
  1656. expectedChanges: []*endpointsChange{{
  1657. previous: EndpointsMap{
  1658. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")},
  1659. svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", ""), newTestEp("10.0.1.2:443", "")},
  1660. },
  1661. current: EndpointsMap{
  1662. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")},
  1663. },
  1664. }},
  1665. items: map[types.NamespacedName]*endpointsChange{
  1666. {Namespace: "ns1", Name: "svc1"}: {
  1667. previous: EndpointsMap{
  1668. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")},
  1669. svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", ""), newTestEp("10.0.1.2:443", "")},
  1670. },
  1671. current: EndpointsMap{
  1672. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", ""), newTestEp("10.0.1.2:80", "")},
  1673. },
  1674. },
  1675. },
  1676. useEndpointSlices: false,
  1677. },
  1678. "adding initial slice": {
  1679. endpointChangeTracker: NewEndpointChangeTracker("", nil, nil, nil, true),
  1680. expectedChanges: []*endpointsChange{{
  1681. previous: EndpointsMap{},
  1682. current: EndpointsMap{
  1683. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")},
  1684. },
  1685. }},
  1686. useEndpointSlices: true,
  1687. appliedSlices: []*discovery.EndpointSlice{},
  1688. pendingSlices: []*discovery.EndpointSlice{
  1689. generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}),
  1690. },
  1691. },
  1692. "removing port in update": {
  1693. endpointChangeTracker: NewEndpointChangeTracker("", nil, nil, nil, true),
  1694. expectedChanges: []*endpointsChange{{
  1695. previous: EndpointsMap{
  1696. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")},
  1697. svcPortName1: []Endpoint{newTestEp("10.0.1.1:443", "host1"), newTestEp("10.0.1.2:443", "host1")},
  1698. },
  1699. current: EndpointsMap{
  1700. svcPortName0: []Endpoint{newTestEp("10.0.1.1:80", "host1"), newTestEp("10.0.1.2:80", "host1")},
  1701. },
  1702. }},
  1703. useEndpointSlices: true,
  1704. appliedSlices: []*discovery.EndpointSlice{
  1705. generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80), utilpointer.Int32Ptr(443)}),
  1706. },
  1707. pendingSlices: []*discovery.EndpointSlice{
  1708. generateEndpointSlice("svc1", "ns1", 1, 3, 3, []string{"host1"}, []*int32{utilpointer.Int32Ptr(80)}),
  1709. },
  1710. },
  1711. }
  1712. for name, tc := range testCases {
  1713. t.Run(name, func(t *testing.T) {
  1714. if tc.useEndpointSlices {
  1715. for _, slice := range tc.appliedSlices {
  1716. tc.endpointChangeTracker.EndpointSliceUpdate(slice, false)
  1717. }
  1718. tc.endpointChangeTracker.checkoutChanges()
  1719. for _, slice := range tc.pendingSlices {
  1720. tc.endpointChangeTracker.EndpointSliceUpdate(slice, false)
  1721. }
  1722. } else {
  1723. tc.endpointChangeTracker.items = tc.items
  1724. }
  1725. changes := tc.endpointChangeTracker.checkoutChanges()
  1726. if len(tc.expectedChanges) != len(changes) {
  1727. t.Fatalf("Expected %d changes, got %d", len(tc.expectedChanges), len(changes))
  1728. }
  1729. for i, change := range changes {
  1730. expectedChange := tc.expectedChanges[i]
  1731. if !reflect.DeepEqual(change.previous, expectedChange.previous) {
  1732. t.Errorf("[%d] Expected change.previous: %+v, got: %+v", i, expectedChange.previous, change.previous)
  1733. }
  1734. if !reflect.DeepEqual(change.current, expectedChange.current) {
  1735. t.Errorf("[%d] Expected change.current: %+v, got: %+v", i, expectedChange.current, change.current)
  1736. }
  1737. }
  1738. })
  1739. }
  1740. }
  1741. // Test helpers
  1742. func compareEndpointsMapsStr(t *testing.T, newMap EndpointsMap, expected map[ServicePortName][]*BaseEndpointInfo) {
  1743. t.Helper()
  1744. if len(newMap) != len(expected) {
  1745. t.Errorf("expected %d results, got %d: %v", len(expected), len(newMap), newMap)
  1746. }
  1747. endpointEqual := func(a, b *BaseEndpointInfo) bool {
  1748. return a.Endpoint == b.Endpoint && a.IsLocal == b.IsLocal
  1749. }
  1750. for x := range expected {
  1751. if len(newMap[x]) != len(expected[x]) {
  1752. t.Errorf("expected %d endpoints for %v, got %d", len(expected[x]), x, len(newMap[x]))
  1753. t.Logf("Endpoints %+v", newMap[x])
  1754. } else {
  1755. for i := range expected[x] {
  1756. newEp, ok := newMap[x][i].(*BaseEndpointInfo)
  1757. if !ok {
  1758. t.Errorf("Failed to cast endpointsInfo")
  1759. continue
  1760. }
  1761. if !endpointEqual(newEp, expected[x][i]) {
  1762. t.Errorf("expected new[%v][%d] to be %v, got %v (IsLocal expected %v, got %v)", x, i, expected[x][i], newEp, expected[x][i].IsLocal, newEp.IsLocal)
  1763. }
  1764. }
  1765. }
  1766. }
  1767. }
  1768. func newTestEp(ep, host string) *BaseEndpointInfo {
  1769. endpointInfo := &BaseEndpointInfo{Endpoint: ep}
  1770. if host != "" {
  1771. endpointInfo.Topology = map[string]string{
  1772. "kubernetes.io/hostname": host,
  1773. }
  1774. }
  1775. return endpointInfo
  1776. }
  1777. func initializeCache(endpointSliceCache *EndpointSliceCache, endpointSlices []*discovery.EndpointSlice) {
  1778. for _, endpointSlice := range endpointSlices {
  1779. endpointSliceCache.updatePending(endpointSlice, false)
  1780. }
  1781. for _, tracker := range endpointSliceCache.trackerByServiceMap {
  1782. tracker.applied = tracker.pending
  1783. tracker.pending = endpointSliceInfoByName{}
  1784. }
  1785. }