...

Source file src/k8s.io/kubernetes/pkg/registry/discovery/endpointslice/strategy_test.go

Documentation: k8s.io/kubernetes/pkg/registry/discovery/endpointslice

     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 endpointslice
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	corev1 "k8s.io/api/core/v1"
    24  	apiequality "k8s.io/apimachinery/pkg/api/equality"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/util/sets"
    27  	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
    28  	utilfeature "k8s.io/apiserver/pkg/util/feature"
    29  	featuregatetesting "k8s.io/component-base/featuregate/testing"
    30  	"k8s.io/kubernetes/pkg/apis/discovery"
    31  	"k8s.io/kubernetes/pkg/features"
    32  	utilpointer "k8s.io/utils/pointer"
    33  )
    34  
    35  func Test_dropDisabledFieldsOnCreate(t *testing.T) {
    36  	testcases := []struct {
    37  		name             string
    38  		hintsGateEnabled bool
    39  		eps              *discovery.EndpointSlice
    40  		expectedEPS      *discovery.EndpointSlice
    41  	}{
    42  		{
    43  			name: "node name gate enabled, field should be allowed",
    44  			eps: &discovery.EndpointSlice{
    45  				Endpoints: []discovery.Endpoint{
    46  					{
    47  						NodeName: utilpointer.String("node-1"),
    48  					},
    49  					{
    50  						NodeName: utilpointer.String("node-2"),
    51  					},
    52  				},
    53  			},
    54  			expectedEPS: &discovery.EndpointSlice{
    55  				Endpoints: []discovery.Endpoint{
    56  					{
    57  						NodeName: utilpointer.String("node-1"),
    58  					},
    59  					{
    60  						NodeName: utilpointer.String("node-2"),
    61  					},
    62  				},
    63  			},
    64  		},
    65  	}
    66  
    67  	for _, testcase := range testcases {
    68  		t.Run(testcase.name, func(t *testing.T) {
    69  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
    70  
    71  			dropDisabledFieldsOnCreate(testcase.eps)
    72  			if !apiequality.Semantic.DeepEqual(testcase.eps, testcase.expectedEPS) {
    73  				t.Logf("actual endpointslice: %v", testcase.eps)
    74  				t.Logf("expected endpointslice: %v", testcase.expectedEPS)
    75  				t.Errorf("unexpected EndpointSlice on create API strategy")
    76  			}
    77  		})
    78  	}
    79  }
    80  
    81  func Test_dropDisabledFieldsOnUpdate(t *testing.T) {
    82  	testcases := []struct {
    83  		name             string
    84  		hintsGateEnabled bool
    85  		oldEPS           *discovery.EndpointSlice
    86  		newEPS           *discovery.EndpointSlice
    87  		expectedEPS      *discovery.EndpointSlice
    88  	}{
    89  		{
    90  			name: "node name gate enabled, set on new EPS",
    91  			oldEPS: &discovery.EndpointSlice{
    92  				Endpoints: []discovery.Endpoint{
    93  					{
    94  						NodeName: nil,
    95  					},
    96  					{
    97  						NodeName: nil,
    98  					},
    99  				},
   100  			},
   101  			newEPS: &discovery.EndpointSlice{
   102  				Endpoints: []discovery.Endpoint{
   103  					{
   104  						NodeName: utilpointer.String("node-1"),
   105  					},
   106  					{
   107  						NodeName: utilpointer.String("node-2"),
   108  					},
   109  				},
   110  			},
   111  			expectedEPS: &discovery.EndpointSlice{
   112  				Endpoints: []discovery.Endpoint{
   113  					{
   114  						NodeName: utilpointer.String("node-1"),
   115  					},
   116  					{
   117  						NodeName: utilpointer.String("node-2"),
   118  					},
   119  				},
   120  			},
   121  		},
   122  		{
   123  			name: "node name gate disabled, set on old and updated EPS",
   124  			oldEPS: &discovery.EndpointSlice{
   125  				Endpoints: []discovery.Endpoint{
   126  					{
   127  						NodeName: utilpointer.String("node-1-old"),
   128  					},
   129  					{
   130  						NodeName: utilpointer.String("node-2-old"),
   131  					},
   132  				},
   133  			},
   134  			newEPS: &discovery.EndpointSlice{
   135  				Endpoints: []discovery.Endpoint{
   136  					{
   137  						NodeName: utilpointer.String("node-1"),
   138  					},
   139  					{
   140  						NodeName: utilpointer.String("node-2"),
   141  					},
   142  				},
   143  			},
   144  			expectedEPS: &discovery.EndpointSlice{
   145  				Endpoints: []discovery.Endpoint{
   146  					{
   147  						NodeName: utilpointer.String("node-1"),
   148  					},
   149  					{
   150  						NodeName: utilpointer.String("node-2"),
   151  					},
   152  				},
   153  			},
   154  		},
   155  		{
   156  			name:             "hints gate enabled, set on new EPS",
   157  			hintsGateEnabled: true,
   158  			oldEPS: &discovery.EndpointSlice{
   159  				Endpoints: []discovery.Endpoint{
   160  					{
   161  						Hints: nil,
   162  					},
   163  					{
   164  						Hints: nil,
   165  					},
   166  				},
   167  			},
   168  			newEPS: &discovery.EndpointSlice{
   169  				Endpoints: []discovery.Endpoint{
   170  					{
   171  						Hints: &discovery.EndpointHints{
   172  							ForZones: []discovery.ForZone{{Name: "zone-a"}},
   173  						},
   174  					},
   175  					{
   176  						Hints: &discovery.EndpointHints{
   177  							ForZones: []discovery.ForZone{{Name: "zone-b"}},
   178  						},
   179  					},
   180  				},
   181  			},
   182  			expectedEPS: &discovery.EndpointSlice{
   183  				Endpoints: []discovery.Endpoint{
   184  					{
   185  						Hints: &discovery.EndpointHints{
   186  							ForZones: []discovery.ForZone{{Name: "zone-a"}},
   187  						},
   188  					},
   189  					{
   190  						Hints: &discovery.EndpointHints{
   191  							ForZones: []discovery.ForZone{{Name: "zone-b"}},
   192  						},
   193  					},
   194  				},
   195  			},
   196  		},
   197  		{
   198  			name:             "hints gate disabled, set on new EPS",
   199  			hintsGateEnabled: false,
   200  			oldEPS: &discovery.EndpointSlice{
   201  				Endpoints: []discovery.Endpoint{
   202  					{
   203  						Hints: nil,
   204  					},
   205  					{
   206  						Hints: nil,
   207  					},
   208  				},
   209  			},
   210  			newEPS: &discovery.EndpointSlice{
   211  				Endpoints: []discovery.Endpoint{
   212  					{
   213  						Hints: &discovery.EndpointHints{
   214  							ForZones: []discovery.ForZone{{Name: "zone-a"}},
   215  						},
   216  					},
   217  					{
   218  						Hints: &discovery.EndpointHints{
   219  							ForZones: []discovery.ForZone{{Name: "zone-b"}},
   220  						},
   221  					},
   222  				},
   223  			},
   224  			expectedEPS: &discovery.EndpointSlice{
   225  				Endpoints: []discovery.Endpoint{
   226  					{
   227  						Hints: nil,
   228  					},
   229  					{
   230  						Hints: nil,
   231  					},
   232  				},
   233  			},
   234  		},
   235  		{
   236  			name:             "hints gate disabled, set on new and old EPS",
   237  			hintsGateEnabled: false,
   238  			oldEPS: &discovery.EndpointSlice{
   239  				Endpoints: []discovery.Endpoint{
   240  					{
   241  						Hints: &discovery.EndpointHints{
   242  							ForZones: []discovery.ForZone{{Name: "zone-a-old"}},
   243  						},
   244  					},
   245  					{
   246  						Hints: &discovery.EndpointHints{
   247  							ForZones: []discovery.ForZone{{Name: "zone-b-old"}},
   248  						},
   249  					},
   250  				},
   251  			},
   252  			newEPS: &discovery.EndpointSlice{
   253  				Endpoints: []discovery.Endpoint{
   254  					{
   255  						Hints: &discovery.EndpointHints{
   256  							ForZones: []discovery.ForZone{{Name: "zone-a"}},
   257  						},
   258  					},
   259  					{
   260  						Hints: &discovery.EndpointHints{
   261  							ForZones: []discovery.ForZone{{Name: "zone-b"}},
   262  						},
   263  					},
   264  				},
   265  			},
   266  			expectedEPS: &discovery.EndpointSlice{
   267  				Endpoints: []discovery.Endpoint{
   268  					{
   269  						Hints: &discovery.EndpointHints{
   270  							ForZones: []discovery.ForZone{{Name: "zone-a"}},
   271  						},
   272  					},
   273  					{
   274  						Hints: &discovery.EndpointHints{
   275  							ForZones: []discovery.ForZone{{Name: "zone-b"}},
   276  						},
   277  					},
   278  				},
   279  			},
   280  		},
   281  	}
   282  
   283  	for _, testcase := range testcases {
   284  		t.Run(testcase.name, func(t *testing.T) {
   285  			defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.TopologyAwareHints, testcase.hintsGateEnabled)()
   286  
   287  			dropDisabledFieldsOnUpdate(testcase.oldEPS, testcase.newEPS)
   288  			if !apiequality.Semantic.DeepEqual(testcase.newEPS, testcase.expectedEPS) {
   289  				t.Logf("actual endpointslice: %v", testcase.newEPS)
   290  				t.Logf("expected endpointslice: %v", testcase.expectedEPS)
   291  				t.Errorf("unexpected EndpointSlice from update API strategy")
   292  			}
   293  		})
   294  	}
   295  }
   296  
   297  func TestPrepareForUpdate(t *testing.T) {
   298  	testCases := []struct {
   299  		name        string
   300  		oldEPS      *discovery.EndpointSlice
   301  		newEPS      *discovery.EndpointSlice
   302  		expectedEPS *discovery.EndpointSlice
   303  	}{
   304  		{
   305  			name: "unchanged EPS should not increment generation",
   306  			oldEPS: &discovery.EndpointSlice{
   307  				ObjectMeta: metav1.ObjectMeta{Generation: 1},
   308  				Endpoints: []discovery.Endpoint{{
   309  					Addresses: []string{"1.2.3.4"},
   310  				}},
   311  			},
   312  			newEPS: &discovery.EndpointSlice{
   313  				ObjectMeta: metav1.ObjectMeta{Generation: 1},
   314  				Endpoints: []discovery.Endpoint{{
   315  					Addresses: []string{"1.2.3.4"},
   316  				}},
   317  			},
   318  			expectedEPS: &discovery.EndpointSlice{
   319  				ObjectMeta: metav1.ObjectMeta{Generation: 1},
   320  				Endpoints: []discovery.Endpoint{{
   321  					Addresses: []string{"1.2.3.4"},
   322  				}},
   323  			},
   324  		},
   325  		{
   326  			name: "changed endpoints should increment generation",
   327  			oldEPS: &discovery.EndpointSlice{
   328  				ObjectMeta: metav1.ObjectMeta{Generation: 1},
   329  				Endpoints: []discovery.Endpoint{{
   330  					Addresses: []string{"1.2.3.4"},
   331  				}},
   332  			},
   333  			newEPS: &discovery.EndpointSlice{
   334  				ObjectMeta: metav1.ObjectMeta{Generation: 1},
   335  				Endpoints: []discovery.Endpoint{{
   336  					Addresses: []string{"1.2.3.5"},
   337  				}},
   338  			},
   339  			expectedEPS: &discovery.EndpointSlice{
   340  				ObjectMeta: metav1.ObjectMeta{Generation: 2},
   341  				Endpoints: []discovery.Endpoint{{
   342  					Addresses: []string{"1.2.3.5"},
   343  				}},
   344  			},
   345  		},
   346  		{
   347  			name: "changed labels should increment generation",
   348  			oldEPS: &discovery.EndpointSlice{
   349  				ObjectMeta: metav1.ObjectMeta{
   350  					Generation: 1,
   351  					Labels:     map[string]string{"example": "one"},
   352  				},
   353  				Endpoints: []discovery.Endpoint{{
   354  					Addresses: []string{"1.2.3.4"},
   355  				}},
   356  			},
   357  			newEPS: &discovery.EndpointSlice{
   358  				ObjectMeta: metav1.ObjectMeta{
   359  					Generation: 1,
   360  					Labels:     map[string]string{"example": "two"},
   361  				},
   362  				Endpoints: []discovery.Endpoint{{
   363  					Addresses: []string{"1.2.3.4"},
   364  				}},
   365  			},
   366  			expectedEPS: &discovery.EndpointSlice{
   367  				ObjectMeta: metav1.ObjectMeta{
   368  					Generation: 2,
   369  					Labels:     map[string]string{"example": "two"},
   370  				},
   371  				Endpoints: []discovery.Endpoint{{
   372  					Addresses: []string{"1.2.3.4"},
   373  				}},
   374  			},
   375  		},
   376  	}
   377  
   378  	for _, tc := range testCases {
   379  		t.Run(tc.name, func(t *testing.T) {
   380  			Strategy.PrepareForUpdate(context.TODO(), tc.newEPS, tc.oldEPS)
   381  			if !apiequality.Semantic.DeepEqual(tc.newEPS, tc.expectedEPS) {
   382  				t.Errorf("Expected %+v\nGot: %+v", tc.expectedEPS, tc.newEPS)
   383  			}
   384  		})
   385  	}
   386  }
   387  
   388  func Test_dropTopologyOnV1(t *testing.T) {
   389  	testcases := []struct {
   390  		name        string
   391  		v1Request   bool
   392  		newEPS      *discovery.EndpointSlice
   393  		originalEPS *discovery.EndpointSlice
   394  		expectedEPS *discovery.EndpointSlice
   395  	}{
   396  		{
   397  			name:      "v1 request, without deprecated topology",
   398  			v1Request: true,
   399  			newEPS: &discovery.EndpointSlice{
   400  				Endpoints: []discovery.Endpoint{
   401  					{Hostname: utilpointer.String("hostname-1")},
   402  					{Hostname: utilpointer.String("hostname-1")},
   403  				},
   404  			},
   405  			expectedEPS: &discovery.EndpointSlice{
   406  				Endpoints: []discovery.Endpoint{
   407  					{Hostname: utilpointer.String("hostname-1")},
   408  					{Hostname: utilpointer.String("hostname-1")},
   409  				},
   410  			},
   411  		},
   412  		{
   413  			name: "v1beta1 request, without deprecated topology",
   414  			newEPS: &discovery.EndpointSlice{
   415  				Endpoints: []discovery.Endpoint{
   416  					{Hostname: utilpointer.String("hostname-1")},
   417  					{Hostname: utilpointer.String("hostname-1")},
   418  				},
   419  			},
   420  			expectedEPS: &discovery.EndpointSlice{
   421  				Endpoints: []discovery.Endpoint{
   422  					{Hostname: utilpointer.String("hostname-1")},
   423  					{Hostname: utilpointer.String("hostname-1")},
   424  				},
   425  			},
   426  		},
   427  		{
   428  			name:      "v1 request, with deprecated topology",
   429  			v1Request: true,
   430  			newEPS: &discovery.EndpointSlice{
   431  				Endpoints: []discovery.Endpoint{
   432  					{DeprecatedTopology: map[string]string{"key": "value"}},
   433  					{DeprecatedTopology: map[string]string{"key": "value"}},
   434  				},
   435  			},
   436  			expectedEPS: &discovery.EndpointSlice{
   437  				Endpoints: []discovery.Endpoint{{}, {}},
   438  			},
   439  		},
   440  		{
   441  			name: "v1beta1 request, with deprecated topology",
   442  			newEPS: &discovery.EndpointSlice{
   443  				Endpoints: []discovery.Endpoint{
   444  					{DeprecatedTopology: map[string]string{"key": "value"}},
   445  					{DeprecatedTopology: map[string]string{"key": "value"}},
   446  				},
   447  			},
   448  			expectedEPS: &discovery.EndpointSlice{
   449  				Endpoints: []discovery.Endpoint{
   450  					{DeprecatedTopology: map[string]string{"key": "value"}},
   451  					{DeprecatedTopology: map[string]string{"key": "value"}},
   452  				},
   453  			},
   454  		},
   455  		{
   456  			name:      "v1 request, updated metadata",
   457  			v1Request: true,
   458  			originalEPS: &discovery.EndpointSlice{
   459  				Endpoints: []discovery.Endpoint{
   460  					{
   461  						NodeName:           utilpointer.String("node-1"),
   462  						DeprecatedTopology: map[string]string{"key": "value"},
   463  					},
   464  					{
   465  						NodeName:           utilpointer.String("node-1"),
   466  						DeprecatedTopology: map[string]string{"key": "value"},
   467  					},
   468  				},
   469  			},
   470  			newEPS: &discovery.EndpointSlice{
   471  				ObjectMeta: metav1.ObjectMeta{
   472  					Labels: map[string]string{"example": "one"},
   473  				},
   474  				Endpoints: []discovery.Endpoint{
   475  					{
   476  						NodeName:           utilpointer.String("node-1"),
   477  						DeprecatedTopology: map[string]string{"key": "value"},
   478  					},
   479  					{
   480  						NodeName:           utilpointer.String("node-1"),
   481  						DeprecatedTopology: map[string]string{"key": "value"},
   482  					},
   483  				},
   484  			},
   485  			expectedEPS: &discovery.EndpointSlice{
   486  				ObjectMeta: metav1.ObjectMeta{
   487  					Labels: map[string]string{"example": "one"},
   488  				},
   489  				Endpoints: []discovery.Endpoint{
   490  					{
   491  						NodeName:           utilpointer.String("node-1"),
   492  						DeprecatedTopology: map[string]string{"key": "value"},
   493  					},
   494  					{
   495  						NodeName:           utilpointer.String("node-1"),
   496  						DeprecatedTopology: map[string]string{"key": "value"},
   497  					},
   498  				},
   499  			},
   500  		},
   501  		{
   502  			name: "v1beta1 request, updated metadata",
   503  			originalEPS: &discovery.EndpointSlice{
   504  				Endpoints: []discovery.Endpoint{
   505  					{
   506  						NodeName:           utilpointer.String("node-1"),
   507  						DeprecatedTopology: map[string]string{"key": "value"},
   508  					},
   509  					{
   510  						NodeName:           utilpointer.String("node-1"),
   511  						DeprecatedTopology: map[string]string{"key": "value"},
   512  					},
   513  				},
   514  			},
   515  			newEPS: &discovery.EndpointSlice{
   516  				ObjectMeta: metav1.ObjectMeta{
   517  					Labels: map[string]string{"example": "one"},
   518  				},
   519  				Endpoints: []discovery.Endpoint{
   520  					{
   521  						NodeName:           utilpointer.String("node-1"),
   522  						DeprecatedTopology: map[string]string{"key": "value"},
   523  					},
   524  					{
   525  						NodeName:           utilpointer.String("node-1"),
   526  						DeprecatedTopology: map[string]string{"key": "value"},
   527  					},
   528  				},
   529  			},
   530  			expectedEPS: &discovery.EndpointSlice{
   531  				ObjectMeta: metav1.ObjectMeta{
   532  					Labels: map[string]string{"example": "one"},
   533  				},
   534  				Endpoints: []discovery.Endpoint{
   535  					{
   536  						NodeName:           utilpointer.String("node-1"),
   537  						DeprecatedTopology: map[string]string{"key": "value"},
   538  					},
   539  					{
   540  						NodeName:           utilpointer.String("node-1"),
   541  						DeprecatedTopology: map[string]string{"key": "value"},
   542  					},
   543  				},
   544  			},
   545  		},
   546  		{
   547  			name:      "v1 request, updated endpoints",
   548  			v1Request: true,
   549  			originalEPS: &discovery.EndpointSlice{
   550  				Endpoints: []discovery.Endpoint{
   551  					{DeprecatedTopology: map[string]string{"key": "value"}},
   552  					{DeprecatedTopology: map[string]string{"key": "value"}},
   553  				},
   554  			},
   555  			newEPS: &discovery.EndpointSlice{
   556  				Endpoints: []discovery.Endpoint{
   557  					{
   558  						Hostname:           utilpointer.String("hostname-1"),
   559  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   560  					},
   561  					{
   562  						Hostname:           utilpointer.String("hostname-1"),
   563  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   564  					},
   565  				},
   566  			},
   567  			expectedEPS: &discovery.EndpointSlice{
   568  				Endpoints: []discovery.Endpoint{
   569  					{Hostname: utilpointer.String("hostname-1")},
   570  					{Hostname: utilpointer.String("hostname-1")},
   571  				},
   572  			},
   573  		},
   574  		{
   575  			name: "v1beta1 request, updated endpoints",
   576  			originalEPS: &discovery.EndpointSlice{
   577  				Endpoints: []discovery.Endpoint{
   578  					{DeprecatedTopology: map[string]string{"key": "value"}},
   579  					{DeprecatedTopology: map[string]string{"key": "value"}},
   580  				},
   581  			},
   582  			newEPS: &discovery.EndpointSlice{
   583  				Endpoints: []discovery.Endpoint{
   584  					{
   585  						Hostname:           utilpointer.String("hostname-1"),
   586  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   587  					},
   588  					{
   589  						Hostname:           utilpointer.String("hostname-1"),
   590  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   591  					},
   592  				},
   593  			},
   594  			expectedEPS: &discovery.EndpointSlice{
   595  				Endpoints: []discovery.Endpoint{
   596  					{
   597  						Hostname:           utilpointer.String("hostname-1"),
   598  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   599  					},
   600  					{
   601  						Hostname:           utilpointer.String("hostname-1"),
   602  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   603  					},
   604  				},
   605  			},
   606  		},
   607  		{
   608  			name:      "v1 request, updated endpoints with topology node names + other topology fields",
   609  			v1Request: true,
   610  			originalEPS: &discovery.EndpointSlice{
   611  				Endpoints: []discovery.Endpoint{
   612  					{
   613  						Hostname:           utilpointer.String("hostname-1"),
   614  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1", "other": "value"},
   615  					},
   616  					{
   617  						Hostname:           utilpointer.String("hostname-1"),
   618  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1", "foo": "bar"},
   619  					},
   620  				},
   621  			},
   622  			newEPS: &discovery.EndpointSlice{
   623  				Endpoints: []discovery.Endpoint{
   624  					{
   625  						Hostname:           utilpointer.String("hostname-1a"),
   626  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1", "other": "value"},
   627  					},
   628  					{
   629  						Hostname:           utilpointer.String("hostname-1b"),
   630  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1", "foo": "bar"},
   631  					},
   632  				},
   633  			},
   634  			expectedEPS: &discovery.EndpointSlice{
   635  				Endpoints: []discovery.Endpoint{
   636  					{
   637  						Hostname: utilpointer.String("hostname-1a"),
   638  						NodeName: utilpointer.String("node-1"),
   639  					},
   640  					{
   641  						Hostname: utilpointer.String("hostname-1b"),
   642  						NodeName: utilpointer.String("node-1"),
   643  					},
   644  				},
   645  			},
   646  		},
   647  		{
   648  			name:      "v1 request, updated endpoints with topology node names",
   649  			v1Request: true,
   650  			originalEPS: &discovery.EndpointSlice{
   651  				Endpoints: []discovery.Endpoint{
   652  					{
   653  						Hostname:           utilpointer.String("hostname-1"),
   654  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   655  					},
   656  					{
   657  						Hostname:           utilpointer.String("hostname-1"),
   658  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   659  					},
   660  				},
   661  			},
   662  			newEPS: &discovery.EndpointSlice{
   663  				Endpoints: []discovery.Endpoint{
   664  					{
   665  						Hostname:           utilpointer.String("hostname-1a"),
   666  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   667  					},
   668  					{
   669  						Hostname:           utilpointer.String("hostname-1b"),
   670  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   671  					},
   672  				},
   673  			},
   674  			expectedEPS: &discovery.EndpointSlice{
   675  				Endpoints: []discovery.Endpoint{
   676  					{
   677  						Hostname: utilpointer.String("hostname-1a"),
   678  						NodeName: utilpointer.String("node-1"),
   679  					},
   680  					{
   681  						Hostname: utilpointer.String("hostname-1b"),
   682  						NodeName: utilpointer.String("node-1"),
   683  					},
   684  				},
   685  			},
   686  		},
   687  		{
   688  			name:      "v1 request, updated endpoints with topology node names swapped",
   689  			v1Request: true,
   690  			originalEPS: &discovery.EndpointSlice{
   691  				Endpoints: []discovery.Endpoint{
   692  					{
   693  						Hostname:           utilpointer.String("hostname-1"),
   694  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   695  					},
   696  					{
   697  						Hostname:           utilpointer.String("hostname-1"),
   698  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-2"},
   699  					},
   700  				},
   701  			},
   702  			newEPS: &discovery.EndpointSlice{
   703  				Endpoints: []discovery.Endpoint{
   704  					{
   705  						Hostname:           utilpointer.String("hostname-1a"),
   706  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-2"},
   707  					},
   708  					{
   709  						Hostname:           utilpointer.String("hostname-1b"),
   710  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   711  					},
   712  				},
   713  			},
   714  			expectedEPS: &discovery.EndpointSlice{
   715  				Endpoints: []discovery.Endpoint{
   716  					{
   717  						Hostname: utilpointer.String("hostname-1a"),
   718  						NodeName: utilpointer.String("node-2"),
   719  					},
   720  					{
   721  						Hostname: utilpointer.String("hostname-1b"),
   722  						NodeName: utilpointer.String("node-1"),
   723  					},
   724  				},
   725  			},
   726  		},
   727  		{
   728  			name:      "v1 request, updated endpoints with new topology node name",
   729  			v1Request: true,
   730  			originalEPS: &discovery.EndpointSlice{
   731  				Endpoints: []discovery.Endpoint{
   732  					{
   733  						Hostname:           utilpointer.String("hostname-1"),
   734  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   735  					},
   736  					{
   737  						Hostname:           utilpointer.String("hostname-1"),
   738  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-2"},
   739  					},
   740  				},
   741  			},
   742  			newEPS: &discovery.EndpointSlice{
   743  				Endpoints: []discovery.Endpoint{
   744  					{
   745  						Hostname: utilpointer.String("hostname-1a"),
   746  						// Invalid node name because it did not exist in previous version of EndpointSlice
   747  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-3"},
   748  					},
   749  					{
   750  						Hostname:           utilpointer.String("hostname-1b"),
   751  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   752  					},
   753  				},
   754  			},
   755  			expectedEPS: &discovery.EndpointSlice{
   756  				Endpoints: []discovery.Endpoint{
   757  					{
   758  						Hostname: utilpointer.String("hostname-1a"),
   759  					},
   760  					{
   761  						Hostname: utilpointer.String("hostname-1b"),
   762  						NodeName: utilpointer.String("node-1"),
   763  					},
   764  				},
   765  			},
   766  		},
   767  		{
   768  			name:      "v1 request, updated endpoints with topology node names + 1 new node name",
   769  			v1Request: true,
   770  			originalEPS: &discovery.EndpointSlice{
   771  				Endpoints: []discovery.Endpoint{
   772  					{
   773  						Hostname:           utilpointer.String("hostname-1"),
   774  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   775  					},
   776  					{
   777  						Hostname:           utilpointer.String("hostname-1"),
   778  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   779  					},
   780  				},
   781  			},
   782  			newEPS: &discovery.EndpointSlice{
   783  				Endpoints: []discovery.Endpoint{
   784  					{
   785  						Hostname:           utilpointer.String("hostname-1a"),
   786  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   787  					},
   788  					{
   789  						Hostname:           utilpointer.String("hostname-1b"),
   790  						NodeName:           utilpointer.String("node-2"),
   791  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   792  					},
   793  				},
   794  			},
   795  			expectedEPS: &discovery.EndpointSlice{
   796  				Endpoints: []discovery.Endpoint{
   797  					{
   798  						Hostname: utilpointer.String("hostname-1a"),
   799  						NodeName: utilpointer.String("node-1"),
   800  					},
   801  					{
   802  						Hostname: utilpointer.String("hostname-1b"),
   803  						NodeName: utilpointer.String("node-2"),
   804  					},
   805  				},
   806  			},
   807  		},
   808  		{
   809  			name:      "v1 request, updated endpoints with topology node names + new node names",
   810  			v1Request: true,
   811  			originalEPS: &discovery.EndpointSlice{
   812  				Endpoints: []discovery.Endpoint{
   813  					{
   814  						Hostname:           utilpointer.String("hostname-1"),
   815  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   816  					},
   817  					{
   818  						Hostname:           utilpointer.String("hostname-1"),
   819  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   820  					},
   821  				},
   822  			},
   823  			newEPS: &discovery.EndpointSlice{
   824  				Endpoints: []discovery.Endpoint{
   825  					{
   826  						Hostname:           utilpointer.String("hostname-1a"),
   827  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   828  						NodeName:           utilpointer.String("node-1"),
   829  					},
   830  					{
   831  						Hostname:           utilpointer.String("hostname-1b"),
   832  						NodeName:           utilpointer.String("node-2"),
   833  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
   834  					},
   835  				},
   836  			},
   837  			expectedEPS: &discovery.EndpointSlice{
   838  				Endpoints: []discovery.Endpoint{
   839  					{
   840  						Hostname: utilpointer.String("hostname-1a"),
   841  						NodeName: utilpointer.String("node-1"),
   842  					},
   843  					{
   844  						Hostname: utilpointer.String("hostname-1b"),
   845  						NodeName: utilpointer.String("node-2"),
   846  					},
   847  				},
   848  			},
   849  		},
   850  		{
   851  			name:      "v1 request, invalid node name label",
   852  			v1Request: true,
   853  			originalEPS: &discovery.EndpointSlice{
   854  				Endpoints: []discovery.Endpoint{
   855  					{
   856  						Hostname:           utilpointer.String("hostname-1"),
   857  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "valid-node-1"},
   858  					},
   859  					{
   860  						Hostname:           utilpointer.String("hostname-2"),
   861  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "invalid node-2"},
   862  					},
   863  					{
   864  						Hostname:           utilpointer.String("hostname-3"),
   865  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "valid-node-3"},
   866  					},
   867  					{
   868  						Hostname:           utilpointer.String("hostname-4"),
   869  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "invalid node-4"},
   870  					},
   871  				},
   872  			},
   873  			newEPS: &discovery.EndpointSlice{
   874  				Endpoints: []discovery.Endpoint{
   875  					{
   876  						Hostname:           utilpointer.String("hostname-1"),
   877  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "valid-node-1"},
   878  					},
   879  					{
   880  						Hostname:           utilpointer.String("hostname-2"),
   881  						DeprecatedTopology: map[string]string{corev1.LabelHostname: "invalid node-2"},
   882  					},
   883  					{
   884  						Hostname: utilpointer.String("hostname-3"),
   885  						NodeName: utilpointer.String("node-3"),
   886  					},
   887  					{
   888  						Hostname: utilpointer.String("hostname-4"),
   889  						NodeName: utilpointer.String("node-4"),
   890  					},
   891  				},
   892  			},
   893  			expectedEPS: &discovery.EndpointSlice{
   894  				Endpoints: []discovery.Endpoint{
   895  					{
   896  						Hostname: utilpointer.String("hostname-1"),
   897  						NodeName: utilpointer.String("valid-node-1"),
   898  					},
   899  					{
   900  						Hostname: utilpointer.String("hostname-2"),
   901  					},
   902  					{
   903  						Hostname: utilpointer.String("hostname-3"),
   904  						NodeName: utilpointer.String("node-3"),
   905  					},
   906  					{
   907  						Hostname: utilpointer.String("hostname-4"),
   908  						NodeName: utilpointer.String("node-4"),
   909  					},
   910  				},
   911  			},
   912  		},
   913  	}
   914  
   915  	for _, tc := range testcases {
   916  		t.Run(tc.name, func(t *testing.T) {
   917  			ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{APIGroup: "discovery.k8s.io", APIVersion: "v1beta1", Resource: "endpointslices"})
   918  			if tc.v1Request {
   919  				ctx = genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{APIGroup: "discovery.k8s.io", APIVersion: "v1", Resource: "endpointslices"})
   920  			}
   921  
   922  			dropTopologyOnV1(ctx, tc.originalEPS, tc.newEPS)
   923  			if !apiequality.Semantic.DeepEqual(tc.newEPS, tc.expectedEPS) {
   924  				t.Logf("actual endpointslice: %v", tc.newEPS)
   925  				t.Logf("expected endpointslice: %v", tc.expectedEPS)
   926  				t.Errorf("unexpected EndpointSlice on API topology strategy")
   927  			}
   928  		})
   929  	}
   930  }
   931  
   932  func Test_getDeprecatedTopologyNodeNames(t *testing.T) {
   933  	testcases := []struct {
   934  		name              string
   935  		endpointSlice     *discovery.EndpointSlice
   936  		expectedNodeNames sets.String
   937  	}{
   938  		{
   939  			name: "2 nodes",
   940  			endpointSlice: &discovery.EndpointSlice{
   941  				Endpoints: []discovery.Endpoint{
   942  					{DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"}},
   943  					{DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-2"}},
   944  				},
   945  			},
   946  			expectedNodeNames: sets.NewString("node-1", "node-2"),
   947  		},
   948  		{
   949  			name: "duplicate values",
   950  			endpointSlice: &discovery.EndpointSlice{
   951  				Endpoints: []discovery.Endpoint{
   952  					{DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"}},
   953  					{DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-3"}},
   954  					{DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-3"}},
   955  				},
   956  			},
   957  			expectedNodeNames: sets.NewString("node-1", "node-3"),
   958  		},
   959  		{
   960  			name: "unset",
   961  			endpointSlice: &discovery.EndpointSlice{
   962  				Endpoints: []discovery.Endpoint{
   963  					{DeprecatedTopology: map[string]string{"other": "value"}},
   964  					{DeprecatedTopology: map[string]string{"foo": "bar"}},
   965  					{DeprecatedTopology: nil},
   966  				},
   967  			},
   968  			expectedNodeNames: sets.NewString(),
   969  		},
   970  	}
   971  
   972  	for _, tc := range testcases {
   973  		t.Run(tc.name, func(t *testing.T) {
   974  			actualNames := getDeprecatedTopologyNodeNames(tc.endpointSlice)
   975  			if !tc.expectedNodeNames.Equal(actualNames) {
   976  				t.Errorf("Expected %+v node names, got %+v", tc.expectedNodeNames, actualNames)
   977  			}
   978  		})
   979  	}
   980  }
   981  
   982  func TestWarningsOnEndpointSliceAddressType(t *testing.T) {
   983  	tests := []struct {
   984  		name        string
   985  		addressType discovery.AddressType
   986  		wantWarning bool
   987  	}{
   988  		{
   989  			name:        "AddressType = FQDN",
   990  			addressType: discovery.AddressTypeFQDN,
   991  			wantWarning: true,
   992  		},
   993  		{
   994  			name:        "AddressType = IPV4",
   995  			addressType: discovery.AddressTypeIPv4,
   996  			wantWarning: false,
   997  		},
   998  		{
   999  			name:        "AddressType = IPV6",
  1000  			addressType: discovery.AddressTypeIPv6,
  1001  			wantWarning: false,
  1002  		},
  1003  	}
  1004  	for _, tc := range tests {
  1005  		t.Run(tc.name, func(t *testing.T) {
  1006  			ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{APIGroup: "discovery.k8s.io", APIVersion: "v1", Resource: "endpointslices"})
  1007  			edp := discovery.EndpointSlice{AddressType: tc.addressType}
  1008  			got := Strategy.WarningsOnCreate(ctx, &edp)
  1009  			if tc.wantWarning && len(got) == 0 {
  1010  				t.Fatal("Failed warning was not returned")
  1011  			} else if !tc.wantWarning && len(got) != 0 {
  1012  				t.Fatalf("Failed warning  was returned (%v)", got)
  1013  			}
  1014  		})
  1015  	}
  1016  }
  1017  

View as plain text