k8s.io/kubernetes@v1.29.3/pkg/controlplane/reconcilers/instancecount_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 }