k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/proxy/config/api_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 config 18 19 import ( 20 "reflect" 21 "testing" 22 "time" 23 24 v1 "k8s.io/api/core/v1" 25 discoveryv1 "k8s.io/api/discovery/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/types" 28 "k8s.io/apimachinery/pkg/util/wait" 29 "k8s.io/apimachinery/pkg/watch" 30 "k8s.io/client-go/informers" 31 "k8s.io/client-go/kubernetes/fake" 32 ktesting "k8s.io/client-go/testing" 33 klogtesting "k8s.io/klog/v2/ktesting" 34 "k8s.io/utils/ptr" 35 ) 36 37 func TestNewServicesSourceApi_UpdatesAndMultipleServices(t *testing.T) { 38 _, ctx := klogtesting.NewTestContext(t) 39 service1v1 := &v1.Service{ 40 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "s1"}, 41 Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Protocol: "TCP", Port: 10}}}} 42 service1v2 := &v1.Service{ 43 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "s1"}, 44 Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Protocol: "TCP", Port: 20}}}} 45 service2 := &v1.Service{ 46 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "s2"}, 47 Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Protocol: "TCP", Port: 30}}}} 48 49 // Setup fake api client. 50 client := fake.NewSimpleClientset() 51 fakeWatch := watch.NewFake() 52 client.PrependWatchReactor("services", ktesting.DefaultWatchReactor(fakeWatch, nil)) 53 54 stopCh := make(chan struct{}) 55 defer close(stopCh) 56 57 handler := NewServiceHandlerMock() 58 59 sharedInformers := informers.NewSharedInformerFactory(client, time.Minute) 60 61 serviceConfig := NewServiceConfig(ctx, sharedInformers.Core().V1().Services(), time.Minute) 62 serviceConfig.RegisterEventHandler(handler) 63 go sharedInformers.Start(stopCh) 64 go serviceConfig.Run(stopCh) 65 66 // Add the first service 67 fakeWatch.Add(service1v1) 68 handler.ValidateServices(t, []*v1.Service{service1v1}) 69 70 // Add another service 71 fakeWatch.Add(service2) 72 handler.ValidateServices(t, []*v1.Service{service1v1, service2}) 73 74 // Modify service1 75 fakeWatch.Modify(service1v2) 76 handler.ValidateServices(t, []*v1.Service{service1v2, service2}) 77 78 // Delete service1 79 fakeWatch.Delete(service1v2) 80 handler.ValidateServices(t, []*v1.Service{service2}) 81 82 // Delete service2 83 fakeWatch.Delete(service2) 84 handler.ValidateServices(t, []*v1.Service{}) 85 } 86 87 func TestNewEndpointsSourceApi_UpdatesAndMultipleEndpoints(t *testing.T) { 88 _, ctx := klogtesting.NewTestContext(t) 89 endpoints1v1 := &discoveryv1.EndpointSlice{ 90 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "e1"}, 91 AddressType: discoveryv1.AddressTypeIPv4, 92 Endpoints: []discoveryv1.Endpoint{{ 93 Addresses: []string{ 94 "1.2.3.4", 95 }, 96 }}, 97 Ports: []discoveryv1.EndpointPort{{ 98 Port: ptr.To[int32](8080), 99 Protocol: ptr.To(v1.ProtocolTCP), 100 }}, 101 } 102 endpoints1v2 := &discoveryv1.EndpointSlice{ 103 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "e1"}, 104 AddressType: discoveryv1.AddressTypeIPv4, 105 Endpoints: []discoveryv1.Endpoint{{ 106 Addresses: []string{ 107 "1.2.3.4", 108 "4.3.2.1", 109 }, 110 }}, 111 Ports: []discoveryv1.EndpointPort{{ 112 Port: ptr.To[int32](8080), 113 Protocol: ptr.To(v1.ProtocolTCP), 114 }}, 115 } 116 endpoints2 := &discoveryv1.EndpointSlice{ 117 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "e2"}, 118 AddressType: discoveryv1.AddressTypeIPv4, 119 Endpoints: []discoveryv1.Endpoint{{ 120 Addresses: []string{ 121 "5.6.7.8", 122 }, 123 }}, 124 Ports: []discoveryv1.EndpointPort{{ 125 Port: ptr.To[int32](8080), 126 Protocol: ptr.To(v1.ProtocolTCP), 127 }}, 128 } 129 130 // Setup fake api client. 131 client := fake.NewSimpleClientset() 132 fakeWatch := watch.NewFake() 133 client.PrependWatchReactor("endpointslices", ktesting.DefaultWatchReactor(fakeWatch, nil)) 134 135 stopCh := make(chan struct{}) 136 defer close(stopCh) 137 138 handler := NewEndpointSliceHandlerMock() 139 140 sharedInformers := informers.NewSharedInformerFactory(client, time.Minute) 141 142 endpointsliceConfig := NewEndpointSliceConfig(ctx, sharedInformers.Discovery().V1().EndpointSlices(), time.Minute) 143 endpointsliceConfig.RegisterEventHandler(handler) 144 go sharedInformers.Start(stopCh) 145 go endpointsliceConfig.Run(stopCh) 146 147 // Add the first endpoints 148 fakeWatch.Add(endpoints1v1) 149 handler.ValidateEndpointSlices(t, []*discoveryv1.EndpointSlice{endpoints1v1}) 150 151 // Add another endpoints 152 fakeWatch.Add(endpoints2) 153 handler.ValidateEndpointSlices(t, []*discoveryv1.EndpointSlice{endpoints1v1, endpoints2}) 154 155 // Modify endpoints1 156 fakeWatch.Modify(endpoints1v2) 157 handler.ValidateEndpointSlices(t, []*discoveryv1.EndpointSlice{endpoints1v2, endpoints2}) 158 159 // Delete endpoints1 160 fakeWatch.Delete(endpoints1v2) 161 handler.ValidateEndpointSlices(t, []*discoveryv1.EndpointSlice{endpoints2}) 162 163 // Delete endpoints2 164 fakeWatch.Delete(endpoints2) 165 handler.ValidateEndpointSlices(t, []*discoveryv1.EndpointSlice{}) 166 } 167 168 func TestInitialSync(t *testing.T) { 169 _, ctx := klogtesting.NewTestContext(t) 170 svc1 := &v1.Service{ 171 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"}, 172 Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Protocol: "TCP", Port: 10}}}, 173 } 174 svc2 := &v1.Service{ 175 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"}, 176 Spec: v1.ServiceSpec{Ports: []v1.ServicePort{{Protocol: "TCP", Port: 10}}}, 177 } 178 eps1 := &discoveryv1.EndpointSlice{ 179 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "foo"}, 180 } 181 eps2 := &discoveryv1.EndpointSlice{ 182 ObjectMeta: metav1.ObjectMeta{Namespace: "testnamespace", Name: "bar"}, 183 } 184 185 expectedSvcState := map[types.NamespacedName]*v1.Service{ 186 {Name: svc1.Name, Namespace: svc1.Namespace}: svc1, 187 {Name: svc2.Name, Namespace: svc2.Namespace}: svc2, 188 } 189 expectedEpsState := map[types.NamespacedName]*discoveryv1.EndpointSlice{ 190 {Name: eps1.Name, Namespace: eps1.Namespace}: eps1, 191 {Name: eps2.Name, Namespace: eps2.Namespace}: eps2, 192 } 193 194 // Setup fake api client. 195 client := fake.NewSimpleClientset(svc1, svc2, eps2, eps1) 196 sharedInformers := informers.NewSharedInformerFactory(client, 0) 197 198 svcConfig := NewServiceConfig(ctx, sharedInformers.Core().V1().Services(), 0) 199 svcHandler := NewServiceHandlerMock() 200 svcConfig.RegisterEventHandler(svcHandler) 201 202 epsConfig := NewEndpointSliceConfig(ctx, sharedInformers.Discovery().V1().EndpointSlices(), 0) 203 epsHandler := NewEndpointSliceHandlerMock() 204 epsConfig.RegisterEventHandler(epsHandler) 205 206 stopCh := make(chan struct{}) 207 defer close(stopCh) 208 sharedInformers.Start(stopCh) 209 210 err := wait.PollImmediate(time.Millisecond*10, wait.ForeverTestTimeout, func() (bool, error) { 211 svcHandler.lock.Lock() 212 defer svcHandler.lock.Unlock() 213 if reflect.DeepEqual(svcHandler.state, expectedSvcState) { 214 return true, nil 215 } 216 return false, nil 217 }) 218 if err != nil { 219 t.Fatal("Timed out waiting for the completion of handler `OnServiceAdd`") 220 } 221 222 err = wait.PollImmediate(time.Millisecond*10, wait.ForeverTestTimeout, func() (bool, error) { 223 epsHandler.lock.Lock() 224 defer epsHandler.lock.Unlock() 225 if reflect.DeepEqual(epsHandler.state, expectedEpsState) { 226 return true, nil 227 } 228 return false, nil 229 }) 230 if err != nil { 231 t.Fatal("Timed out waiting for the completion of handler `OnEndpointsAdd`") 232 } 233 234 svcConfig.Run(stopCh) 235 epsConfig.Run(stopCh) 236 237 gotSvc := <-svcHandler.updated 238 gotSvcState := make(map[types.NamespacedName]*v1.Service, len(gotSvc)) 239 for _, svc := range gotSvc { 240 gotSvcState[types.NamespacedName{Namespace: svc.Namespace, Name: svc.Name}] = svc 241 } 242 if !reflect.DeepEqual(gotSvcState, expectedSvcState) { 243 t.Fatalf("Expected service state: %v\nGot: %v\n", expectedSvcState, gotSvcState) 244 } 245 246 gotEps := <-epsHandler.updated 247 gotEpsState := make(map[types.NamespacedName]*discoveryv1.EndpointSlice, len(gotEps)) 248 for _, eps := range gotEps { 249 gotEpsState[types.NamespacedName{Namespace: eps.Namespace, Name: eps.Name}] = eps 250 } 251 if !reflect.DeepEqual(gotEpsState, expectedEpsState) { 252 t.Fatalf("Expected endpoints state: %v\nGot: %v\n", expectedEpsState, gotEpsState) 253 } 254 }