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  }