1
16
17 package reconcilers
18
19 import (
20 "testing"
21
22 corev1 "k8s.io/api/core/v1"
23 "k8s.io/apimachinery/pkg/runtime"
24 "k8s.io/client-go/kubernetes/fake"
25 netutils "k8s.io/utils/net"
26 )
27
28 func TestMasterCountEndpointReconciler(t *testing.T) {
29 reconcileTests := []struct {
30 testName string
31 serviceName string
32 ip string
33 endpointPorts []corev1.EndpointPort
34 additionalMasters int
35 initialState []runtime.Object
36 expectUpdate []runtime.Object
37 expectCreate []runtime.Object
38 }{
39 {
40 testName: "no existing endpoints",
41 serviceName: "foo",
42 ip: "1.2.3.4",
43 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
44 initialState: nil,
45 expectCreate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
46 },
47 {
48 testName: "existing endpoints satisfy",
49 serviceName: "foo",
50 ip: "1.2.3.4",
51 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
52 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
53 },
54 {
55 testName: "existing endpoints satisfy, no endpointslice",
56 serviceName: "foo",
57 ip: "1.2.3.4",
58 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
59 initialState: []runtime.Object{
60 makeEndpoints("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
61 },
62 expectCreate: []runtime.Object{
63 makeEndpointSlice("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
64 },
65 },
66 {
67 testName: "existing endpointslice satisfies, no endpoints",
68 serviceName: "foo",
69 ip: "1.2.3.4",
70 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
71 initialState: []runtime.Object{
72 makeEndpointSlice("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
73 },
74 expectCreate: []runtime.Object{
75 makeEndpoints("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
76 },
77 },
78 {
79 testName: "existing endpoints satisfy, endpointslice is wrong",
80 serviceName: "foo",
81 ip: "1.2.3.4",
82 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
83 initialState: []runtime.Object{
84 makeEndpoints("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
85 makeEndpointSlice("foo", []string{"4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
86 },
87 expectUpdate: []runtime.Object{
88 makeEndpointSlice("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
89 },
90 },
91 {
92 testName: "existing endpointslice satisfies, endpoints is wrong",
93 serviceName: "foo",
94 ip: "1.2.3.4",
95 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
96 initialState: []runtime.Object{
97 makeEndpoints("foo", []string{"4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
98 makeEndpointSlice("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
99 },
100 expectUpdate: []runtime.Object{
101 makeEndpoints("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
102 },
103 },
104 {
105 testName: "existing endpoints satisfy but too many",
106 serviceName: "foo",
107 ip: "1.2.3.4",
108 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
109 initialState: makeEndpointsArray("foo", []string{"1.2.3.4", "4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
110 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
111 },
112 {
113 testName: "existing endpoints satisfy but too many + extra masters",
114 serviceName: "foo",
115 ip: "1.2.3.4",
116 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
117 additionalMasters: 3,
118 initialState: makeEndpointsArray("foo", []string{"1.2.3.4", "4.3.2.1", "4.3.2.2", "4.3.2.3", "4.3.2.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
119 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4", "4.3.2.2", "4.3.2.3", "4.3.2.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
120 },
121 {
122 testName: "existing endpoints satisfy but too many + extra masters + delete first",
123 serviceName: "foo",
124 ip: "4.3.2.4",
125 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
126 additionalMasters: 3,
127 initialState: makeEndpointsArray("foo", []string{"1.2.3.4", "4.3.2.1", "4.3.2.2", "4.3.2.3", "4.3.2.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
128 expectUpdate: makeEndpointsArray("foo", []string{"4.3.2.1", "4.3.2.2", "4.3.2.3", "4.3.2.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
129 },
130 {
131 testName: "existing endpoints satisfy and endpoint addresses length less than master count",
132 serviceName: "foo",
133 ip: "4.3.2.2",
134 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
135 additionalMasters: 3,
136 initialState: makeEndpointsArray("foo", []string{"4.3.2.1", "4.3.2.2"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
137 expectUpdate: nil,
138 },
139 {
140 testName: "existing endpoints current IP missing and address length less than master count",
141 serviceName: "foo",
142 ip: "4.3.2.2",
143 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
144 additionalMasters: 3,
145 initialState: makeEndpointsArray("foo", []string{"4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
146 expectUpdate: makeEndpointsArray("foo", []string{"4.3.2.1", "4.3.2.2"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
147 },
148 {
149 testName: "existing endpoints wrong name",
150 serviceName: "foo",
151 ip: "1.2.3.4",
152 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
153 initialState: makeEndpointsArray("bar", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
154 expectCreate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
155 },
156 {
157 testName: "existing endpoints wrong IP",
158 serviceName: "foo",
159 ip: "1.2.3.4",
160 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
161 initialState: makeEndpointsArray("foo", []string{"4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
162 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
163 },
164 {
165 testName: "existing endpoints wrong port",
166 serviceName: "foo",
167 ip: "1.2.3.4",
168 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
169 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 9090, Protocol: "TCP"}}),
170 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
171 },
172 {
173 testName: "existing endpoints wrong protocol",
174 serviceName: "foo",
175 ip: "1.2.3.4",
176 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
177 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "UDP"}}),
178 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
179 },
180 {
181 testName: "existing endpoints wrong port name",
182 serviceName: "foo",
183 ip: "1.2.3.4",
184 endpointPorts: []corev1.EndpointPort{{Name: "baz", Port: 8080, Protocol: "TCP"}},
185 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
186 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "baz", Port: 8080, Protocol: "TCP"}}),
187 },
188 {
189 testName: "existing endpoints extra service ports satisfy",
190 serviceName: "foo",
191 ip: "1.2.3.4",
192 endpointPorts: []corev1.EndpointPort{
193 {Name: "foo", Port: 8080, Protocol: "TCP"},
194 {Name: "bar", Port: 1000, Protocol: "TCP"},
195 {Name: "baz", Port: 1010, Protocol: "TCP"},
196 },
197 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"},
198 []corev1.EndpointPort{
199 {Name: "foo", Port: 8080, Protocol: "TCP"},
200 {Name: "bar", Port: 1000, Protocol: "TCP"},
201 {Name: "baz", Port: 1010, Protocol: "TCP"},
202 },
203 ),
204 },
205 {
206 testName: "existing endpoints extra service ports missing port",
207 serviceName: "foo",
208 ip: "1.2.3.4",
209 endpointPorts: []corev1.EndpointPort{
210 {Name: "foo", Port: 8080, Protocol: "TCP"},
211 {Name: "bar", Port: 1000, Protocol: "TCP"},
212 },
213 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
214 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"},
215 []corev1.EndpointPort{
216 {Name: "foo", Port: 8080, Protocol: "TCP"},
217 {Name: "bar", Port: 1000, Protocol: "TCP"},
218 },
219 ),
220 },
221 {
222 testName: "no existing sctp endpoints",
223 serviceName: "boo",
224 ip: "1.2.3.4",
225 endpointPorts: []corev1.EndpointPort{{Name: "boo", Port: 7777, Protocol: "SCTP"}},
226 initialState: nil,
227 expectCreate: makeEndpointsArray("boo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "boo", Port: 7777, Protocol: "SCTP"}}),
228 },
229 }
230 for _, test := range reconcileTests {
231 t.Run(test.testName, func(t *testing.T) {
232 fakeClient := fake.NewSimpleClientset(test.initialState...)
233 epAdapter := NewEndpointsAdapter(fakeClient.CoreV1(), fakeClient.DiscoveryV1())
234 reconciler := NewMasterCountEndpointReconciler(test.additionalMasters+1, epAdapter)
235 err := reconciler.ReconcileEndpoints(test.serviceName, netutils.ParseIPSloppy(test.ip), test.endpointPorts, true)
236 if err != nil {
237 t.Errorf("unexpected error reconciling: %v", err)
238 }
239
240 err = verifyCreatesAndUpdates(fakeClient, test.expectCreate, test.expectUpdate)
241 if err != nil {
242 t.Errorf("unexpected error in side effects: %v", err)
243 }
244 })
245 }
246
247 nonReconcileTests := []struct {
248 testName string
249 serviceName string
250 ip string
251 endpointPorts []corev1.EndpointPort
252 additionalMasters int
253 initialState []runtime.Object
254 expectUpdate []runtime.Object
255 expectCreate []runtime.Object
256 }{
257 {
258 testName: "existing endpoints extra service ports missing port no update",
259 serviceName: "foo",
260 ip: "1.2.3.4",
261 endpointPorts: []corev1.EndpointPort{
262 {Name: "foo", Port: 8080, Protocol: "TCP"},
263 {Name: "bar", Port: 1000, Protocol: "TCP"},
264 },
265 initialState: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
266 expectUpdate: nil,
267 },
268 {
269 testName: "existing endpoints extra service ports, wrong ports, wrong IP",
270 serviceName: "foo",
271 ip: "1.2.3.4",
272 endpointPorts: []corev1.EndpointPort{
273 {Name: "foo", Port: 8080, Protocol: "TCP"},
274 {Name: "bar", Port: 1000, Protocol: "TCP"},
275 },
276 initialState: makeEndpointsArray("foo", []string{"4.3.2.1"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
277 expectUpdate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
278 },
279 {
280 testName: "no existing endpoints",
281 serviceName: "foo",
282 ip: "1.2.3.4",
283 endpointPorts: []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}},
284 initialState: nil,
285 expectCreate: makeEndpointsArray("foo", []string{"1.2.3.4"}, []corev1.EndpointPort{{Name: "foo", Port: 8080, Protocol: "TCP"}}),
286 },
287 }
288 for _, test := range nonReconcileTests {
289 t.Run(test.testName, func(t *testing.T) {
290 fakeClient := fake.NewSimpleClientset(test.initialState...)
291 epAdapter := NewEndpointsAdapter(fakeClient.CoreV1(), fakeClient.DiscoveryV1())
292 reconciler := NewMasterCountEndpointReconciler(test.additionalMasters+1, epAdapter)
293 err := reconciler.ReconcileEndpoints(test.serviceName, netutils.ParseIPSloppy(test.ip), test.endpointPorts, false)
294 if err != nil {
295 t.Errorf("unexpected error reconciling: %v", err)
296 }
297
298 err = verifyCreatesAndUpdates(fakeClient, test.expectCreate, test.expectUpdate)
299 if err != nil {
300 t.Errorf("unexpected error in side effects: %v", err)
301 }
302 })
303 }
304 }
305
306 func TestEmptySubsets(t *testing.T) {
307 endpoints := makeEndpointsArray("foo", nil, nil)
308 fakeClient := fake.NewSimpleClientset(endpoints...)
309 epAdapter := NewEndpointsAdapter(fakeClient.CoreV1(), fakeClient.DiscoveryV1())
310 reconciler := NewMasterCountEndpointReconciler(1, epAdapter)
311 endpointPorts := []corev1.EndpointPort{
312 {Name: "foo", Port: 8080, Protocol: "TCP"},
313 }
314 err := reconciler.RemoveEndpoints("foo", netutils.ParseIPSloppy("1.2.3.4"), endpointPorts)
315 if err != nil {
316 t.Errorf("unexpected error: %v", err)
317 }
318 }
319
View as plain text