k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/controlplane/controller/kubernetesservice/controller_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 kubernetesservice 18 19 import ( 20 "reflect" 21 "testing" 22 "time" 23 24 corev1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/util/intstr" 27 v1informers "k8s.io/client-go/informers/core/v1" 28 "k8s.io/client-go/kubernetes/fake" 29 v1listers "k8s.io/client-go/listers/core/v1" 30 core "k8s.io/client-go/testing" 31 "k8s.io/client-go/tools/cache" 32 netutils "k8s.io/utils/net" 33 ) 34 35 func TestCreateOrUpdateMasterService(t *testing.T) { 36 singleStack := corev1.IPFamilyPolicySingleStack 37 ns := metav1.NamespaceDefault 38 om := func(name string) metav1.ObjectMeta { 39 return metav1.ObjectMeta{Namespace: ns, Name: name} 40 } 41 42 createTests := []struct { 43 testName string 44 serviceName string 45 servicePorts []corev1.ServicePort 46 serviceType corev1.ServiceType 47 expectCreate *corev1.Service // nil means none expected 48 }{ 49 { 50 testName: "service does not exist", 51 serviceName: "foo", 52 servicePorts: []corev1.ServicePort{ 53 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 54 }, 55 serviceType: corev1.ServiceTypeClusterIP, 56 expectCreate: &corev1.Service{ 57 ObjectMeta: om("foo"), 58 Spec: corev1.ServiceSpec{ 59 Ports: []corev1.ServicePort{ 60 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 61 }, 62 Selector: nil, 63 ClusterIP: "1.2.3.4", 64 IPFamilyPolicy: &singleStack, 65 SessionAffinity: corev1.ServiceAffinityNone, 66 Type: corev1.ServiceTypeClusterIP, 67 }, 68 }, 69 }, 70 } 71 for _, test := range createTests { 72 t.Run(test.testName, func(t *testing.T) { 73 master := Controller{} 74 fakeClient := fake.NewSimpleClientset() 75 serviceStore := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) 76 master.serviceLister = v1listers.NewServiceLister(serviceStore) 77 master.client = fakeClient 78 master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, false) 79 creates := []core.CreateAction{} 80 for _, action := range fakeClient.Actions() { 81 if action.GetVerb() == "create" { 82 creates = append(creates, action.(core.CreateAction)) 83 } 84 } 85 if test.expectCreate != nil { 86 if len(creates) != 1 { 87 t.Errorf("case %q: unexpected creations: %v", test.testName, creates) 88 } else { 89 obj := creates[0].GetObject() 90 if e, a := test.expectCreate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) { 91 t.Errorf("case %q: expected create:\n%#v\ngot:\n%#v\n", test.testName, e, a) 92 } 93 } 94 } 95 if test.expectCreate == nil && len(creates) > 1 { 96 t.Errorf("case %q: no create expected, yet saw: %v", test.testName, creates) 97 } 98 }) 99 } 100 101 reconcileTests := []struct { 102 testName string 103 serviceName string 104 servicePorts []corev1.ServicePort 105 serviceType corev1.ServiceType 106 service *corev1.Service 107 expectUpdate *corev1.Service // nil means none expected 108 }{ 109 { 110 testName: "service definition wrong port", 111 serviceName: "foo", 112 servicePorts: []corev1.ServicePort{ 113 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 114 }, 115 serviceType: corev1.ServiceTypeClusterIP, 116 service: &corev1.Service{ 117 ObjectMeta: om("foo"), 118 Spec: corev1.ServiceSpec{ 119 Ports: []corev1.ServicePort{ 120 {Name: "foo", Port: 8000, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 121 }, 122 Selector: nil, 123 ClusterIP: "1.2.3.4", 124 SessionAffinity: corev1.ServiceAffinityNone, 125 Type: corev1.ServiceTypeClusterIP, 126 }, 127 }, 128 expectUpdate: &corev1.Service{ 129 ObjectMeta: om("foo"), 130 Spec: corev1.ServiceSpec{ 131 Ports: []corev1.ServicePort{ 132 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 133 }, 134 Selector: nil, 135 ClusterIP: "1.2.3.4", 136 SessionAffinity: corev1.ServiceAffinityNone, 137 Type: corev1.ServiceTypeClusterIP, 138 }, 139 }, 140 }, 141 { 142 testName: "service definition missing port", 143 serviceName: "foo", 144 servicePorts: []corev1.ServicePort{ 145 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 146 {Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)}, 147 }, 148 serviceType: corev1.ServiceTypeClusterIP, 149 service: &corev1.Service{ 150 ObjectMeta: om("foo"), 151 Spec: corev1.ServiceSpec{ 152 Ports: []corev1.ServicePort{ 153 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 154 }, 155 Selector: nil, 156 ClusterIP: "1.2.3.4", 157 SessionAffinity: corev1.ServiceAffinityNone, 158 Type: corev1.ServiceTypeClusterIP, 159 }, 160 }, 161 expectUpdate: &corev1.Service{ 162 ObjectMeta: om("foo"), 163 Spec: corev1.ServiceSpec{ 164 Ports: []corev1.ServicePort{ 165 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 166 {Name: "baz", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)}, 167 }, 168 Selector: nil, 169 ClusterIP: "1.2.3.4", 170 SessionAffinity: corev1.ServiceAffinityNone, 171 Type: corev1.ServiceTypeClusterIP, 172 }, 173 }, 174 }, 175 { 176 testName: "service definition incorrect port", 177 serviceName: "foo", 178 servicePorts: []corev1.ServicePort{ 179 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 180 }, 181 serviceType: corev1.ServiceTypeClusterIP, 182 service: &corev1.Service{ 183 ObjectMeta: om("foo"), 184 Spec: corev1.ServiceSpec{ 185 Ports: []corev1.ServicePort{ 186 {Name: "bar", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt32(1000)}, 187 }, 188 Selector: nil, 189 ClusterIP: "1.2.3.4", 190 SessionAffinity: corev1.ServiceAffinityNone, 191 Type: corev1.ServiceTypeClusterIP, 192 }, 193 }, 194 expectUpdate: &corev1.Service{ 195 ObjectMeta: om("foo"), 196 Spec: corev1.ServiceSpec{ 197 Ports: []corev1.ServicePort{ 198 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 199 }, 200 Selector: nil, 201 ClusterIP: "1.2.3.4", 202 SessionAffinity: corev1.ServiceAffinityNone, 203 Type: corev1.ServiceTypeClusterIP, 204 }, 205 }, 206 }, 207 { 208 testName: "service definition incorrect port name", 209 serviceName: "foo", 210 servicePorts: []corev1.ServicePort{ 211 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 212 }, 213 serviceType: corev1.ServiceTypeClusterIP, 214 service: &corev1.Service{ 215 ObjectMeta: om("foo"), 216 Spec: corev1.ServiceSpec{ 217 Ports: []corev1.ServicePort{ 218 {Name: "foo", Port: 1000, Protocol: "UDP", TargetPort: intstr.FromInt32(1000)}, 219 }, 220 Selector: nil, 221 ClusterIP: "1.2.3.4", 222 SessionAffinity: corev1.ServiceAffinityNone, 223 Type: corev1.ServiceTypeClusterIP, 224 }, 225 }, 226 expectUpdate: &corev1.Service{ 227 ObjectMeta: om("foo"), 228 Spec: corev1.ServiceSpec{ 229 Ports: []corev1.ServicePort{ 230 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 231 }, 232 Selector: nil, 233 ClusterIP: "1.2.3.4", 234 SessionAffinity: corev1.ServiceAffinityNone, 235 Type: corev1.ServiceTypeClusterIP, 236 }, 237 }, 238 }, 239 { 240 testName: "service definition incorrect target port", 241 serviceName: "foo", 242 servicePorts: []corev1.ServicePort{ 243 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 244 }, 245 serviceType: corev1.ServiceTypeClusterIP, 246 service: &corev1.Service{ 247 ObjectMeta: om("foo"), 248 Spec: corev1.ServiceSpec{ 249 Ports: []corev1.ServicePort{ 250 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)}, 251 }, 252 Selector: nil, 253 ClusterIP: "1.2.3.4", 254 SessionAffinity: corev1.ServiceAffinityNone, 255 Type: corev1.ServiceTypeClusterIP, 256 }, 257 }, 258 expectUpdate: &corev1.Service{ 259 ObjectMeta: om("foo"), 260 Spec: corev1.ServiceSpec{ 261 Ports: []corev1.ServicePort{ 262 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 263 }, 264 Selector: nil, 265 ClusterIP: "1.2.3.4", 266 SessionAffinity: corev1.ServiceAffinityNone, 267 Type: corev1.ServiceTypeClusterIP, 268 }, 269 }, 270 }, 271 { 272 testName: "service definition incorrect protocol", 273 serviceName: "foo", 274 servicePorts: []corev1.ServicePort{ 275 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 276 }, 277 serviceType: corev1.ServiceTypeClusterIP, 278 service: &corev1.Service{ 279 ObjectMeta: om("foo"), 280 Spec: corev1.ServiceSpec{ 281 Ports: []corev1.ServicePort{ 282 {Name: "foo", Port: 8080, Protocol: "UDP", TargetPort: intstr.FromInt32(8080)}, 283 }, 284 Selector: nil, 285 ClusterIP: "1.2.3.4", 286 SessionAffinity: corev1.ServiceAffinityNone, 287 Type: corev1.ServiceTypeClusterIP, 288 }, 289 }, 290 expectUpdate: &corev1.Service{ 291 ObjectMeta: om("foo"), 292 Spec: corev1.ServiceSpec{ 293 Ports: []corev1.ServicePort{ 294 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 295 }, 296 Selector: nil, 297 ClusterIP: "1.2.3.4", 298 SessionAffinity: corev1.ServiceAffinityNone, 299 Type: corev1.ServiceTypeClusterIP, 300 }, 301 }, 302 }, 303 { 304 testName: "service definition has incorrect type", 305 serviceName: "foo", 306 servicePorts: []corev1.ServicePort{ 307 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 308 }, 309 serviceType: corev1.ServiceTypeClusterIP, 310 service: &corev1.Service{ 311 ObjectMeta: om("foo"), 312 Spec: corev1.ServiceSpec{ 313 Ports: []corev1.ServicePort{ 314 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 315 }, 316 Selector: nil, 317 ClusterIP: "1.2.3.4", 318 SessionAffinity: corev1.ServiceAffinityNone, 319 Type: corev1.ServiceTypeNodePort, 320 }, 321 }, 322 expectUpdate: &corev1.Service{ 323 ObjectMeta: om("foo"), 324 Spec: corev1.ServiceSpec{ 325 Ports: []corev1.ServicePort{ 326 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 327 }, 328 Selector: nil, 329 ClusterIP: "1.2.3.4", 330 SessionAffinity: corev1.ServiceAffinityNone, 331 Type: corev1.ServiceTypeClusterIP, 332 }, 333 }, 334 }, 335 { 336 testName: "service definition satisfies", 337 serviceName: "foo", 338 servicePorts: []corev1.ServicePort{ 339 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 340 }, 341 serviceType: corev1.ServiceTypeClusterIP, 342 service: &corev1.Service{ 343 ObjectMeta: om("foo"), 344 Spec: corev1.ServiceSpec{ 345 Ports: []corev1.ServicePort{ 346 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 347 }, 348 Selector: nil, 349 ClusterIP: "1.2.3.4", 350 SessionAffinity: corev1.ServiceAffinityNone, 351 Type: corev1.ServiceTypeClusterIP, 352 }, 353 }, 354 expectUpdate: nil, 355 }, 356 } 357 for _, test := range reconcileTests { 358 t.Run(test.testName, func(t *testing.T) { 359 master := Controller{} 360 fakeClient := fake.NewSimpleClientset(test.service) 361 serviceInformer := v1informers.NewServiceInformer(fakeClient, metav1.NamespaceDefault, 12*time.Hour, cache.Indexers{}) 362 serviceStore := serviceInformer.GetIndexer() 363 err := serviceStore.Add(test.service) 364 if err != nil { 365 t.Fatalf("unexpected error adding service %v to the store: %v", test.service, err) 366 } 367 master.serviceLister = v1listers.NewServiceLister(serviceStore) 368 master.client = fakeClient 369 err = master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, true) 370 if err != nil { 371 t.Errorf("case %q: unexpected error: %v", test.testName, err) 372 } 373 updates := []core.UpdateAction{} 374 for _, action := range fakeClient.Actions() { 375 if action.GetVerb() == "update" { 376 updates = append(updates, action.(core.UpdateAction)) 377 } 378 } 379 if test.expectUpdate != nil { 380 if len(updates) != 1 { 381 t.Errorf("case %q: unexpected updates: %v", test.testName, updates) 382 } else { 383 obj := updates[0].GetObject() 384 if e, a := test.expectUpdate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) { 385 t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a) 386 } 387 } 388 } 389 if test.expectUpdate == nil && len(updates) > 0 { 390 t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates) 391 } 392 }) 393 } 394 395 nonReconcileTests := []struct { 396 testName string 397 serviceName string 398 servicePorts []corev1.ServicePort 399 serviceType corev1.ServiceType 400 service *corev1.Service 401 expectUpdate *corev1.Service // nil means none expected 402 }{ 403 { 404 testName: "service definition wrong port, no expected update", 405 serviceName: "foo", 406 servicePorts: []corev1.ServicePort{ 407 {Name: "foo", Port: 8080, Protocol: "TCP", TargetPort: intstr.FromInt32(8080)}, 408 }, 409 serviceType: corev1.ServiceTypeClusterIP, 410 service: &corev1.Service{ 411 ObjectMeta: om("foo"), 412 Spec: corev1.ServiceSpec{ 413 Ports: []corev1.ServicePort{ 414 {Name: "foo", Port: 1000, Protocol: "TCP", TargetPort: intstr.FromInt32(1000)}, 415 }, 416 Selector: nil, 417 ClusterIP: "1.2.3.4", 418 SessionAffinity: corev1.ServiceAffinityNone, 419 Type: corev1.ServiceTypeClusterIP, 420 }, 421 }, 422 expectUpdate: nil, 423 }, 424 } 425 for _, test := range nonReconcileTests { 426 t.Run(test.testName, func(t *testing.T) { 427 master := Controller{} 428 fakeClient := fake.NewSimpleClientset(test.service) 429 master.client = fakeClient 430 serviceInformer := v1informers.NewServiceInformer(fakeClient, metav1.NamespaceDefault, 12*time.Hour, cache.Indexers{}) 431 serviceStore := serviceInformer.GetIndexer() 432 err := serviceStore.Add(test.service) 433 if err != nil { 434 t.Fatalf("unexpected error adding service %v to the store: %v", test.service, err) 435 } 436 master.serviceLister = v1listers.NewServiceLister(serviceStore) 437 438 err = master.CreateOrUpdateMasterServiceIfNeeded(test.serviceName, netutils.ParseIPSloppy("1.2.3.4"), test.servicePorts, test.serviceType, false) 439 if err != nil { 440 t.Errorf("case %q: unexpected error: %v", test.testName, err) 441 } 442 updates := []core.UpdateAction{} 443 for _, action := range fakeClient.Actions() { 444 if action.GetVerb() == "update" { 445 updates = append(updates, action.(core.UpdateAction)) 446 } 447 } 448 if test.expectUpdate != nil { 449 if len(updates) != 1 { 450 t.Errorf("case %q: unexpected updates: %v", test.testName, updates) 451 } else { 452 obj := updates[0].GetObject() 453 if e, a := test.expectUpdate.Spec, obj.(*corev1.Service).Spec; !reflect.DeepEqual(e, a) { 454 t.Errorf("case %q: expected update:\n%#v\ngot:\n%#v\n", test.testName, e, a) 455 } 456 } 457 } 458 if test.expectUpdate == nil && len(updates) > 0 { 459 t.Errorf("case %q: no update expected, yet saw: %v", test.testName, updates) 460 } 461 }) 462 } 463 }