istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/kube/controller/util_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package controller
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	v1 "k8s.io/api/core/v1"
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	"k8s.io/apimachinery/pkg/types"
    24  
    25  	"istio.io/istio/pilot/pkg/model"
    26  	"istio.io/istio/pkg/config/labels"
    27  )
    28  
    29  func TestHasProxyIP(t *testing.T) {
    30  	tests := []struct {
    31  		name      string
    32  		addresses []v1.EndpointAddress
    33  		proxyIP   string
    34  		expected  bool
    35  	}{
    36  		{
    37  			"has proxy ip",
    38  			[]v1.EndpointAddress{{IP: "172.17.0.1"}, {IP: "172.17.0.2"}},
    39  			"172.17.0.1",
    40  			true,
    41  		},
    42  		{
    43  			"has no proxy ip",
    44  			[]v1.EndpointAddress{{IP: "172.17.0.1"}, {IP: "172.17.0.2"}},
    45  			"172.17.0.100",
    46  			false,
    47  		},
    48  	}
    49  
    50  	for _, test := range tests {
    51  		t.Run(test.name, func(t *testing.T) {
    52  			got := hasProxyIP(test.addresses, test.proxyIP)
    53  			if test.expected != got {
    54  				t.Errorf("Expected %v, but got %v", test.expected, got)
    55  			}
    56  		})
    57  	}
    58  }
    59  
    60  func TestGetLabelValue(t *testing.T) {
    61  	tests := []struct {
    62  		name               string
    63  		node               *v1.Node
    64  		expectedLabelValue string
    65  	}{
    66  		{
    67  			"Chooses beta label",
    68  			&v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{NodeRegionLabel: "beta-region", NodeRegionLabelGA: "ga-region"}}},
    69  			"beta-region",
    70  		},
    71  		{
    72  			"Fallback no beta label defined",
    73  			&v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{NodeRegionLabelGA: "ga-region"}}},
    74  			"ga-region",
    75  		},
    76  		{
    77  			"Only beta label specified",
    78  			&v1.Node{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{NodeRegionLabel: "beta-region"}}},
    79  			"beta-region",
    80  		},
    81  		{
    82  			"No label defined at all",
    83  			&v1.Node{},
    84  			"",
    85  		},
    86  	}
    87  
    88  	for _, test := range tests {
    89  		t.Run(test.name, func(t *testing.T) {
    90  			got := getLabelValue(test.node.ObjectMeta, NodeRegionLabel, NodeRegionLabelGA)
    91  			if test.expectedLabelValue != got {
    92  				t.Errorf("Expected %v, but got %v", test.expectedLabelValue, got)
    93  			}
    94  		})
    95  	}
    96  }
    97  
    98  func TestPodKeyByProxy(t *testing.T) {
    99  	testCases := []struct {
   100  		name        string
   101  		proxy       *model.Proxy
   102  		expectedKey types.NamespacedName
   103  	}{
   104  		{
   105  			name: "invalid id: bad format",
   106  			proxy: &model.Proxy{
   107  				ID: "invalid",
   108  				Metadata: &model.NodeMetadata{
   109  					Namespace: "default",
   110  				},
   111  			},
   112  		},
   113  		{
   114  			name: "invalid id: namespace mismatch",
   115  			proxy: &model.Proxy{
   116  				ID: "pod1.ns1",
   117  				Metadata: &model.NodeMetadata{
   118  					Namespace: "default",
   119  				},
   120  			},
   121  		},
   122  		{
   123  			name: "invalid id: namespace mismatch",
   124  			proxy: &model.Proxy{
   125  				ID: "pod1.ns1",
   126  				Metadata: &model.NodeMetadata{
   127  					Namespace: "ns1",
   128  				},
   129  			},
   130  			expectedKey: types.NamespacedName{Namespace: "ns1", Name: "pod1"},
   131  		},
   132  	}
   133  
   134  	for _, tc := range testCases {
   135  		t.Run(tc.name, func(t *testing.T) {
   136  			key := podKeyByProxy(tc.proxy)
   137  			if key != tc.expectedKey {
   138  				t.Errorf("expected key %s != %s", tc.expectedKey, key)
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestGetNodeSelectorsForService(t *testing.T) {
   145  	testCases := []struct {
   146  		name                  string
   147  		svc                   *v1.Service
   148  		expectedLabelSelector labels.Instance
   149  	}{
   150  		{
   151  			name:                  "empty selector",
   152  			svc:                   makeFakeSvc(""),
   153  			expectedLabelSelector: nil,
   154  		},
   155  		{
   156  			name:                  "invalid selector",
   157  			svc:                   makeFakeSvc("invalid value"),
   158  			expectedLabelSelector: nil,
   159  		},
   160  		{
   161  			name:                  "wildcard match",
   162  			svc:                   makeFakeSvc("{}"),
   163  			expectedLabelSelector: labels.Instance{},
   164  		},
   165  		{
   166  			name:                  "specific match",
   167  			svc:                   makeFakeSvc(`{"kubernetes.io/hostname": "node1"}`),
   168  			expectedLabelSelector: labels.Instance{"kubernetes.io/hostname": "node1"},
   169  		},
   170  	}
   171  
   172  	for _, tc := range testCases {
   173  		t.Run(tc.name, func(t *testing.T) {
   174  			selector := getNodeSelectorsForService(tc.svc)
   175  			if !reflect.DeepEqual(selector, tc.expectedLabelSelector) {
   176  				t.Errorf("expected selector %v != %v", tc.expectedLabelSelector, selector)
   177  			}
   178  		})
   179  	}
   180  }
   181  
   182  func makeFakeSvc(nodeSelector string) *v1.Service {
   183  	svc := &v1.Service{
   184  		ObjectMeta: metav1.ObjectMeta{
   185  			Name:      "service",
   186  			Namespace: "ns",
   187  		},
   188  		Spec: v1.ServiceSpec{
   189  			Ports: []v1.ServicePort{{
   190  				Name: "http",
   191  				Port: 80,
   192  			}},
   193  			Selector:  map[string]string{"app": "helloworld"},
   194  			ClusterIP: "9.9.9.9",
   195  		},
   196  	}
   197  
   198  	if nodeSelector != "" {
   199  		svc.Annotations = map[string]string{
   200  			"traffic.istio.io/nodeSelector": nodeSelector,
   201  		}
   202  	}
   203  	return svc
   204  }
   205  
   206  func hasProxyIP(addresses []v1.EndpointAddress, proxyIP string) bool {
   207  	for _, addr := range addresses {
   208  		if addr.IP == proxyIP {
   209  			return true
   210  		}
   211  	}
   212  	return false
   213  }