k8s.io/kubernetes@v1.29.3/pkg/controller/endpointslicemirroring/reconciler_helpers_test.go (about) 1 /* 2 Copyright 2020 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 endpointslicemirroring 18 19 import ( 20 "sort" 21 "testing" 22 23 discovery "k8s.io/api/discovery/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ) 26 27 func TestRecycleSlices(t *testing.T) { 28 testCases := []struct { 29 testName string 30 startingSlices *slicesByAction 31 expectedSlices *slicesByAction 32 }{{ 33 testName: "Empty slices", 34 startingSlices: &slicesByAction{}, 35 expectedSlices: &slicesByAction{}, 36 }, { 37 testName: "1 to create and 1 to delete", 38 startingSlices: &slicesByAction{ 39 toCreate: []*discovery.EndpointSlice{simpleEndpointSlice("foo", "10.1.2.3", discovery.AddressTypeIPv4)}, 40 toDelete: []*discovery.EndpointSlice{simpleEndpointSlice("bar", "10.2.3.4", discovery.AddressTypeIPv4)}, 41 }, 42 expectedSlices: &slicesByAction{ 43 toUpdate: []*discovery.EndpointSlice{simpleEndpointSlice("bar", "10.1.2.3", discovery.AddressTypeIPv4)}, 44 }, 45 }, { 46 testName: "1 to create, update, and delete", 47 startingSlices: &slicesByAction{ 48 toCreate: []*discovery.EndpointSlice{simpleEndpointSlice("foo", "10.1.2.3", discovery.AddressTypeIPv4)}, 49 toUpdate: []*discovery.EndpointSlice{simpleEndpointSlice("baz", "10.2.3.4", discovery.AddressTypeIPv4)}, 50 toDelete: []*discovery.EndpointSlice{simpleEndpointSlice("bar", "10.3.4.5", discovery.AddressTypeIPv4)}, 51 }, 52 expectedSlices: &slicesByAction{ 53 toUpdate: []*discovery.EndpointSlice{ 54 simpleEndpointSlice("bar", "10.1.2.3", discovery.AddressTypeIPv4), 55 simpleEndpointSlice("baz", "10.2.3.4", discovery.AddressTypeIPv4), 56 }, 57 }, 58 }, { 59 testName: "2 to create and 1 to delete", 60 startingSlices: &slicesByAction{ 61 toCreate: []*discovery.EndpointSlice{ 62 simpleEndpointSlice("foo1", "10.1.2.3", discovery.AddressTypeIPv4), 63 simpleEndpointSlice("foo2", "10.3.4.5", discovery.AddressTypeIPv4), 64 }, 65 toDelete: []*discovery.EndpointSlice{simpleEndpointSlice("bar", "10.2.3.4", discovery.AddressTypeIPv4)}, 66 }, 67 expectedSlices: &slicesByAction{ 68 toCreate: []*discovery.EndpointSlice{simpleEndpointSlice("foo2", "10.3.4.5", discovery.AddressTypeIPv4)}, 69 toUpdate: []*discovery.EndpointSlice{simpleEndpointSlice("bar", "10.1.2.3", discovery.AddressTypeIPv4)}, 70 }, 71 }, { 72 testName: "1 to create and 2 to delete", 73 startingSlices: &slicesByAction{ 74 toCreate: []*discovery.EndpointSlice{ 75 simpleEndpointSlice("foo1", "10.1.2.3", discovery.AddressTypeIPv4), 76 }, 77 toDelete: []*discovery.EndpointSlice{ 78 simpleEndpointSlice("bar1", "10.2.3.4", discovery.AddressTypeIPv4), 79 simpleEndpointSlice("bar2", "10.3.4.5", discovery.AddressTypeIPv4), 80 }, 81 }, 82 expectedSlices: &slicesByAction{ 83 toUpdate: []*discovery.EndpointSlice{simpleEndpointSlice("bar1", "10.1.2.3", discovery.AddressTypeIPv4)}, 84 toDelete: []*discovery.EndpointSlice{simpleEndpointSlice("bar2", "10.3.4.5", discovery.AddressTypeIPv4)}, 85 }, 86 }, { 87 testName: "1 to create and 1 to delete for each IP family", 88 startingSlices: &slicesByAction{ 89 toCreate: []*discovery.EndpointSlice{ 90 simpleEndpointSlice("foo-v4", "10.1.2.3", discovery.AddressTypeIPv4), 91 simpleEndpointSlice("foo-v6", "2001:db8:1111:3333:4444:5555:6666:7777", discovery.AddressTypeIPv6), 92 }, 93 toDelete: []*discovery.EndpointSlice{ 94 simpleEndpointSlice("bar-v4", "10.2.2.3", discovery.AddressTypeIPv4), 95 simpleEndpointSlice("bar-v6", "2001:db8:2222:3333:4444:5555:6666:7777", discovery.AddressTypeIPv6), 96 }, 97 }, 98 expectedSlices: &slicesByAction{ 99 toUpdate: []*discovery.EndpointSlice{ 100 simpleEndpointSlice("bar-v4", "10.1.2.3", discovery.AddressTypeIPv4), 101 simpleEndpointSlice("bar-v6", "2001:db8:1111:3333:4444:5555:6666:7777", discovery.AddressTypeIPv6), 102 }, 103 }, 104 }, { 105 testName: "1 to create and 1 to delete, wrong IP family", 106 startingSlices: &slicesByAction{ 107 toCreate: []*discovery.EndpointSlice{ 108 simpleEndpointSlice("foo-v4", "10.1.2.3", discovery.AddressTypeIPv4), 109 }, 110 toDelete: []*discovery.EndpointSlice{ 111 simpleEndpointSlice("bar-v6", "2001:db8:2222:3333:4444:5555:6666:7777", discovery.AddressTypeIPv6), 112 }, 113 }, 114 expectedSlices: &slicesByAction{ 115 toCreate: []*discovery.EndpointSlice{ 116 simpleEndpointSlice("foo-v4", "10.1.2.3", discovery.AddressTypeIPv4), 117 }, 118 toDelete: []*discovery.EndpointSlice{ 119 simpleEndpointSlice("bar-v6", "2001:db8:2222:3333:4444:5555:6666:7777", discovery.AddressTypeIPv6), 120 }, 121 }, 122 }} 123 124 for _, tc := range testCases { 125 t.Run(tc.testName, func(t *testing.T) { 126 startingSlices := tc.startingSlices 127 recycleSlices(startingSlices) 128 129 unorderedSlices := [][]*discovery.EndpointSlice{startingSlices.toCreate, startingSlices.toUpdate, startingSlices.toDelete} 130 for _, actual := range unorderedSlices { 131 sort.Slice(actual, func(i, j int) bool { 132 return actual[i].Name < actual[j].Name 133 }) 134 } 135 136 expectEqualSlices(t, startingSlices.toCreate, tc.expectedSlices.toCreate) 137 expectEqualSlices(t, startingSlices.toUpdate, tc.expectedSlices.toUpdate) 138 expectEqualSlices(t, startingSlices.toDelete, tc.expectedSlices.toDelete) 139 }) 140 } 141 } 142 143 // Test helpers 144 func expectEqualSlices(t *testing.T, actual, expected []*discovery.EndpointSlice) { 145 t.Helper() 146 if len(actual) != len(expected) { 147 t.Fatalf("Expected %d EndpointSlices, got %d: %v", len(expected), len(actual), actual) 148 } 149 150 for i, expectedSlice := range expected { 151 if expectedSlice.AddressType != actual[i].AddressType { 152 t.Errorf("Expected Slice to have %s address type, got %s", expectedSlice.AddressType, actual[i].AddressType) 153 } 154 155 if expectedSlice.Name != actual[i].Name { 156 t.Errorf("Expected Slice to have %s name, got %s", expectedSlice.Name, actual[i].Name) 157 } 158 159 if len(expectedSlice.Endpoints) != len(actual[i].Endpoints) { 160 t.Fatalf("Expected Slice to have %d endpoints, got %d", len(expectedSlice.Endpoints), len(actual[i].Endpoints)) 161 } 162 163 for j, expectedEndpoint := range expectedSlice.Endpoints { 164 actualEndpoint := actual[i].Endpoints[j] 165 if len(expectedEndpoint.Addresses) != len(actualEndpoint.Addresses) { 166 t.Fatalf("Expected Endpoint to have %d addresses, got %d", len(expectedEndpoint.Addresses), len(actualEndpoint.Addresses)) 167 } 168 169 for k, expectedAddress := range expectedEndpoint.Addresses { 170 actualAddress := actualEndpoint.Addresses[k] 171 if expectedAddress != actualAddress { 172 t.Fatalf("Expected address to be %s, got %s", expectedAddress, actualAddress) 173 } 174 } 175 } 176 } 177 } 178 179 func simpleEndpointSlice(name, ip string, addrType discovery.AddressType) *discovery.EndpointSlice { 180 return &discovery.EndpointSlice{ 181 ObjectMeta: metav1.ObjectMeta{ 182 Name: name, 183 }, 184 AddressType: addrType, 185 Endpoints: []discovery.Endpoint{{ 186 Addresses: []string{ip}, 187 }}, 188 } 189 }