istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/serviceregistry/serviceentry/controller_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 serviceentry
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"reflect"
    21  	"sort"
    22  	"strings"
    23  	"testing"
    24  	"time"
    25  
    26  	"istio.io/api/label"
    27  	networking "istio.io/api/networking/v1alpha3"
    28  	"istio.io/istio/pilot/pkg/config/memory"
    29  	"istio.io/istio/pilot/pkg/model"
    30  	"istio.io/istio/pilot/pkg/serviceregistry/util/xdsfake"
    31  	"istio.io/istio/pkg/config"
    32  	"istio.io/istio/pkg/config/constants"
    33  	"istio.io/istio/pkg/config/host"
    34  	"istio.io/istio/pkg/config/labels"
    35  	"istio.io/istio/pkg/config/schema/collections"
    36  	"istio.io/istio/pkg/config/schema/gvk"
    37  	"istio.io/istio/pkg/maps"
    38  	"istio.io/istio/pkg/ptr"
    39  	"istio.io/istio/pkg/slices"
    40  	"istio.io/istio/pkg/spiffe"
    41  	"istio.io/istio/pkg/test"
    42  	"istio.io/istio/pkg/test/util/assert"
    43  	"istio.io/istio/pkg/test/util/retry"
    44  )
    45  
    46  func createConfigs(configs []*config.Config, store model.ConfigStore, t testing.TB) {
    47  	t.Helper()
    48  	for _, cfg := range configs {
    49  		_, err := store.Create(*cfg)
    50  		if err != nil && strings.Contains(err.Error(), "item already exists") {
    51  			_, err := store.Update(*cfg)
    52  			if err != nil {
    53  				t.Fatalf("error occurred updating ServiceEntry config: %v", err)
    54  			}
    55  		} else if err != nil {
    56  			t.Fatalf("error occurred creating ServiceEntry config: %v", err)
    57  		}
    58  	}
    59  }
    60  
    61  func callInstanceHandlers(instances []*model.WorkloadInstance, sd *Controller, ev model.Event, t testing.TB) {
    62  	t.Helper()
    63  	for _, instance := range instances {
    64  		sd.WorkloadInstanceHandler(instance, ev)
    65  	}
    66  }
    67  
    68  func deleteConfigs(configs []*config.Config, store model.ConfigStore, t testing.TB) {
    69  	t.Helper()
    70  	for _, cfg := range configs {
    71  		err := store.Delete(cfg.GroupVersionKind, cfg.Name, cfg.Namespace, nil)
    72  		if err != nil {
    73  			t.Errorf("error occurred crearting ServiceEntry config: %v", err)
    74  		}
    75  	}
    76  }
    77  
    78  type Event = xdsfake.Event
    79  
    80  func initServiceDiscovery(t test.Failer) (model.ConfigStore, *Controller, *xdsfake.Updater) {
    81  	return initServiceDiscoveryWithOpts(t, false)
    82  }
    83  
    84  // initServiceDiscoveryWithoutEvents initializes a test setup with no events. This avoids excessive attempts to push
    85  // EDS updates to a full queue
    86  func initServiceDiscoveryWithoutEvents(t test.Failer) (model.ConfigStore, *Controller) {
    87  	store := memory.Make(collections.Pilot)
    88  	configController := memory.NewController(store)
    89  
    90  	stop := test.NewStop(t)
    91  	go configController.Run(stop)
    92  	fx := xdsfake.NewFakeXDS()
    93  	go func() {
    94  		for {
    95  			select {
    96  			case <-stop:
    97  				return
    98  			case <-fx.Events: // drain
    99  			}
   100  		}
   101  	}()
   102  
   103  	serviceController := NewController(configController, fx)
   104  	return configController, serviceController
   105  }
   106  
   107  func initServiceDiscoveryWithOpts(t test.Failer, workloadOnly bool, opts ...Option) (model.ConfigStore, *Controller, *xdsfake.Updater) {
   108  	store := memory.Make(collections.Pilot)
   109  	configController := memory.NewSyncController(store)
   110  
   111  	stop := test.NewStop(t)
   112  	go configController.Run(stop)
   113  
   114  	endpoints := model.NewEndpointIndex(model.DisabledCache{})
   115  	delegate := model.NewEndpointIndexUpdater(endpoints)
   116  	xdsUpdater := xdsfake.NewWithDelegate(delegate)
   117  
   118  	istioStore := configController
   119  	var controller *Controller
   120  	if !workloadOnly {
   121  		controller = NewController(configController, xdsUpdater, opts...)
   122  	} else {
   123  		controller = NewWorkloadEntryController(configController, xdsUpdater, opts...)
   124  	}
   125  	go controller.Run(stop)
   126  	return istioStore, controller, xdsUpdater
   127  }
   128  
   129  func TestServiceDiscoveryServices(t *testing.T) {
   130  	store, sd, fx := initServiceDiscovery(t)
   131  	expectedServices := []*model.Service{
   132  		makeService("*.istio.io", "httpDNSRR", constants.UnspecifiedIP, map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.DNSRoundRobinLB),
   133  		makeService("*.google.com", "httpDNS", constants.UnspecifiedIP, map[string]int{"http-port": 80, "http-alt-port": 8080}, true, model.DNSLB),
   134  		makeService("tcpstatic.com", "tcpStatic", "172.217.0.1", map[string]int{"tcp-444": 444}, true, model.ClientSideLB),
   135  	}
   136  
   137  	createConfigs([]*config.Config{httpDNS, httpDNSRR, tcpStatic}, store, t)
   138  
   139  	expectEvents(t, fx,
   140  		Event{Type: "xds full", ID: "*.google.com"},
   141  		Event{Type: "xds full", ID: "*.istio.io"},
   142  		Event{Type: "xds full", ID: "tcpstatic.com"},
   143  		Event{Type: "service", ID: "*.google.com", Namespace: httpDNS.Namespace},
   144  		Event{Type: "eds cache", ID: "*.google.com", Namespace: httpDNS.Namespace},
   145  		Event{Type: "service", ID: "*.istio.io", Namespace: httpDNSRR.Namespace},
   146  		Event{Type: "eds cache", ID: "*.istio.io", Namespace: httpDNSRR.Namespace},
   147  		Event{Type: "service", ID: "tcpstatic.com", Namespace: tcpStatic.Namespace},
   148  		Event{Type: "eds cache", ID: "tcpstatic.com", Namespace: tcpStatic.Namespace})
   149  	services := sd.Services()
   150  	sortServices(services)
   151  	sortServices(expectedServices)
   152  	if err := compare(t, services, expectedServices); err != nil {
   153  		t.Error(err)
   154  	}
   155  }
   156  
   157  func TestServiceDiscoveryGetService(t *testing.T) {
   158  	hostname := "*.google.com"
   159  	hostDNE := "does.not.exist.local"
   160  
   161  	store, sd, fx := initServiceDiscovery(t)
   162  
   163  	createConfigs([]*config.Config{httpDNS, tcpStatic}, store, t)
   164  	fx.WaitOrFail(t, "xds full")
   165  	fx.WaitOrFail(t, "xds full")
   166  	service := sd.GetService(host.Name(hostDNE))
   167  	if service != nil {
   168  		t.Errorf("GetService(%q) => should not exist, got %s", hostDNE, service.Hostname)
   169  	}
   170  
   171  	service = sd.GetService(host.Name(hostname))
   172  	if service == nil {
   173  		t.Fatalf("GetService(%q) => should exist", hostname)
   174  	}
   175  	if service.Hostname != host.Name(hostname) {
   176  		t.Errorf("GetService(%q) => %q, want %q", hostname, service.Hostname, hostname)
   177  	}
   178  }
   179  
   180  // TestServiceDiscoveryServiceUpdate test various add/update/delete events for ServiceEntry
   181  // nolint: lll
   182  func TestServiceDiscoveryServiceUpdate(t *testing.T) {
   183  	store, sd, events := initServiceDiscovery(t)
   184  	// httpStaticOverlayUpdated is the same as httpStaticOverlay but with an extra endpoint added to test updates
   185  	httpStaticOverlayUpdated := func() *config.Config {
   186  		c := httpStaticOverlay.DeepCopy()
   187  		se := c.Spec.(*networking.ServiceEntry)
   188  		se.Endpoints = append(se.Endpoints, &networking.WorkloadEntry{
   189  			Address: "6.6.6.6",
   190  			Labels:  map[string]string{"other": "bar"},
   191  		})
   192  		return &c
   193  	}()
   194  	// httpStaticOverlayUpdatedInstance is the same as httpStaticOverlayUpdated but with an extra endpoint added that has the same address
   195  	httpStaticOverlayUpdatedInstance := func() *config.Config {
   196  		c := httpStaticOverlayUpdated.DeepCopy()
   197  		se := c.Spec.(*networking.ServiceEntry)
   198  		se.Endpoints = append(se.Endpoints, &networking.WorkloadEntry{
   199  			Address: "6.6.6.6",
   200  			Labels:  map[string]string{"some-new-label": "bar"},
   201  		})
   202  		return &c
   203  	}()
   204  
   205  	// httpStaticOverlayUpdatedNop is the same as httpStaticOverlayUpdated but with a NOP change
   206  	httpStaticOverlayUpdatedNop := func() *config.Config {
   207  		return ptr.Of(httpStaticOverlayUpdated.DeepCopy())
   208  	}()
   209  
   210  	// httpStaticOverlayUpdatedNs is the same as httpStaticOverlay but with an extra endpoint and different namespace added to test updates
   211  	httpStaticOverlayUpdatedNs := func() *config.Config {
   212  		c := httpStaticOverlay.DeepCopy()
   213  		c.Namespace = "other"
   214  		se := c.Spec.(*networking.ServiceEntry)
   215  		se.Endpoints = append(se.Endpoints, &networking.WorkloadEntry{
   216  			Address: "7.7.7.7",
   217  			Labels:  map[string]string{"namespace": "bar"},
   218  		})
   219  		return &c
   220  	}()
   221  
   222  	// Setup the expected instances for `httpStatic`. This will be added/removed from as we add various configs
   223  	baseInstances := []*model.ServiceInstance{
   224  		makeInstance(httpStatic, "2.2.2.2", 7080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
   225  		makeInstance(httpStatic, "2.2.2.2", 18080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS),
   226  		makeInstance(httpStatic, "3.3.3.3", 1080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
   227  		makeInstance(httpStatic, "3.3.3.3", 8080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS),
   228  		makeInstance(httpStatic, "4.4.4.4", 1080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, PlainText),
   229  		makeInstance(httpStatic, "4.4.4.4", 8080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"foo": "bar"}, PlainText),
   230  	}
   231  
   232  	t.Run("simple entry", func(t *testing.T) {
   233  		// Create a SE, expect the base instances
   234  		createConfigs([]*config.Config{httpStatic}, store, t)
   235  		instances := baseInstances
   236  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   237  		expectEvents(t, events,
   238  			Event{Type: "service", ID: "*.google.com", Namespace: httpStatic.Namespace},
   239  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStatic.Namespace},
   240  			Event{Type: "xds full", ID: httpStatic.Spec.(*networking.ServiceEntry).Hosts[0]})
   241  	})
   242  
   243  	t.Run("add entry", func(t *testing.T) {
   244  		// Create another SE for the same host, expect these instances to get added
   245  		createConfigs([]*config.Config{httpStaticOverlay}, store, t)
   246  		instances := append(baseInstances,
   247  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText))
   248  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   249  		expectEvents(t, events,
   250  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   251  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   252  			Event{Type: "xds full", ID: httpStatic.Spec.(*networking.ServiceEntry).Hosts[0]})
   253  	})
   254  
   255  	t.Run("add endpoint", func(t *testing.T) {
   256  		// Update the SE for the same host, expect these instances to get added
   257  		createConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   258  		instances := append(baseInstances,
   259  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   260  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   261  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   262  		expectEvents(t, events, Event{Type: "eds", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace, EndpointCount: len(instances)})
   263  
   264  		// Make a NOP change, expect that there are no changes
   265  		createConfigs([]*config.Config{httpStaticOverlayUpdatedNop}, store, t)
   266  		expectServiceInstances(t, sd, httpStaticOverlayUpdatedNop, 0, instances)
   267  		// TODO this could trigger no changes
   268  		expectEvents(t, events, Event{Type: "eds", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace, EndpointCount: len(instances)})
   269  	})
   270  
   271  	t.Run("overlapping address", func(t *testing.T) {
   272  		// Add another SE with an additional endpoint with a matching address
   273  		createConfigs([]*config.Config{httpStaticOverlayUpdatedInstance}, store, t)
   274  		instances := append(baseInstances,
   275  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   276  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText),
   277  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"some-new-label": "bar"}, PlainText))
   278  		expectServiceInstances(t, sd, httpStaticOverlayUpdatedInstance, 0, instances)
   279  		proxyInstances := []model.ServiceTarget{
   280  			makeTarget(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText),
   281  			makeTarget(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"some-new-label": "bar"}, PlainText),
   282  		}
   283  		expectProxyTargets(t, sd, proxyInstances, "6.6.6.6")
   284  		// TODO 45 is wrong
   285  		expectEvents(t, events, Event{Type: "eds", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace, EndpointCount: len(instances)})
   286  
   287  		// Remove the additional endpoint
   288  		createConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   289  		instances = append(baseInstances,
   290  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   291  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   292  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   293  		proxyInstances = []model.ServiceTarget{
   294  			makeTarget(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText),
   295  		}
   296  		expectProxyTargets(t, sd, proxyInstances, "6.6.6.6")
   297  		expectEvents(t, events, Event{Type: "eds", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace, EndpointCount: len(instances)})
   298  	})
   299  
   300  	t.Run("update removes endpoint", func(t *testing.T) {
   301  		// Update the SE for the same host to remove the endpoint
   302  		createConfigs([]*config.Config{httpStaticOverlay}, store, t)
   303  		instances := append(baseInstances,
   304  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText))
   305  		expectServiceInstances(t, sd, httpStaticOverlay, 0, instances)
   306  		expectEvents(t, events,
   307  			Event{Type: "eds", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace, EndpointCount: len(instances)})
   308  	})
   309  
   310  	t.Run("different namespace", func(t *testing.T) {
   311  		// Update the SE for the same host in a different ns, expect these instances to get added
   312  		createConfigs([]*config.Config{httpStaticOverlayUpdatedNs}, store, t)
   313  		instances := []*model.ServiceInstance{
   314  			makeInstance(httpStaticOverlayUpdatedNs, "5.5.5.5", 4567, httpStaticOverlayUpdatedNs.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   315  			makeInstance(httpStaticOverlayUpdatedNs, "7.7.7.7", 4567, httpStaticOverlayUpdatedNs.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"namespace": "bar"}, PlainText),
   316  		}
   317  		// This lookup is per-namespace, so we should only see the objects in the same namespace
   318  		expectServiceInstances(t, sd, httpStaticOverlayUpdatedNs, 0, instances)
   319  		// Expect a full push, as the Service has changed
   320  		expectEvents(t, events,
   321  			Event{Type: "service", ID: "*.google.com", Namespace: "other"},
   322  			Event{Type: "eds cache", ID: "*.google.com", Namespace: "other"},
   323  			Event{Type: "xds full", ID: httpStaticOverlayUpdatedNs.Spec.(*networking.ServiceEntry).Hosts[0]})
   324  	})
   325  
   326  	t.Run("delete entry", func(t *testing.T) {
   327  		// Delete the additional SE in same namespace , expect it to get removed
   328  		deleteConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   329  		expectServiceInstances(t, sd, httpStatic, 0, baseInstances)
   330  		// Check the other namespace is untouched
   331  		instances := []*model.ServiceInstance{
   332  			makeInstance(httpStaticOverlayUpdatedNs, "5.5.5.5", 4567, httpStaticOverlayUpdatedNs.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   333  			makeInstance(httpStaticOverlayUpdatedNs, "7.7.7.7", 4567, httpStaticOverlayUpdatedNs.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"namespace": "bar"}, PlainText),
   334  		}
   335  		expectServiceInstances(t, sd, httpStaticOverlayUpdatedNs, 0, instances)
   336  		// svcUpdate is not triggered since `httpStatic` is there and has instances, so we should
   337  		// not delete the endpoints shards of "*.google.com". We xpect a full push as the service has changed.
   338  		expectEvents(t, events,
   339  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   340  			Event{Type: "xds full", ID: "*.google.com"},
   341  		)
   342  
   343  		// delete httpStatic, no "*.google.com" service exists now.
   344  		deleteConfigs([]*config.Config{httpStatic}, store, t)
   345  		// svcUpdate is triggered since "*.google.com" in same namespace is deleted and
   346  		// we need to delete endpoint shards. We expect a full push as the service has changed.
   347  		expectEvents(t, events,
   348  			Event{Type: "service", ID: "*.google.com", Namespace: httpStatic.Namespace},
   349  			Event{Type: "xds full", ID: "*.google.com"},
   350  		)
   351  
   352  		// add back httpStatic
   353  		createConfigs([]*config.Config{httpStatic}, store, t)
   354  		instances = baseInstances
   355  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   356  		expectEvents(t, events,
   357  			Event{Type: "service", ID: "*.google.com", Namespace: httpStatic.Namespace},
   358  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStatic.Namespace},
   359  			Event{Type: "xds full", ID: httpStatic.Spec.(*networking.ServiceEntry).Hosts[0]})
   360  
   361  		// Add back the ServiceEntry, expect these instances to get added
   362  		createConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   363  		instances = append(baseInstances,
   364  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   365  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   366  		expectServiceInstances(t, sd, httpStatic, 0, instances)
   367  		// Service change, so we need a full push
   368  		expectEvents(t, events,
   369  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   370  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   371  			Event{Type: "xds full", ID: "*.google.com"})
   372  	})
   373  
   374  	t.Run("change target port", func(t *testing.T) {
   375  		// Change the target port
   376  		targetPortChanged := func() *config.Config {
   377  			c := httpStaticOverlayUpdated.DeepCopy()
   378  			c.Spec.(*networking.ServiceEntry).Ports[0].TargetPort = 33333
   379  			return &c
   380  		}()
   381  		createConfigs([]*config.Config{targetPortChanged}, store, t)
   382  
   383  		// Endpoint ports should be changed
   384  		instances := append(baseInstances,
   385  			makeInstance(httpStaticOverlay, "5.5.5.5", 33333, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   386  			makeInstance(httpStaticOverlay, "6.6.6.6", 33333, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   387  		expectServiceInstances(t, sd, targetPortChanged, 0, instances)
   388  
   389  		// Expect a full push, as the target port has changed
   390  		expectEvents(t, events,
   391  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   392  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   393  			Event{Type: "xds full", ID: "*.google.com"})
   394  
   395  		// Restore the target port
   396  		createConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   397  
   398  		// Endpoint ports should be changed
   399  		instances = append(baseInstances,
   400  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   401  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   402  		expectServiceInstances(t, sd, targetPortChanged, 0, instances)
   403  		// Expect a full push, as the target port has changed
   404  		expectEvents(t, events,
   405  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   406  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   407  			Event{Type: "xds full", ID: "*.google.com"})
   408  	})
   409  
   410  	t.Run("change host", func(t *testing.T) {
   411  		// same as httpStaticOverlayUpdated but with an additional host
   412  		httpStaticHost := func() *config.Config {
   413  			c := httpStaticOverlayUpdated.DeepCopy()
   414  			se := c.Spec.(*networking.ServiceEntry)
   415  			se.Hosts = append(se.Hosts, "other.com")
   416  			return &c
   417  		}()
   418  		createConfigs([]*config.Config{httpStaticHost}, store, t)
   419  		instances := append(baseInstances,
   420  			makeInstance(httpStaticOverlay, "5.5.5.5", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   421  			makeInstance(httpStaticOverlay, "6.6.6.6", 4567, httpStaticOverlay.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText))
   422  		// This is not applied, just to make makeInstance pick the right service.
   423  		otherHost := func() *config.Config {
   424  			c := httpStaticOverlayUpdated.DeepCopy()
   425  			se := c.Spec.(*networking.ServiceEntry)
   426  			se.Hosts = []string{"other.com"}
   427  			return &c
   428  		}()
   429  		instances2 := []*model.ServiceInstance{
   430  			makeInstance(otherHost, "5.5.5.5", 4567, httpStaticHost.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"overlay": "bar"}, PlainText),
   431  			makeInstance(otherHost, "6.6.6.6", 4567, httpStaticHost.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"other": "bar"}, PlainText),
   432  		}
   433  		expectServiceInstances(t, sd, httpStaticHost, 0, instances, instances2)
   434  		// Service change, so we need a full push
   435  		expectEvents(t, events,
   436  			Event{Type: "service", ID: "other.com", Namespace: httpStaticOverlayUpdated.Namespace},
   437  			Event{Type: "eds cache", ID: "other.com", Namespace: httpStaticOverlayUpdated.Namespace},
   438  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlayUpdated.Namespace},
   439  			Event{Type: "xds full", ID: "other.com"}) // service added
   440  
   441  		// restore this config and remove the added host.
   442  		createConfigs([]*config.Config{httpStaticOverlayUpdated}, store, t)
   443  		expectEvents(t, events,
   444  			Event{Type: "service", ID: "other.com", Namespace: httpStatic.Namespace},
   445  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStatic.Namespace},
   446  			Event{Type: "xds full", ID: "other.com"}) // service deleted
   447  	})
   448  
   449  	t.Run("change dns endpoints", func(t *testing.T) {
   450  		// Setup the expected instances for DNS. This will be added/removed from as we add various configs
   451  		instances1 := []*model.ServiceInstance{
   452  			makeInstance(tcpDNS, "lon.google.com", 444, tcpDNS.Spec.(*networking.ServiceEntry).Ports[0],
   453  				nil, MTLS),
   454  			makeInstance(tcpDNS, "in.google.com", 444, tcpDNS.Spec.(*networking.ServiceEntry).Ports[0],
   455  				nil, MTLS),
   456  		}
   457  
   458  		// This is not applied, just to make makeInstance pick the right service.
   459  		tcpDNSUpdated := func() *config.Config {
   460  			c := tcpDNS.DeepCopy()
   461  			se := c.Spec.(*networking.ServiceEntry)
   462  			se.Endpoints = []*networking.WorkloadEntry{
   463  				{
   464  					Address: "lon.google.com",
   465  					Labels:  map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
   466  				},
   467  			}
   468  			return &c
   469  		}()
   470  
   471  		instances2 := []*model.ServiceInstance{
   472  			makeInstance(tcpDNS, "lon.google.com", 444, tcpDNS.Spec.(*networking.ServiceEntry).Ports[0],
   473  				nil, MTLS),
   474  		}
   475  
   476  		createConfigs([]*config.Config{tcpDNS}, store, t)
   477  		expectServiceInstances(t, sd, tcpDNS, 0, instances1)
   478  		// Service change, so we need a full push
   479  		expectEvents(t, events,
   480  			Event{Type: "service", ID: "tcpdns.com", Namespace: tcpDNS.Namespace},
   481  			Event{Type: "eds cache", ID: "tcpdns.com", Namespace: tcpDNS.Namespace},
   482  			Event{Type: "xds full", ID: "tcpdns.com"}) // service added
   483  
   484  		// now update the config
   485  		createConfigs([]*config.Config{tcpDNSUpdated}, store, t)
   486  		expectEvents(t, events,
   487  			Event{Type: "xds full", ID: "tcpdns.com"},
   488  			Event{Type: "eds cache", ID: "tcpdns.com"},
   489  		) // service deleted
   490  		expectServiceInstances(t, sd, tcpDNS, 0, instances2)
   491  	})
   492  
   493  	t.Run("change workload selector", func(t *testing.T) {
   494  		// same as selector but with an additional host
   495  		selector1 := func() *config.Config {
   496  			c := httpStaticOverlay.DeepCopy()
   497  			se := c.Spec.(*networking.ServiceEntry)
   498  			se.Hosts = append(se.Hosts, "selector1.com")
   499  			se.Endpoints = nil
   500  			se.WorkloadSelector = &networking.WorkloadSelector{
   501  				Labels: map[string]string{"app": "wle"},
   502  			}
   503  			return &c
   504  		}()
   505  		createConfigs([]*config.Config{selector1}, store, t)
   506  		// Service change, so we need a full push
   507  		expectEvents(t, events,
   508  			Event{Type: "service", ID: "selector1.com", Namespace: httpStaticOverlay.Namespace},
   509  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   510  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   511  			Event{Type: "xds full", ID: "*.google.com,selector1.com"}) // service added
   512  
   513  		selector1Updated := func() *config.Config {
   514  			c := selector1.DeepCopy()
   515  			se := c.Spec.(*networking.ServiceEntry)
   516  			se.WorkloadSelector = &networking.WorkloadSelector{
   517  				Labels: map[string]string{"app": "wle1"},
   518  			}
   519  			return &c
   520  		}()
   521  		createConfigs([]*config.Config{selector1Updated}, store, t)
   522  		expectEvents(t, events,
   523  			Event{Type: "service", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   524  			Event{Type: "service", ID: "selector1.com", Namespace: httpStaticOverlay.Namespace},
   525  			Event{Type: "eds cache", ID: "*.google.com", Namespace: httpStaticOverlay.Namespace},
   526  			Event{Type: "xds full", ID: "*.google.com,selector1.com"}) // service updated
   527  	})
   528  }
   529  
   530  func TestServiceDiscoveryWorkloadUpdate(t *testing.T) {
   531  	store, sd, events := initServiceDiscovery(t)
   532  
   533  	// Setup a couple workload entries for test. These will be selected by the `selector` SE
   534  	wle := createWorkloadEntry("wl", selector.Name,
   535  		&networking.WorkloadEntry{
   536  			Address:        "2.2.2.2",
   537  			Labels:         map[string]string{"app": "wle"},
   538  			ServiceAccount: "default",
   539  		})
   540  	wle2 := createWorkloadEntry("wl2", selector.Name,
   541  		&networking.WorkloadEntry{
   542  			Address:        "3.3.3.3",
   543  			Labels:         map[string]string{"app": "wle"},
   544  			ServiceAccount: "default",
   545  		})
   546  	wle3 := createWorkloadEntry("wl3", selector.Name,
   547  		&networking.WorkloadEntry{
   548  			Address:        "abc.def",
   549  			Labels:         map[string]string{"app": "wle"},
   550  			ServiceAccount: "default",
   551  		})
   552  	dnsWle := createWorkloadEntry("dnswl", dnsSelector.Namespace,
   553  		&networking.WorkloadEntry{
   554  			Address:        "4.4.4.4",
   555  			Labels:         map[string]string{"app": "dns-wle"},
   556  			ServiceAccount: "default",
   557  		})
   558  
   559  	t.Run("service entry", func(t *testing.T) {
   560  		// Add just the ServiceEntry with selector. We should see no instances
   561  		createConfigs([]*config.Config{selector}, store, t)
   562  		instances := []*model.ServiceInstance{}
   563  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   564  		expectServiceInstances(t, sd, selector, 0, instances)
   565  		expectEvents(t, events,
   566  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
   567  			Event{Type: "eds cache", ID: "selector.com", Namespace: selector.Namespace},
   568  			Event{Type: "xds full", ID: "selector.com"})
   569  	})
   570  
   571  	t.Run("add workload", func(t *testing.T) {
   572  		// Add a WLE, we expect this to update
   573  		createConfigs([]*config.Config{wle}, store, t)
   574  
   575  		instances := []*model.ServiceInstance{
   576  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   577  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   578  				map[string]string{"app": "wle"}, "default"),
   579  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   580  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   581  				map[string]string{"app": "wle"}, "default"),
   582  		}
   583  		for _, i := range instances {
   584  			i.Endpoint.WorkloadName = "wl"
   585  			i.Endpoint.Namespace = selector.Name
   586  		}
   587  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   588  		expectServiceInstances(t, sd, selector, 0, instances)
   589  		expectEvents(t, events,
   590  			Event{Type: "proxy", ID: "2.2.2.2"},
   591  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2},
   592  		)
   593  	})
   594  
   595  	t.Run("update service entry host", func(t *testing.T) {
   596  		updated := func() *config.Config {
   597  			d := selector.DeepCopy()
   598  			se := d.Spec.(*networking.ServiceEntry)
   599  			se.Hosts = []string{"updated.com"}
   600  			return &d
   601  		}()
   602  
   603  		instances := []*model.ServiceInstance{
   604  			makeInstanceWithServiceAccount(updated, "2.2.2.2", 444,
   605  				updated.Spec.(*networking.ServiceEntry).Ports[0],
   606  				map[string]string{"app": "wle"}, "default"),
   607  			makeInstanceWithServiceAccount(updated, "2.2.2.2", 445,
   608  				updated.Spec.(*networking.ServiceEntry).Ports[1],
   609  				map[string]string{"app": "wle"}, "default"),
   610  		}
   611  		for _, i := range instances {
   612  			i.Endpoint.WorkloadName = "wl"
   613  			i.Endpoint.Namespace = updated.Name
   614  		}
   615  
   616  		createConfigs([]*config.Config{updated}, store, t)
   617  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   618  		expectServiceInstances(t, sd, selector, 0, []*model.ServiceInstance{})
   619  		expectServiceInstances(t, sd, updated, 0, instances)
   620  		expectEvents(t, events,
   621  			Event{Type: "service", ID: "updated.com", Namespace: selector.Namespace},
   622  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
   623  			Event{Type: "eds cache", ID: "updated.com", Namespace: selector.Namespace},
   624  			Event{Type: "xds full", ID: "selector.com,updated.com"},
   625  		)
   626  	})
   627  
   628  	t.Run("restore service entry host", func(t *testing.T) {
   629  		instances := []*model.ServiceInstance{
   630  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   631  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   632  				map[string]string{"app": "wle"}, "default"),
   633  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   634  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   635  				map[string]string{"app": "wle"}, "default"),
   636  		}
   637  		for _, i := range instances {
   638  			i.Endpoint.WorkloadName = "wl"
   639  			i.Endpoint.Namespace = selector.Name
   640  		}
   641  		updated := func() *config.Config {
   642  			d := selector.DeepCopy()
   643  			se := d.Spec.(*networking.ServiceEntry)
   644  			se.Hosts = []string{"updated.com"}
   645  			return &d
   646  		}()
   647  
   648  		createConfigs([]*config.Config{selector}, store, t)
   649  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   650  		expectServiceInstances(t, sd, selector, 0, instances)
   651  		expectServiceInstances(t, sd, updated, 0, []*model.ServiceInstance{})
   652  		expectEvents(t, events,
   653  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
   654  			Event{Type: "service", ID: "updated.com", Namespace: selector.Namespace},
   655  			Event{Type: "eds cache", ID: "selector.com", Namespace: selector.Namespace},
   656  			Event{Type: "xds full", ID: "selector.com,updated.com"},
   657  		)
   658  	})
   659  
   660  	t.Run("add dns service entry", func(t *testing.T) {
   661  		// Add just the ServiceEntry with selector. We should see no instances
   662  		createConfigs([]*config.Config{dnsSelector}, store, t)
   663  		instances := []*model.ServiceInstance{}
   664  		expectProxyInstances(t, sd, instances, "4.4.4.4")
   665  		expectServiceInstances(t, sd, dnsSelector, 0, instances)
   666  		expectEvents(t, events,
   667  			Event{Type: "service", ID: "dns.selector.com", Namespace: dnsSelector.Namespace},
   668  			Event{Type: "eds cache", ID: "dns.selector.com", Namespace: dnsSelector.Namespace},
   669  			Event{Type: "xds full", ID: "dns.selector.com"})
   670  	})
   671  
   672  	t.Run("add dns workload", func(t *testing.T) {
   673  		// Add a WLE, we expect this to update
   674  		createConfigs([]*config.Config{dnsWle}, store, t)
   675  		instances := []*model.ServiceInstance{
   676  			makeInstanceWithServiceAccount(dnsSelector, "4.4.4.4", 444,
   677  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   678  				map[string]string{"app": "dns-wle"}, "default"),
   679  			makeInstanceWithServiceAccount(dnsSelector, "4.4.4.4", 445,
   680  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   681  				map[string]string{"app": "dns-wle"}, "default"),
   682  		}
   683  		for _, i := range instances {
   684  			i.Endpoint.WorkloadName = "dnswl"
   685  			i.Endpoint.Namespace = dnsSelector.Namespace
   686  		}
   687  		expectProxyInstances(t, sd, instances, "4.4.4.4")
   688  		expectServiceInstances(t, sd, dnsSelector, 0, instances)
   689  		expectEvents(t, events,
   690  			Event{Type: "eds cache", ID: "dns.selector.com", Namespace: dnsSelector.Namespace},
   691  			Event{Type: "xds full", ID: "dns.selector.com"})
   692  	})
   693  
   694  	t.Run("another workload", func(t *testing.T) {
   695  		// Add a different WLE
   696  		createConfigs([]*config.Config{wle2}, store, t)
   697  		instances := []*model.ServiceInstance{
   698  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   699  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   700  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   701  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
   702  		}
   703  		for _, i := range instances {
   704  			i.Endpoint.WorkloadName = "wl"
   705  			i.Endpoint.Namespace = selector.Name
   706  		}
   707  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   708  		instances = append(instances,
   709  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 444,
   710  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   711  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 445,
   712  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"))
   713  		for _, i := range instances[2:] {
   714  			i.Endpoint.WorkloadName = "wl2"
   715  			i.Endpoint.Namespace = selector.Name
   716  		}
   717  		expectServiceInstances(t, sd, selector, 0, instances)
   718  		expectEvents(t, events,
   719  			Event{Type: "proxy", ID: "3.3.3.3"},
   720  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 4},
   721  		)
   722  	})
   723  
   724  	t.Run("ignore host workload", func(t *testing.T) {
   725  		// Add a WLE with host address. Should be ignored by static service entry.
   726  		createConfigs([]*config.Config{wle3}, store, t)
   727  		instances := []*model.ServiceInstance{
   728  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   729  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   730  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   731  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
   732  		}
   733  		for _, i := range instances {
   734  			i.Endpoint.WorkloadName = "wl"
   735  			i.Endpoint.Namespace = selector.Name
   736  		}
   737  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   738  		instances = append(instances,
   739  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 444,
   740  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   741  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 445,
   742  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"))
   743  		for _, i := range instances[2:] {
   744  			i.Endpoint.WorkloadName = "wl2"
   745  			i.Endpoint.Namespace = selector.Name
   746  		}
   747  		expectServiceInstances(t, sd, selector, 0, instances)
   748  		expectEvents(t, events,
   749  			Event{Type: "proxy", ID: "abc.def"},
   750  		)
   751  	})
   752  
   753  	t.Run("deletion", func(t *testing.T) {
   754  		// Delete the configs, it should be gone
   755  		deleteConfigs([]*config.Config{wle2}, store, t)
   756  		instances := []*model.ServiceInstance{
   757  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   758  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   759  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   760  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
   761  		}
   762  		for _, i := range instances {
   763  			i.Endpoint.WorkloadName = "wl"
   764  			i.Endpoint.Namespace = selector.Name
   765  		}
   766  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   767  		expectServiceInstances(t, sd, selector, 0, instances)
   768  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2})
   769  
   770  		// Delete the other config
   771  		deleteConfigs([]*config.Config{wle}, store, t)
   772  		instances = []*model.ServiceInstance{}
   773  		expectServiceInstances(t, sd, selector, 0, instances)
   774  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   775  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 0})
   776  
   777  		// Add the config back
   778  		createConfigs([]*config.Config{wle}, store, t)
   779  		instances = []*model.ServiceInstance{
   780  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   781  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   782  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   783  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
   784  		}
   785  		for _, i := range instances {
   786  			i.Endpoint.WorkloadName = "wl"
   787  			i.Endpoint.Namespace = selector.Name
   788  		}
   789  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   790  		expectServiceInstances(t, sd, selector, 0, instances)
   791  		expectEvents(t, events,
   792  			Event{Type: "proxy", ID: "2.2.2.2"},
   793  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2},
   794  		)
   795  	})
   796  
   797  	t.Run("update", func(t *testing.T) {
   798  		updated := func() *config.Config {
   799  			d := wle.DeepCopy()
   800  			we := d.Spec.(*networking.WorkloadEntry)
   801  			we.Address = "9.9.9.9"
   802  			return &d
   803  		}()
   804  		// Update the configs
   805  		createConfigs([]*config.Config{updated}, store, t)
   806  		instances := []*model.ServiceInstance{
   807  			makeInstanceWithServiceAccount(selector, "9.9.9.9", 444,
   808  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
   809  			makeInstanceWithServiceAccount(selector, "9.9.9.9", 445,
   810  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
   811  		}
   812  		for _, i := range instances {
   813  			i.Endpoint.WorkloadName = "wl"
   814  			i.Endpoint.Namespace = selector.Name
   815  		}
   816  		// Old IP is gone
   817  		expectProxyInstances(t, sd, nil, "2.2.2.2")
   818  		expectProxyInstances(t, sd, instances, "9.9.9.9")
   819  		expectServiceInstances(t, sd, selector, 0, instances)
   820  		expectEvents(t, events,
   821  			Event{Type: "proxy", ID: "9.9.9.9"},
   822  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2},
   823  		)
   824  	})
   825  
   826  	t.Run("cleanup", func(t *testing.T) {
   827  		deleteConfigs([]*config.Config{wle, selector, dnsSelector, dnsWle, wle3}, store, t)
   828  		assertControllerEmpty(t, sd)
   829  	})
   830  }
   831  
   832  func assertControllerEmpty(t *testing.T, sd *Controller) {
   833  	assert.Equal(t, len(sd.services.servicesBySE), 0)
   834  	assert.Equal(t, len(sd.serviceInstances.ip2instance), 0)
   835  	assert.Equal(t, len(sd.serviceInstances.instances), 0)
   836  	assert.Equal(t, len(sd.serviceInstances.instancesBySE), 0)
   837  	assert.Equal(t, len(sd.serviceInstances.instancesByHostAndPort), 0)
   838  	assert.Equal(t, sd.workloadInstances.Empty(), true)
   839  }
   840  
   841  func TestServiceDiscoveryWorkloadChangeLabel(t *testing.T) {
   842  	store, sd, events := initServiceDiscovery(t)
   843  
   844  	wle := createWorkloadEntry("wl", selector.Name,
   845  		&networking.WorkloadEntry{
   846  			Address:        "2.2.2.2",
   847  			Labels:         map[string]string{"app": "wle"},
   848  			ServiceAccount: "default",
   849  		})
   850  
   851  	wle2 := createWorkloadEntry("wl", selector.Name,
   852  		&networking.WorkloadEntry{
   853  			Address:        "2.2.2.2",
   854  			Labels:         map[string]string{"app": "wle2"},
   855  			ServiceAccount: "default",
   856  		})
   857  	wle3 := createWorkloadEntry("wl3", selector.Name,
   858  		&networking.WorkloadEntry{
   859  			Address:        "3.3.3.3",
   860  			Labels:         map[string]string{"app": "wle"},
   861  			ServiceAccount: "default",
   862  		})
   863  
   864  	t.Run("service entry", func(t *testing.T) {
   865  		// Add just the ServiceEntry with selector. We should see no instances
   866  		createConfigs([]*config.Config{selector}, store, t)
   867  		instances := []*model.ServiceInstance{}
   868  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   869  		expectServiceInstances(t, sd, selector, 0, instances)
   870  		expectEvents(t, events,
   871  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
   872  			Event{Type: "eds cache", ID: "selector.com", Namespace: selector.Namespace},
   873  			Event{Type: "xds full", ID: "selector.com"})
   874  	})
   875  
   876  	t.Run("change label removing all", func(t *testing.T) {
   877  		// Add a WLE, we expect this to update
   878  		createConfigs([]*config.Config{wle}, store, t)
   879  		instances := []*model.ServiceInstance{
   880  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   881  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   882  				map[string]string{"app": "wle"}, "default"),
   883  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   884  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   885  				map[string]string{"app": "wle"}, "default"),
   886  		}
   887  		for _, i := range instances {
   888  			i.Endpoint.WorkloadName = "wl"
   889  			i.Endpoint.Namespace = selector.Name
   890  		}
   891  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   892  		expectServiceInstances(t, sd, selector, 0, instances)
   893  		expectEvents(t, events,
   894  			Event{Type: "proxy", ID: "2.2.2.2"},
   895  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2},
   896  		)
   897  
   898  		createConfigs([]*config.Config{wle2}, store, t)
   899  		instances = []*model.ServiceInstance{}
   900  		expectServiceInstances(t, sd, selector, 0, instances)
   901  		expectProxyInstances(t, sd, instances, "2.2.2.2")
   902  		expectEvents(t, events,
   903  			Event{Type: "proxy", ID: "2.2.2.2"},
   904  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 0})
   905  	})
   906  
   907  	t.Run("change label removing one", func(t *testing.T) {
   908  		// Add a WLE, we expect this to update
   909  		createConfigs([]*config.Config{wle}, store, t)
   910  		expectEvents(t, events,
   911  			Event{Type: "proxy", ID: "2.2.2.2"},
   912  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2},
   913  		)
   914  		// add a wle, expect this to be an add
   915  		createConfigs([]*config.Config{wle3}, store, t)
   916  		instances := []*model.ServiceInstance{
   917  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
   918  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   919  				map[string]string{"app": "wle"}, "default"),
   920  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
   921  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   922  				map[string]string{"app": "wle"}, "default"),
   923  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 444,
   924  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   925  				map[string]string{"app": "wle"}, "default"),
   926  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 445,
   927  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   928  				map[string]string{"app": "wle"}, "default"),
   929  		}
   930  		for _, i := range instances[:2] {
   931  			i.Endpoint.WorkloadName = "wl"
   932  			i.Endpoint.Namespace = selector.Name
   933  		}
   934  		for _, i := range instances[2:] {
   935  			i.Endpoint.WorkloadName = "wl3"
   936  			i.Endpoint.Namespace = selector.Name
   937  		}
   938  		expectProxyInstances(t, sd, instances[:2], "2.2.2.2")
   939  		expectProxyInstances(t, sd, instances[2:], "3.3.3.3")
   940  		expectServiceInstances(t, sd, selector, 0, instances)
   941  		expectEvents(t, events,
   942  			Event{Type: "proxy", ID: "3.3.3.3"},
   943  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 4},
   944  		)
   945  
   946  		createConfigs([]*config.Config{wle2}, store, t)
   947  		instances = []*model.ServiceInstance{
   948  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 444,
   949  				selector.Spec.(*networking.ServiceEntry).Ports[0],
   950  				map[string]string{"app": "wle"}, "default"),
   951  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 445,
   952  				selector.Spec.(*networking.ServiceEntry).Ports[1],
   953  				map[string]string{"app": "wle"}, "default"),
   954  		}
   955  		for _, i := range instances {
   956  			i.Endpoint.WorkloadName = "wl3"
   957  			i.Endpoint.Namespace = selector.Name
   958  		}
   959  		expectServiceInstances(t, sd, selector, 0, instances)
   960  		expectProxyInstances(t, sd, instances, "3.3.3.3")
   961  		expectEvents(t, events,
   962  			Event{Type: "proxy", ID: "2.2.2.2"},
   963  			Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2})
   964  	})
   965  }
   966  
   967  func TestWorkloadInstanceFullPush(t *testing.T) {
   968  	store, sd, events := initServiceDiscovery(t)
   969  
   970  	// Setup a WorkloadEntry with selector the same as ServiceEntry
   971  	wle := createWorkloadEntry("wl", selectorDNS.Name,
   972  		&networking.WorkloadEntry{
   973  			Address:        "postman-echo.com",
   974  			Labels:         map[string]string{"app": "wle"},
   975  			ServiceAccount: "default",
   976  		})
   977  
   978  	fi1 := &model.WorkloadInstance{
   979  		Name:      "additional-name",
   980  		Namespace: selectorDNS.Name,
   981  		Endpoint: &model.IstioEndpoint{
   982  			Address:        "4.4.4.4",
   983  			Labels:         map[string]string{"app": "wle"},
   984  			ServiceAccount: spiffe.MustGenSpiffeURI(selectorDNS.Name, "default"),
   985  			TLSMode:        model.IstioMutualTLSModeLabel,
   986  		},
   987  	}
   988  
   989  	fi2 := &model.WorkloadInstance{
   990  		Name:      "another-name",
   991  		Namespace: selectorDNS.Namespace,
   992  		Endpoint: &model.IstioEndpoint{
   993  			Address:        "2.2.2.2",
   994  			Labels:         map[string]string{"app": "wle"},
   995  			ServiceAccount: spiffe.MustGenSpiffeURI(selectorDNS.Name, "default"),
   996  			TLSMode:        model.IstioMutualTLSModeLabel,
   997  		},
   998  	}
   999  
  1000  	t.Run("service entry", func(t *testing.T) {
  1001  		// Add just the ServiceEntry with selector. We should see no instances
  1002  		createConfigs([]*config.Config{selectorDNS}, store, t)
  1003  		instances := []*model.ServiceInstance{}
  1004  		expectProxyInstances(t, sd, instances, "4.4.4.4")
  1005  		expectServiceInstances(t, sd, selectorDNS, 0, instances)
  1006  		expectEvents(t, events,
  1007  			Event{Type: "service", ID: "selector.com", Namespace: selectorDNS.Namespace},
  1008  			Event{Type: "eds cache", ID: "selector.com", Namespace: selectorDNS.Namespace},
  1009  			Event{Type: "xds full", ID: "selector.com"})
  1010  	})
  1011  
  1012  	t.Run("add workload", func(t *testing.T) {
  1013  		// Add a WLE, we expect this to update
  1014  		createConfigs([]*config.Config{wle}, store, t)
  1015  
  1016  		instances := []*model.ServiceInstance{
  1017  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 444,
  1018  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[0],
  1019  				map[string]string{"app": "wle"}, "default"),
  1020  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 445,
  1021  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[1],
  1022  				map[string]string{"app": "wle"}, "default"),
  1023  		}
  1024  		for _, i := range instances {
  1025  			i.Endpoint.WorkloadName = "wl"
  1026  			i.Endpoint.Namespace = selectorDNS.Name
  1027  		}
  1028  		expectProxyInstances(t, sd, instances, "postman-echo.com")
  1029  		expectServiceInstances(t, sd, selectorDNS, 0, instances)
  1030  		expectEvents(t, events,
  1031  			Event{Type: "eds cache", ID: "selector.com", Namespace: selectorDNS.Namespace},
  1032  			Event{Type: "xds full", ID: "selector.com"},
  1033  		)
  1034  	})
  1035  
  1036  	t.Run("full push for new instance", func(t *testing.T) {
  1037  		callInstanceHandlers([]*model.WorkloadInstance{fi1}, sd, model.EventAdd, t)
  1038  		instances := []*model.ServiceInstance{
  1039  			makeInstanceWithServiceAccount(selectorDNS, "4.4.4.4", 444,
  1040  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1041  			makeInstanceWithServiceAccount(selectorDNS, "4.4.4.4", 445,
  1042  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1043  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 444,
  1044  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1045  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 445,
  1046  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1047  		}
  1048  
  1049  		for _, i := range instances[2:] {
  1050  			i.Endpoint.WorkloadName = "wl"
  1051  			i.Endpoint.Namespace = selectorDNS.Name
  1052  		}
  1053  
  1054  		expectProxyInstances(t, sd, instances[:2], "4.4.4.4")
  1055  		expectProxyInstances(t, sd, instances[2:], "postman-echo.com")
  1056  		expectServiceInstances(t, sd, selectorDNS, 0, instances)
  1057  		expectEvents(t, events,
  1058  			Event{Type: "eds", ID: "selector.com", Namespace: selectorDNS.Namespace, EndpointCount: len(instances)},
  1059  			Event{Type: "xds full", ID: "selector.com"})
  1060  	})
  1061  
  1062  	t.Run("full push for another new workload instance", func(t *testing.T) {
  1063  		callInstanceHandlers([]*model.WorkloadInstance{fi2}, sd, model.EventAdd, t)
  1064  		expectEvents(t, events,
  1065  			Event{Type: "eds", ID: "selector.com", Namespace: selectorDNS.Namespace, EndpointCount: 6},
  1066  			Event{Type: "xds full", ID: "selector.com"})
  1067  	})
  1068  
  1069  	t.Run("full push on delete workload instance", func(t *testing.T) {
  1070  		callInstanceHandlers([]*model.WorkloadInstance{fi1}, sd, model.EventDelete, t)
  1071  		instances := []*model.ServiceInstance{
  1072  			makeInstanceWithServiceAccount(selectorDNS, "2.2.2.2", 444,
  1073  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1074  			makeInstanceWithServiceAccount(selectorDNS, "2.2.2.2", 445,
  1075  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1076  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 444,
  1077  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1078  			makeInstanceWithServiceAccount(selectorDNS, "postman-echo.com", 445,
  1079  				selectorDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1080  		}
  1081  
  1082  		for _, i := range instances[2:] {
  1083  			i.Endpoint.WorkloadName = "wl"
  1084  			i.Endpoint.Namespace = selectorDNS.Name
  1085  		}
  1086  
  1087  		expectProxyInstances(t, sd, instances[:2], "2.2.2.2")
  1088  		expectProxyInstances(t, sd, instances[2:], "postman-echo.com")
  1089  		expectServiceInstances(t, sd, selectorDNS, 0, instances)
  1090  
  1091  		expectEvents(t, events,
  1092  			Event{Type: "eds", ID: "selector.com", Namespace: selectorDNS.Namespace, EndpointCount: len(instances)},
  1093  			Event{Type: "xds full", ID: "selector.com"})
  1094  	})
  1095  }
  1096  
  1097  func TestServiceDiscoveryWorkloadInstance(t *testing.T) {
  1098  	store, sd, events := initServiceDiscovery(t)
  1099  
  1100  	// Setup a couple of workload instances for test. These will be selected by the `selector` SE
  1101  	fi1 := &model.WorkloadInstance{
  1102  		Name:      selector.Name,
  1103  		Namespace: selector.Namespace,
  1104  		Endpoint: &model.IstioEndpoint{
  1105  			Address:        "2.2.2.2",
  1106  			Labels:         map[string]string{"app": "wle"},
  1107  			ServiceAccount: spiffe.MustGenSpiffeURI(selector.Name, "default"),
  1108  			TLSMode:        model.IstioMutualTLSModeLabel,
  1109  		},
  1110  	}
  1111  
  1112  	fi2 := &model.WorkloadInstance{
  1113  		Name:      "some-other-name",
  1114  		Namespace: selector.Namespace,
  1115  		Endpoint: &model.IstioEndpoint{
  1116  			Address:        "3.3.3.3",
  1117  			Labels:         map[string]string{"app": "wle"},
  1118  			ServiceAccount: spiffe.MustGenSpiffeURI(selector.Name, "default"),
  1119  			TLSMode:        model.IstioMutualTLSModeLabel,
  1120  		},
  1121  	}
  1122  
  1123  	fi3 := &model.WorkloadInstance{
  1124  		Name:      "another-name",
  1125  		Namespace: dnsSelector.Namespace,
  1126  		Endpoint: &model.IstioEndpoint{
  1127  			Address:        "2.2.2.2",
  1128  			Labels:         map[string]string{"app": "dns-wle"},
  1129  			ServiceAccount: spiffe.MustGenSpiffeURI(dnsSelector.Name, "default"),
  1130  			TLSMode:        model.IstioMutualTLSModeLabel,
  1131  		},
  1132  	}
  1133  
  1134  	t.Run("service entry", func(t *testing.T) {
  1135  		// Add just the ServiceEntry with selector. We should see no instances
  1136  		createConfigs([]*config.Config{selector}, store, t)
  1137  		instances := []*model.ServiceInstance{}
  1138  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1139  		expectServiceInstances(t, sd, selector, 0, instances)
  1140  		expectEvents(t, events,
  1141  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
  1142  			Event{Type: "eds cache", ID: "selector.com", Namespace: selector.Namespace},
  1143  			Event{Type: "xds full", ID: "selector.com"})
  1144  	})
  1145  
  1146  	t.Run("add another service entry", func(t *testing.T) {
  1147  		createConfigs([]*config.Config{dnsSelector}, store, t)
  1148  		instances := []*model.ServiceInstance{}
  1149  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1150  		expectServiceInstances(t, sd, dnsSelector, 0, instances)
  1151  		expectEvents(t, events,
  1152  			Event{Type: "service", ID: "dns.selector.com", Namespace: dnsSelector.Namespace},
  1153  			Event{Type: "eds cache", ID: "dns.selector.com", Namespace: dnsSelector.Namespace},
  1154  			Event{Type: "xds full", ID: "dns.selector.com"})
  1155  	})
  1156  
  1157  	t.Run("add workload instance", func(t *testing.T) {
  1158  		// Add a workload instance, we expect this to update
  1159  		callInstanceHandlers([]*model.WorkloadInstance{fi1}, sd, model.EventAdd, t)
  1160  		instances := []*model.ServiceInstance{
  1161  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
  1162  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1163  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
  1164  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1165  		}
  1166  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1167  		expectServiceInstances(t, sd, selector, 0, instances)
  1168  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2})
  1169  	})
  1170  
  1171  	t.Run("another workload instance", func(t *testing.T) {
  1172  		// Add a different instance
  1173  		callInstanceHandlers([]*model.WorkloadInstance{fi2}, sd, model.EventAdd, t)
  1174  		instances := []*model.ServiceInstance{
  1175  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
  1176  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1177  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
  1178  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1179  		}
  1180  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1181  		instances = append(instances,
  1182  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 444,
  1183  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1184  			makeInstanceWithServiceAccount(selector, "3.3.3.3", 445,
  1185  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"))
  1186  		expectServiceInstances(t, sd, selector, 0, instances)
  1187  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 4})
  1188  	})
  1189  
  1190  	t.Run("delete workload instance", func(t *testing.T) {
  1191  		// Delete the instances, it should be gone
  1192  		callInstanceHandlers([]*model.WorkloadInstance{fi2}, sd, model.EventDelete, t)
  1193  		instances := []*model.ServiceInstance{
  1194  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 444,
  1195  				selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1196  			makeInstanceWithServiceAccount(selector, "2.2.2.2", 445,
  1197  				selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1198  		}
  1199  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1200  		expectServiceInstances(t, sd, selector, 0, instances)
  1201  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 2})
  1202  
  1203  		key := instancesKey{namespace: selector.Namespace, hostname: "selector.com"}
  1204  		namespacedName := selector.NamespacedName()
  1205  		if len(sd.serviceInstances.ip2instance) != 1 {
  1206  			t.Fatalf("service instances store `ip2instance` memory leak, expect 1, got %d", len(sd.serviceInstances.ip2instance))
  1207  		}
  1208  		if len(sd.serviceInstances.instances[key]) != 1 {
  1209  			t.Fatalf("service instances store `instances` memory leak, expect 1, got %d", len(sd.serviceInstances.instances[key]))
  1210  		}
  1211  		if len(sd.serviceInstances.instancesBySE[namespacedName]) != 1 {
  1212  			t.Fatalf("service instances store `instancesBySE` memory leak, expect 1, got %d", len(sd.serviceInstances.instancesBySE[namespacedName]))
  1213  		}
  1214  
  1215  		// The following sections mimic this scenario:
  1216  		// f1 starts terminating, f3 picks up the IP, f3 delete event (pod
  1217  		// not ready yet) comes before f1
  1218  		//
  1219  		// Delete f3 event
  1220  		callInstanceHandlers([]*model.WorkloadInstance{fi3}, sd, model.EventDelete, t)
  1221  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1222  		expectServiceInstances(t, sd, selector, 0, instances)
  1223  
  1224  		// Delete f1 event
  1225  		callInstanceHandlers([]*model.WorkloadInstance{fi1}, sd, model.EventDelete, t)
  1226  		instances = []*model.ServiceInstance{}
  1227  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1228  		expectServiceInstances(t, sd, selector, 0, instances)
  1229  		expectEvents(t, events, Event{Type: "eds", ID: "selector.com", Namespace: selector.Namespace, EndpointCount: 0})
  1230  
  1231  		if len(sd.serviceInstances.ip2instance) != 0 {
  1232  			t.Fatalf("service instances store `ip2instance` memory leak, expect 0, got %d", len(sd.serviceInstances.ip2instance))
  1233  		}
  1234  		if len(sd.serviceInstances.instances[key]) != 0 {
  1235  			t.Fatalf("service instances store `instances` memory leak, expect 0, got %d", len(sd.serviceInstances.instances[key]))
  1236  		}
  1237  		if len(sd.serviceInstances.instancesBySE[namespacedName]) != 0 {
  1238  			t.Fatalf("service instances store `instancesBySE` memory leak, expect 0, got %d", len(sd.serviceInstances.instancesBySE[namespacedName]))
  1239  		}
  1240  
  1241  		// Add f3 event
  1242  		callInstanceHandlers([]*model.WorkloadInstance{fi3}, sd, model.EventAdd, t)
  1243  		instances = []*model.ServiceInstance{
  1244  			makeInstanceWithServiceAccount(dnsSelector, "2.2.2.2", 444,
  1245  				dnsSelector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "dns-wle"}, "default"),
  1246  			makeInstanceWithServiceAccount(dnsSelector, "2.2.2.2", 445,
  1247  				dnsSelector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "dns-wle"}, "default"),
  1248  		}
  1249  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1250  		expectServiceInstances(t, sd, dnsSelector, 0, instances)
  1251  		expectEvents(t, events, Event{Type: "eds", ID: "dns.selector.com", Namespace: dnsSelector.Namespace, EndpointCount: 2})
  1252  	})
  1253  }
  1254  
  1255  func TestServiceDiscoveryWorkloadInstanceChangeLabel(t *testing.T) {
  1256  	store, sd, events := initServiceDiscovery(t)
  1257  
  1258  	type expectedProxyInstances struct {
  1259  		instancesWithSA []*model.ServiceInstance
  1260  		address         string
  1261  	}
  1262  
  1263  	type testWorkloadInstance struct {
  1264  		name                   string
  1265  		namespace              string
  1266  		address                string
  1267  		labels                 map[string]string
  1268  		serviceAccount         string
  1269  		tlsmode                string
  1270  		expectedProxyInstances []expectedProxyInstances
  1271  	}
  1272  
  1273  	t.Run("service entry", func(t *testing.T) {
  1274  		// Add just the ServiceEntry with selector. We should see no instances
  1275  		createConfigs([]*config.Config{selector}, store, t)
  1276  		instances := []*model.ServiceInstance{}
  1277  		expectProxyInstances(t, sd, instances, "2.2.2.2")
  1278  		expectServiceInstances(t, sd, selector, 0, instances)
  1279  		expectEvents(t, events,
  1280  			Event{Type: "service", ID: "selector.com", Namespace: selector.Namespace},
  1281  			Event{Type: "eds cache", ID: "selector.com", Namespace: selector.Namespace},
  1282  			Event{Type: "xds full"})
  1283  	})
  1284  
  1285  	cases := []struct {
  1286  		name      string
  1287  		instances []testWorkloadInstance
  1288  	}{
  1289  		{
  1290  			name: "change label removing all",
  1291  			instances: []testWorkloadInstance{
  1292  				{
  1293  					name:           selector.Name,
  1294  					namespace:      selector.Namespace,
  1295  					address:        "2.2.2.2",
  1296  					labels:         map[string]string{"app": "wle"},
  1297  					serviceAccount: "default",
  1298  					tlsmode:        model.IstioMutualTLSModeLabel,
  1299  					expectedProxyInstances: []expectedProxyInstances{
  1300  						{
  1301  							instancesWithSA: []*model.ServiceInstance{
  1302  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1303  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1304  							},
  1305  							address: "2.2.2.2",
  1306  						},
  1307  					},
  1308  				},
  1309  				{
  1310  					name:           selector.Name,
  1311  					namespace:      selector.Namespace,
  1312  					address:        "2.2.2.2",
  1313  					labels:         map[string]string{"app": "wle2"},
  1314  					serviceAccount: "default",
  1315  					tlsmode:        model.IstioMutualTLSModeLabel,
  1316  					expectedProxyInstances: []expectedProxyInstances{
  1317  						{
  1318  							instancesWithSA: []*model.ServiceInstance{}, // The instance labels don't match the se anymore, so adding this wi removes 2 instances
  1319  							address:         "2.2.2.2",
  1320  						},
  1321  					},
  1322  				},
  1323  			},
  1324  		},
  1325  		{
  1326  			name: "change label removing all",
  1327  			instances: []testWorkloadInstance{
  1328  				{
  1329  					name:           selector.Name,
  1330  					namespace:      selector.Namespace,
  1331  					address:        "2.2.2.2",
  1332  					labels:         map[string]string{"app": "wle"},
  1333  					serviceAccount: "default",
  1334  					tlsmode:        model.IstioMutualTLSModeLabel,
  1335  					expectedProxyInstances: []expectedProxyInstances{
  1336  						{
  1337  							instancesWithSA: []*model.ServiceInstance{
  1338  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1339  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1340  							},
  1341  							address: "2.2.2.2",
  1342  						},
  1343  					},
  1344  				},
  1345  				{
  1346  					name:           "another-name",
  1347  					namespace:      selector.Namespace,
  1348  					address:        "3.3.3.3",
  1349  					labels:         map[string]string{"app": "wle"},
  1350  					serviceAccount: "default",
  1351  					tlsmode:        model.IstioMutualTLSModeLabel,
  1352  					expectedProxyInstances: []expectedProxyInstances{
  1353  						{
  1354  							instancesWithSA: []*model.ServiceInstance{
  1355  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1356  								makeInstanceWithServiceAccount(selector, "2.2.2.2", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1357  							},
  1358  							address: "2.2.2.2",
  1359  						},
  1360  						{
  1361  							instancesWithSA: []*model.ServiceInstance{
  1362  								makeInstanceWithServiceAccount(selector, "3.3.3.3", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1363  								makeInstanceWithServiceAccount(selector, "3.3.3.3", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1364  							},
  1365  							address: "3.3.3.3",
  1366  						},
  1367  					},
  1368  				},
  1369  				{
  1370  					name:           selector.Name,
  1371  					namespace:      selector.Namespace,
  1372  					address:        "2.2.2.2",
  1373  					labels:         map[string]string{"app": "wle2"},
  1374  					serviceAccount: "default",
  1375  					tlsmode:        model.IstioMutualTLSModeLabel,
  1376  					expectedProxyInstances: []expectedProxyInstances{
  1377  						{
  1378  							instancesWithSA: []*model.ServiceInstance{
  1379  								makeInstanceWithServiceAccount(selector, "3.3.3.3", 444, selector.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"app": "wle"}, "default"),
  1380  								makeInstanceWithServiceAccount(selector, "3.3.3.3", 445, selector.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"app": "wle"}, "default"),
  1381  							},
  1382  							address: "3.3.3.3",
  1383  						},
  1384  					},
  1385  				},
  1386  			},
  1387  		},
  1388  	}
  1389  
  1390  	for _, testCase := range cases {
  1391  		t.Run(testCase.name, func(t *testing.T) {
  1392  			for _, instance := range testCase.instances {
  1393  
  1394  				wi := &model.WorkloadInstance{
  1395  					Name:      instance.name,
  1396  					Namespace: instance.namespace,
  1397  					Endpoint: &model.IstioEndpoint{
  1398  						Address:        instance.address,
  1399  						Labels:         instance.labels,
  1400  						ServiceAccount: spiffe.MustGenSpiffeURI(selector.Name, instance.serviceAccount),
  1401  						TLSMode:        instance.tlsmode,
  1402  					},
  1403  				}
  1404  
  1405  				callInstanceHandlers([]*model.WorkloadInstance{wi}, sd, model.EventAdd, t)
  1406  
  1407  				totalInstances := []*model.ServiceInstance{}
  1408  				for _, expectedProxyInstance := range instance.expectedProxyInstances {
  1409  					expectProxyInstances(t, sd, expectedProxyInstance.instancesWithSA, expectedProxyInstance.address)
  1410  					totalInstances = append(totalInstances, expectedProxyInstance.instancesWithSA...)
  1411  				}
  1412  
  1413  				expectServiceInstances(t, sd, selector, 0, totalInstances)
  1414  				expectEvents(t, events,
  1415  					Event{Type: "eds", ID: selector.Spec.(*networking.ServiceEntry).Hosts[0], Namespace: selector.Namespace, EndpointCount: len(totalInstances)})
  1416  			}
  1417  		})
  1418  	}
  1419  }
  1420  
  1421  func expectProxyInstances(t testing.TB, sd *Controller, expected []*model.ServiceInstance, ip string) {
  1422  	t.Helper()
  1423  	expectProxyTargets(t, sd, slices.Map(expected, model.ServiceInstanceToTarget), ip)
  1424  }
  1425  
  1426  func expectProxyTargets(t testing.TB, sd *Controller, expected []model.ServiceTarget, ip string) {
  1427  	t.Helper()
  1428  	// The system is eventually consistent, so add some retries
  1429  	retry.UntilSuccessOrFail(t, func() error {
  1430  		instances := sd.GetProxyServiceTargets(&model.Proxy{IPAddresses: []string{ip}, Metadata: &model.NodeMetadata{}})
  1431  		sortServiceTargets(instances)
  1432  		sortServiceTargets(expected)
  1433  		if err := compare(t, instances, expected); err != nil {
  1434  			return err
  1435  		}
  1436  		return nil
  1437  	}, retry.Converge(2), retry.Timeout(time.Second*5))
  1438  }
  1439  
  1440  func expectEvents(t testing.TB, ch *xdsfake.Updater, events ...Event) {
  1441  	t.Helper()
  1442  	ch.StrictMatchOrFail(t, events...)
  1443  }
  1444  
  1445  func expectServiceInstances(t testing.TB, sd *Controller, cfg *config.Config, port int, expected ...[]*model.ServiceInstance) {
  1446  	t.Helper()
  1447  	svcs := convertServices(*cfg)
  1448  	if len(svcs) != len(expected) {
  1449  		t.Fatalf("got more services than expected: %v vs %v", len(svcs), len(expected))
  1450  	}
  1451  	expe := [][]*model.IstioEndpoint{}
  1452  	for _, o := range expected {
  1453  		res := []*model.IstioEndpoint{}
  1454  		for _, i := range o {
  1455  			res = append(res, i.Endpoint)
  1456  		}
  1457  		expe = append(expe, res)
  1458  	}
  1459  	// The system is eventually consistent, so add some retries
  1460  	retry.UntilSuccessOrFail(t, func() error {
  1461  		for i, svc := range svcs {
  1462  			endpoints := GetEndpointsForPort(svc, sd.XdsUpdater.(*xdsfake.Updater).Delegate.(*model.EndpointIndexUpdater).Index, port)
  1463  			if endpoints == nil {
  1464  				endpoints = []*model.IstioEndpoint{} // To simplify tests a bit
  1465  			}
  1466  			sortEndpoints(endpoints)
  1467  			sortEndpoints(expe[i])
  1468  			if err := compare(t, endpoints, expe[i]); err != nil {
  1469  				return fmt.Errorf("%d: %v", i, err)
  1470  			}
  1471  		}
  1472  		return nil
  1473  	}, retry.Converge(2), retry.Timeout(time.Second*1))
  1474  }
  1475  
  1476  func TestServiceDiscoveryGetProxyServiceTargets(t *testing.T) {
  1477  	store, sd, _ := initServiceDiscovery(t)
  1478  
  1479  	createConfigs([]*config.Config{httpStatic, tcpStatic}, store, t)
  1480  
  1481  	expectProxyInstances(t, sd, []*model.ServiceInstance{
  1482  		makeInstance(httpStatic, "2.2.2.2", 7080, httpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1483  		makeInstance(httpStatic, "2.2.2.2", 18080, httpStatic.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS),
  1484  		makeInstance(tcpStatic, "2.2.2.2", 444, tcpStatic.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1485  	}, "2.2.2.2")
  1486  }
  1487  
  1488  // Keeping this test for legacy - but it never happens in real life.
  1489  func TestServiceDiscoveryInstances(t *testing.T) {
  1490  	store, sd, _ := initServiceDiscovery(t)
  1491  
  1492  	createConfigs([]*config.Config{httpDNS, tcpStatic}, store, t)
  1493  
  1494  	expectServiceInstances(t, sd, httpDNS, 0, []*model.ServiceInstance{
  1495  		makeInstance(httpDNS, "us.google.com", 7080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1496  		makeInstance(httpDNS, "us.google.com", 18080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS),
  1497  		makeInstance(httpDNS, "uk.google.com", 1080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1498  		makeInstance(httpDNS, "uk.google.com", 8080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], nil, MTLS),
  1499  		makeInstance(httpDNS, "de.google.com", 80, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, MTLS),
  1500  		makeInstance(httpDNS, "de.google.com", 8080, httpDNS.Spec.(*networking.ServiceEntry).Ports[1], map[string]string{"foo": "bar"}, MTLS),
  1501  	})
  1502  }
  1503  
  1504  // Keeping this test for legacy - but it never happens in real life.
  1505  func TestServiceDiscoveryInstances1Port(t *testing.T) {
  1506  	store, sd, _ := initServiceDiscovery(t)
  1507  
  1508  	createConfigs([]*config.Config{httpDNS, tcpStatic}, store, t)
  1509  
  1510  	expectServiceInstances(t, sd, httpDNS, 80, []*model.ServiceInstance{
  1511  		makeInstance(httpDNS, "us.google.com", 7080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1512  		makeInstance(httpDNS, "uk.google.com", 1080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1513  		makeInstance(httpDNS, "de.google.com", 80, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, MTLS),
  1514  	})
  1515  }
  1516  
  1517  func TestNonServiceConfig(t *testing.T) {
  1518  	store, sd, _ := initServiceDiscovery(t)
  1519  
  1520  	// Create a non-service configuration element. This should not affect the service registry at all.
  1521  	cfg := config.Config{
  1522  		Meta: config.Meta{
  1523  			GroupVersionKind:  gvk.DestinationRule,
  1524  			Name:              "fakeDestinationRule",
  1525  			Namespace:         "default",
  1526  			Domain:            "cluster.local",
  1527  			CreationTimestamp: GlobalTime,
  1528  		},
  1529  		Spec: &networking.DestinationRule{
  1530  			Host: "fakehost",
  1531  		},
  1532  	}
  1533  	_, err := store.Create(cfg)
  1534  	if err != nil {
  1535  		t.Errorf("error occurred crearting ServiceEntry config: %v", err)
  1536  	}
  1537  
  1538  	// Now create some service entries and verify that it's added to the registry.
  1539  	createConfigs([]*config.Config{httpDNS, tcpStatic}, store, t)
  1540  	expectServiceInstances(t, sd, httpDNS, 80, []*model.ServiceInstance{
  1541  		makeInstance(httpDNS, "us.google.com", 7080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1542  		makeInstance(httpDNS, "uk.google.com", 1080, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], nil, MTLS),
  1543  		makeInstance(httpDNS, "de.google.com", 80, httpDNS.Spec.(*networking.ServiceEntry).Ports[0], map[string]string{"foo": "bar"}, MTLS),
  1544  	})
  1545  }
  1546  
  1547  // nolint: lll
  1548  func TestServicesDiff(t *testing.T) {
  1549  	updatedHTTPDNS := &config.Config{
  1550  		Meta: config.Meta{
  1551  			GroupVersionKind:  gvk.ServiceEntry,
  1552  			Name:              "httpDNS",
  1553  			Namespace:         "httpDNS",
  1554  			CreationTimestamp: GlobalTime,
  1555  			Labels:            map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
  1556  		},
  1557  		Spec: &networking.ServiceEntry{
  1558  			Hosts: []string{"*.google.com", "*.mail.com"},
  1559  			Ports: []*networking.ServicePort{
  1560  				{Number: 80, Name: "http-port", Protocol: "http"},
  1561  				{Number: 8080, Name: "http-alt-port", Protocol: "http"},
  1562  			},
  1563  			Endpoints: []*networking.WorkloadEntry{
  1564  				{
  1565  					Address: "us.google.com",
  1566  					Ports:   map[string]uint32{"http-port": 7080, "http-alt-port": 18080},
  1567  					Labels:  map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
  1568  				},
  1569  				{
  1570  					Address: "uk.google.com",
  1571  					Ports:   map[string]uint32{"http-port": 1080},
  1572  					Labels:  map[string]string{label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
  1573  				},
  1574  				{
  1575  					Address: "de.google.com",
  1576  					Labels:  map[string]string{"foo": "bar", label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
  1577  				},
  1578  			},
  1579  			Location:   networking.ServiceEntry_MESH_EXTERNAL,
  1580  			Resolution: networking.ServiceEntry_DNS,
  1581  		},
  1582  	}
  1583  
  1584  	updatedHTTPDNSPort := func() *config.Config {
  1585  		c := updatedHTTPDNS.DeepCopy()
  1586  		se := c.Spec.(*networking.ServiceEntry)
  1587  		var ports []*networking.ServicePort
  1588  		ports = append(ports, se.Ports...)
  1589  		ports = append(ports, &networking.ServicePort{Number: 9090, Name: "http-new-port", Protocol: "http"})
  1590  		se.Ports = ports
  1591  		return &c
  1592  	}()
  1593  
  1594  	updatedEndpoint := func() *config.Config {
  1595  		c := updatedHTTPDNS.DeepCopy()
  1596  		se := c.Spec.(*networking.ServiceEntry)
  1597  		var endpoints []*networking.WorkloadEntry
  1598  		endpoints = append(endpoints, se.Endpoints...)
  1599  		endpoints = append(endpoints, &networking.WorkloadEntry{
  1600  			Address: "in.google.com",
  1601  			Labels:  map[string]string{"foo": "bar", label.SecurityTlsMode.Name: model.IstioMutualTLSModeLabel},
  1602  		})
  1603  		se.Endpoints = endpoints
  1604  		return &c
  1605  	}()
  1606  
  1607  	stringsToHosts := func(hosts []string) []host.Name {
  1608  		ret := make([]host.Name, len(hosts))
  1609  		for i, hostname := range hosts {
  1610  			ret[i] = host.Name(hostname)
  1611  		}
  1612  		return ret
  1613  	}
  1614  
  1615  	cases := []struct {
  1616  		name    string
  1617  		current *config.Config
  1618  		new     *config.Config
  1619  
  1620  		added     []host.Name
  1621  		deleted   []host.Name
  1622  		updated   []host.Name
  1623  		unchanged []host.Name
  1624  	}{
  1625  		{
  1626  			name:      "same config",
  1627  			current:   updatedHTTPDNS,
  1628  			new:       updatedHTTPDNS,
  1629  			unchanged: stringsToHosts(updatedHTTPDNS.Spec.(*networking.ServiceEntry).Hosts),
  1630  		},
  1631  		{
  1632  			name:    "different resolution",
  1633  			current: updatedHTTPDNS,
  1634  			new: func() *config.Config {
  1635  				c := updatedHTTPDNS.DeepCopy()
  1636  				c.Spec.(*networking.ServiceEntry).Resolution = networking.ServiceEntry_NONE
  1637  				return &c
  1638  			}(),
  1639  			updated: stringsToHosts(updatedHTTPDNS.Spec.(*networking.ServiceEntry).Hosts),
  1640  		},
  1641  		{
  1642  			name:    "config modified with added/deleted host",
  1643  			current: updatedHTTPDNS,
  1644  			new: func() *config.Config {
  1645  				c := updatedHTTPDNS.DeepCopy()
  1646  				se := c.Spec.(*networking.ServiceEntry)
  1647  				se.Hosts = []string{"*.google.com", "host.com"}
  1648  				return &c
  1649  			}(),
  1650  			added:     []host.Name{"host.com"},
  1651  			deleted:   []host.Name{"*.mail.com"},
  1652  			unchanged: []host.Name{"*.google.com"},
  1653  		},
  1654  		{
  1655  			name:    "config modified with additional port",
  1656  			current: updatedHTTPDNS,
  1657  			new:     updatedHTTPDNSPort,
  1658  			updated: stringsToHosts(updatedHTTPDNS.Spec.(*networking.ServiceEntry).Hosts),
  1659  		},
  1660  		{
  1661  			name:      "same config with additional endpoint",
  1662  			current:   updatedHTTPDNS,
  1663  			new:       updatedEndpoint,
  1664  			unchanged: stringsToHosts(updatedHTTPDNS.Spec.(*networking.ServiceEntry).Hosts),
  1665  		},
  1666  	}
  1667  
  1668  	servicesHostnames := func(services []*model.Service) []host.Name {
  1669  		if len(services) == 0 {
  1670  			return nil
  1671  		}
  1672  		ret := make([]host.Name, len(services))
  1673  		for i, svc := range services {
  1674  			ret[i] = svc.Hostname
  1675  		}
  1676  		return ret
  1677  	}
  1678  
  1679  	for _, tt := range cases {
  1680  		t.Run(tt.name, func(t *testing.T) {
  1681  			as := convertServices(*tt.current)
  1682  			bs := convertServices(*tt.new)
  1683  			added, deleted, updated, unchanged := servicesDiff(as, bs)
  1684  			for i, item := range []struct {
  1685  				hostnames []host.Name
  1686  				services  []*model.Service
  1687  			}{
  1688  				{tt.added, added},
  1689  				{tt.deleted, deleted},
  1690  				{tt.updated, updated},
  1691  				{tt.unchanged, unchanged},
  1692  			} {
  1693  				if !reflect.DeepEqual(servicesHostnames(item.services), item.hostnames) {
  1694  					t.Errorf("ServicesChanged %d got %v, want %v", i, servicesHostnames(item.services), item.hostnames)
  1695  				}
  1696  			}
  1697  		})
  1698  	}
  1699  }
  1700  
  1701  func sortServices(services []*model.Service) {
  1702  	sort.Slice(services, func(i, j int) bool { return services[i].Hostname < services[j].Hostname })
  1703  	for _, service := range services {
  1704  		sortPorts(service.Ports)
  1705  	}
  1706  }
  1707  
  1708  func sortServiceTargets(instances []model.ServiceTarget) {
  1709  	sort.Slice(instances, func(i, j int) bool {
  1710  		if instances[i].Service.Hostname == instances[j].Service.Hostname {
  1711  			if instances[i].Port.TargetPort == instances[j].Port.TargetPort {
  1712  				return instances[i].Port.TargetPort < instances[j].Port.TargetPort
  1713  			}
  1714  		}
  1715  		return instances[i].Service.Hostname < instances[j].Service.Hostname
  1716  	})
  1717  }
  1718  
  1719  func sortServiceInstances(instances []*model.ServiceInstance) {
  1720  	labelsToSlice := func(labels labels.Instance) []string {
  1721  		out := make([]string, 0, len(labels))
  1722  		for k, v := range labels {
  1723  			out = append(out, fmt.Sprintf("%s=%s", k, v))
  1724  		}
  1725  		sort.Strings(out)
  1726  		return out
  1727  	}
  1728  
  1729  	sort.Slice(instances, func(i, j int) bool {
  1730  		if instances[i].Service.Hostname == instances[j].Service.Hostname {
  1731  			if instances[i].Endpoint.EndpointPort == instances[j].Endpoint.EndpointPort {
  1732  				if instances[i].Endpoint.Address == instances[j].Endpoint.Address {
  1733  					if len(instances[i].Endpoint.Labels) == len(instances[j].Endpoint.Labels) {
  1734  						iLabels := labelsToSlice(instances[i].Endpoint.Labels)
  1735  						jLabels := labelsToSlice(instances[j].Endpoint.Labels)
  1736  						for k := range iLabels {
  1737  							if iLabels[k] < jLabels[k] {
  1738  								return true
  1739  							}
  1740  						}
  1741  					}
  1742  					return len(instances[i].Endpoint.Labels) < len(instances[j].Endpoint.Labels)
  1743  				}
  1744  				return instances[i].Endpoint.Address < instances[j].Endpoint.Address
  1745  			}
  1746  			return instances[i].Endpoint.EndpointPort < instances[j].Endpoint.EndpointPort
  1747  		}
  1748  		return instances[i].Service.Hostname < instances[j].Service.Hostname
  1749  	})
  1750  }
  1751  
  1752  func sortEndpoints(endpoints []*model.IstioEndpoint) {
  1753  	labelsToSlice := func(labels labels.Instance) []string {
  1754  		out := make([]string, 0, len(labels))
  1755  		for k, v := range labels {
  1756  			out = append(out, fmt.Sprintf("%s=%s", k, v))
  1757  		}
  1758  		sort.Strings(out)
  1759  		return out
  1760  	}
  1761  
  1762  	sort.Slice(endpoints, func(i, j int) bool {
  1763  		if endpoints[i].EndpointPort == endpoints[j].EndpointPort {
  1764  			if endpoints[i].Address == endpoints[j].Address {
  1765  				if len(endpoints[i].Labels) == len(endpoints[j].Labels) {
  1766  					iLabels := labelsToSlice(endpoints[i].Labels)
  1767  					jLabels := labelsToSlice(endpoints[j].Labels)
  1768  					for k := range iLabels {
  1769  						if iLabels[k] < jLabels[k] {
  1770  							return true
  1771  						}
  1772  					}
  1773  				}
  1774  				return len(endpoints[i].Labels) < len(endpoints[j].Labels)
  1775  			}
  1776  			return endpoints[i].Address < endpoints[j].Address
  1777  		}
  1778  		return endpoints[i].EndpointPort < endpoints[j].EndpointPort
  1779  	})
  1780  }
  1781  
  1782  func sortPorts(ports []*model.Port) {
  1783  	sort.Slice(ports, func(i, j int) bool {
  1784  		if ports[i].Port == ports[j].Port {
  1785  			if ports[i].Name == ports[j].Name {
  1786  				return ports[i].Protocol < ports[j].Protocol
  1787  			}
  1788  			return ports[i].Name < ports[j].Name
  1789  		}
  1790  		return ports[i].Port < ports[j].Port
  1791  	})
  1792  }
  1793  
  1794  func Test_autoAllocateIP_conditions(t *testing.T) {
  1795  	tests := []struct {
  1796  		name         string
  1797  		inServices   []*model.Service
  1798  		wantServices []*model.Service
  1799  	}{
  1800  		{
  1801  			name: "no allocation for passthrough",
  1802  			inServices: []*model.Service{
  1803  				{
  1804  					Hostname:       "foo.com",
  1805  					Resolution:     model.Passthrough,
  1806  					DefaultAddress: "0.0.0.0",
  1807  				},
  1808  			},
  1809  			wantServices: []*model.Service{
  1810  				{
  1811  					Hostname:       "foo.com",
  1812  					Resolution:     model.Passthrough,
  1813  					DefaultAddress: "0.0.0.0",
  1814  				},
  1815  			},
  1816  		},
  1817  		{
  1818  			name: "no allocation if address exists",
  1819  			inServices: []*model.Service{
  1820  				{
  1821  					Hostname:       "foo.com",
  1822  					Resolution:     model.ClientSideLB,
  1823  					DefaultAddress: "1.1.1.1",
  1824  				},
  1825  			},
  1826  			wantServices: []*model.Service{
  1827  				{
  1828  					Hostname:       "foo.com",
  1829  					Resolution:     model.ClientSideLB,
  1830  					DefaultAddress: "1.1.1.1",
  1831  				},
  1832  			},
  1833  		},
  1834  		{
  1835  			name: "no allocation if hostname is wildcard",
  1836  			inServices: []*model.Service{
  1837  				{
  1838  					Hostname:       "*.foo.com",
  1839  					Resolution:     model.ClientSideLB,
  1840  					DefaultAddress: "1.1.1.1",
  1841  				},
  1842  			},
  1843  			wantServices: []*model.Service{
  1844  				{
  1845  					Hostname:       "*.foo.com",
  1846  					Resolution:     model.ClientSideLB,
  1847  					DefaultAddress: "1.1.1.1",
  1848  				},
  1849  			},
  1850  		},
  1851  		{
  1852  			name: "allocate IP for clientside lb",
  1853  			inServices: []*model.Service{
  1854  				{
  1855  					Hostname:       "foo.com",
  1856  					Resolution:     model.ClientSideLB,
  1857  					DefaultAddress: "0.0.0.0",
  1858  				},
  1859  			},
  1860  			wantServices: []*model.Service{
  1861  				{
  1862  					Hostname:                 "foo.com",
  1863  					Resolution:               model.ClientSideLB,
  1864  					DefaultAddress:           "0.0.0.0",
  1865  					AutoAllocatedIPv4Address: "240.240.227.81",
  1866  					AutoAllocatedIPv6Address: "2001:2::f0f0:e351",
  1867  				},
  1868  			},
  1869  		},
  1870  		{
  1871  			name: "allocate IP for dns lb",
  1872  			inServices: []*model.Service{
  1873  				{
  1874  					Hostname:       "foo.com",
  1875  					Resolution:     model.DNSLB,
  1876  					DefaultAddress: "0.0.0.0",
  1877  				},
  1878  			},
  1879  			wantServices: []*model.Service{
  1880  				{
  1881  					Hostname:                 "foo.com",
  1882  					Resolution:               model.DNSLB,
  1883  					DefaultAddress:           "0.0.0.0",
  1884  					AutoAllocatedIPv4Address: "240.240.227.81",
  1885  					AutoAllocatedIPv6Address: "2001:2::f0f0:e351",
  1886  				},
  1887  			},
  1888  		},
  1889  		{
  1890  			name: "collision",
  1891  			inServices: []*model.Service{
  1892  				{
  1893  					Hostname:       "a17061.example.com",
  1894  					Resolution:     model.DNSLB,
  1895  					DefaultAddress: "0.0.0.0",
  1896  				},
  1897  				{
  1898  					// hashes to the same value as the hostname above,
  1899  					// a new collision needs to be found if the hash algorithm changes
  1900  					Hostname:       "a44155.example.com",
  1901  					Resolution:     model.DNSLB,
  1902  					DefaultAddress: "0.0.0.0",
  1903  				},
  1904  			},
  1905  			wantServices: []*model.Service{
  1906  				{
  1907  					Hostname:                 "a17061.example.com",
  1908  					Resolution:               model.DNSLB,
  1909  					DefaultAddress:           "0.0.0.0",
  1910  					AutoAllocatedIPv4Address: "240.240.25.11",
  1911  					AutoAllocatedIPv6Address: "2001:2::f0f0:19b",
  1912  				},
  1913  				{
  1914  					Hostname:                 "a44155.example.com",
  1915  					Resolution:               model.DNSLB,
  1916  					DefaultAddress:           "0.0.0.0",
  1917  					AutoAllocatedIPv4Address: "240.240.31.17",
  1918  					AutoAllocatedIPv6Address: "2001:2::f0f0:1f11",
  1919  				},
  1920  			},
  1921  		},
  1922  		{
  1923  			name: "stable IP - baseline test",
  1924  			inServices: []*model.Service{
  1925  				{
  1926  					Hostname:       "a.example.com",
  1927  					Resolution:     model.DNSLB,
  1928  					DefaultAddress: "0.0.0.0",
  1929  					Attributes:     model.ServiceAttributes{Namespace: "a"},
  1930  				},
  1931  			},
  1932  			wantServices: []*model.Service{
  1933  				{
  1934  					Hostname:                 "a.example.com",
  1935  					Resolution:               model.DNSLB,
  1936  					DefaultAddress:           "0.0.0.0",
  1937  					AutoAllocatedIPv4Address: "240.240.134.206",
  1938  					AutoAllocatedIPv6Address: "2001:2::f0f0:86ce",
  1939  				},
  1940  			},
  1941  		},
  1942  		{
  1943  			name: "stable IP - not affected by other namespace",
  1944  			inServices: []*model.Service{
  1945  				{
  1946  					Hostname:       "a.example.com",
  1947  					Resolution:     model.DNSLB,
  1948  					DefaultAddress: "0.0.0.0",
  1949  					Attributes:     model.ServiceAttributes{Namespace: "a"},
  1950  				},
  1951  				{
  1952  					Hostname:       "a.example.com",
  1953  					Resolution:     model.DNSLB,
  1954  					DefaultAddress: "0.0.0.0",
  1955  					Attributes:     model.ServiceAttributes{Namespace: "b"},
  1956  				},
  1957  			},
  1958  			wantServices: []*model.Service{
  1959  				{
  1960  					Hostname:                 "a.example.com",
  1961  					Resolution:               model.DNSLB,
  1962  					DefaultAddress:           "0.0.0.0",
  1963  					AutoAllocatedIPv4Address: "240.240.134.206",
  1964  					AutoAllocatedIPv6Address: "2001:2::f0f0:86ce",
  1965  				},
  1966  				{
  1967  					Hostname:                 "a.example.com",
  1968  					Resolution:               model.DNSLB,
  1969  					DefaultAddress:           "0.0.0.0",
  1970  					AutoAllocatedIPv4Address: "240.240.41.100",
  1971  					AutoAllocatedIPv6Address: "2001:2::f0f0:2964",
  1972  				},
  1973  			},
  1974  		},
  1975  	}
  1976  	for _, tt := range tests {
  1977  		t.Run(tt.name, func(t *testing.T) {
  1978  			gotServices := autoAllocateIPs(tt.inServices)
  1979  			for i, got := range gotServices {
  1980  				if got.AutoAllocatedIPv4Address != tt.wantServices[i].AutoAllocatedIPv4Address {
  1981  					t.Errorf("autoAllocateIPs() AutoAllocatedIPv4Address = %v, want %v",
  1982  						got.AutoAllocatedIPv4Address, tt.wantServices[i].AutoAllocatedIPv4Address)
  1983  				}
  1984  				if got.AutoAllocatedIPv6Address != tt.wantServices[i].AutoAllocatedIPv6Address {
  1985  					t.Errorf("autoAllocateIPs() AutoAllocatedIPv6Address = %v, want %v",
  1986  						got.AutoAllocatedIPv6Address, tt.wantServices[i].AutoAllocatedIPv6Address)
  1987  				}
  1988  			}
  1989  		})
  1990  	}
  1991  }
  1992  
  1993  func Test_autoAllocateIP_values(t *testing.T) {
  1994  	ips := maxIPs
  1995  	inServices := make([]*model.Service, ips)
  1996  	for i := 0; i < ips; i++ {
  1997  		temp := model.Service{
  1998  			Hostname:       host.Name(fmt.Sprintf("foo%d.com", i)),
  1999  			Resolution:     model.ClientSideLB,
  2000  			DefaultAddress: constants.UnspecifiedIP,
  2001  		}
  2002  		inServices[i] = &temp
  2003  	}
  2004  	gotServices := autoAllocateIPs(inServices)
  2005  
  2006  	// We dont expect the following pattern of IPs.
  2007  	// 240.240.0.0
  2008  	// 240.240.0.255
  2009  	// 240.240.1.0
  2010  	// 240.240.1.255
  2011  	// 240.240.2.0
  2012  	// 240.240.2.255
  2013  	// 240.240.3.0
  2014  	// 240.240.3.255
  2015  	// The last IP should be 240.240.202.167
  2016  	doNotWant := map[string]bool{
  2017  		"240.240.0.0":   true,
  2018  		"240.240.0.255": true,
  2019  		"240.240.1.0":   true,
  2020  		"240.240.1.255": true,
  2021  		"240.240.2.0":   true,
  2022  		"240.240.2.255": true,
  2023  		"240.240.3.0":   true,
  2024  		"240.240.3.255": true,
  2025  	}
  2026  	expectedLastIP := "240.240.10.222"
  2027  	if gotServices[len(gotServices)-1].AutoAllocatedIPv4Address != expectedLastIP {
  2028  		t.Errorf("expected last IP address to be %s, got %s", expectedLastIP, gotServices[len(gotServices)-1].AutoAllocatedIPv4Address)
  2029  	}
  2030  
  2031  	gotIPMap := make(map[string]string)
  2032  	for _, svc := range gotServices {
  2033  		if svc.AutoAllocatedIPv4Address == "" || doNotWant[svc.AutoAllocatedIPv4Address] {
  2034  			t.Errorf("unexpected value for auto allocated IP address %s for service %s", svc.AutoAllocatedIPv4Address, svc.Hostname.String())
  2035  		}
  2036  		if v, ok := gotIPMap[svc.AutoAllocatedIPv4Address]; ok && v != svc.Hostname.String() {
  2037  			t.Errorf("multiple allocations of same IP address to different services with different hostname: %s", svc.AutoAllocatedIPv4Address)
  2038  		}
  2039  		gotIPMap[svc.AutoAllocatedIPv4Address] = svc.Hostname.String()
  2040  		// Validate that IP address is valid.
  2041  		ip := net.ParseIP(svc.AutoAllocatedIPv4Address)
  2042  		if ip == nil {
  2043  			t.Errorf("invalid IP address %s : %s", svc.AutoAllocatedIPv4Address, svc.Hostname.String())
  2044  		}
  2045  		// Validate that IP address is in the expected range.
  2046  		_, subnet, _ := net.ParseCIDR("240.240.0.0/16")
  2047  		if !subnet.Contains(ip) {
  2048  			t.Errorf("IP address not in range %s : %s", svc.AutoAllocatedIPv4Address, svc.Hostname.String())
  2049  		}
  2050  	}
  2051  	assert.Equal(t, maxIPs, len(gotIPMap))
  2052  }
  2053  
  2054  func BenchmarkAutoAllocateIPs(t *testing.B) {
  2055  	inServices := make([]*model.Service, 255*255)
  2056  	for i := 0; i < 255*255; i++ {
  2057  		temp := model.Service{
  2058  			Hostname:       host.Name(fmt.Sprintf("foo%d.com", i)),
  2059  			Resolution:     model.ClientSideLB,
  2060  			DefaultAddress: constants.UnspecifiedIP,
  2061  		}
  2062  		inServices[i] = &temp
  2063  	}
  2064  	t.ResetTimer()
  2065  	for i := 0; i < t.N; i++ {
  2066  		autoAllocateIPs(inServices)
  2067  	}
  2068  }
  2069  
  2070  // Validate that ipaddress allocation is deterministic based on hash.
  2071  func Test_autoAllocateIP_deterministic(t *testing.T) {
  2072  	inServices := make([]*model.Service, 0)
  2073  	originalServices := map[string]string{
  2074  		"a.com": "240.240.109.8",
  2075  		"c.com": "240.240.234.51",
  2076  		"e.com": "240.240.85.60",
  2077  		"g.com": "240.240.23.172",
  2078  		"i.com": "240.240.15.2",
  2079  		"k.com": "240.240.160.161",
  2080  		"l.com": "240.240.42.96",
  2081  		"n.com": "240.240.121.61",
  2082  		"o.com": "240.240.122.71",
  2083  	}
  2084  
  2085  	allocateAndValidate := func() {
  2086  		gotServices := autoAllocateIPs(model.SortServicesByCreationTime(inServices))
  2087  		gotIPMap := make(map[string]string)
  2088  		serviceIPMap := make(map[string]string)
  2089  		for _, svc := range gotServices {
  2090  			if v, ok := gotIPMap[svc.AutoAllocatedIPv4Address]; ok && v != svc.Hostname.String() {
  2091  				t.Errorf("multiple allocations of same IP address to different services with different hostname: %s", svc.AutoAllocatedIPv4Address)
  2092  			}
  2093  			gotIPMap[svc.AutoAllocatedIPv4Address] = svc.Hostname.String()
  2094  			serviceIPMap[svc.Hostname.String()] = svc.AutoAllocatedIPv4Address
  2095  		}
  2096  		for k, v := range originalServices {
  2097  			if gotIPMap[v] != k {
  2098  				t.Errorf("ipaddress changed for service %s. expected: %s, got: %s", k, v, serviceIPMap[k])
  2099  			}
  2100  		}
  2101  		for k, v := range gotIPMap {
  2102  			if net.ParseIP(k) == nil {
  2103  				t.Errorf("invalid ipaddress for service %s. got: %s", v, k)
  2104  			}
  2105  		}
  2106  	}
  2107  
  2108  	// Validate that IP addresses are allocated for original list of services.
  2109  	for k := range originalServices {
  2110  		inServices = append(inServices, &model.Service{
  2111  			Hostname:       host.Name(k),
  2112  			Resolution:     model.ClientSideLB,
  2113  			DefaultAddress: constants.UnspecifiedIP,
  2114  		})
  2115  	}
  2116  	allocateAndValidate()
  2117  
  2118  	// Now add few services in between and validate that IPs are retained for original services.
  2119  	addServices := map[string]bool{
  2120  		"b.com": true,
  2121  		"d.com": true,
  2122  		"f.com": true,
  2123  		"h.com": true,
  2124  		"j.com": true,
  2125  		"m.com": true,
  2126  		"p.com": true,
  2127  		"q.com": true,
  2128  		"r.com": true,
  2129  	}
  2130  
  2131  	for k := range addServices {
  2132  		inServices = append(inServices, &model.Service{
  2133  			Hostname:       host.Name(k),
  2134  			Resolution:     model.ClientSideLB,
  2135  			DefaultAddress: constants.UnspecifiedIP,
  2136  		})
  2137  	}
  2138  	allocateAndValidate()
  2139  
  2140  	// Now delete few services and validate that IPs are retained for original services.
  2141  	deleteServices := []*model.Service{}
  2142  	for i, svc := range inServices {
  2143  		if _, exists := originalServices[svc.Hostname.String()]; !exists {
  2144  			if i%2 == 0 {
  2145  				continue
  2146  			}
  2147  		}
  2148  		deleteServices = append(deleteServices, svc)
  2149  	}
  2150  	inServices = deleteServices
  2151  	allocateAndValidate()
  2152  }
  2153  
  2154  func Test_autoAllocateIP_with_duplicated_host(t *testing.T) {
  2155  	inServices := make([]*model.Service, 0)
  2156  	originalServices := map[string]string{
  2157  		"a.com": "240.240.109.8",
  2158  		"c.com": "240.240.234.51",
  2159  		"e.com": "240.240.85.60",
  2160  		"g.com": "240.240.23.172",
  2161  		"i.com": "240.240.15.2",
  2162  		"k.com": "240.240.160.161",
  2163  		"l.com": "240.240.42.96",
  2164  		"n.com": "240.240.121.61",
  2165  		"o.com": "240.240.122.71",
  2166  	}
  2167  
  2168  	allocateAndValidate := func() {
  2169  		gotServices := autoAllocateIPs(model.SortServicesByCreationTime(inServices))
  2170  		gotIPMap := make(map[string]string)
  2171  		serviceIPMap := make(map[string]string)
  2172  		for _, svc := range gotServices {
  2173  			if v, ok := gotIPMap[svc.AutoAllocatedIPv4Address]; ok && v != svc.Hostname.String() {
  2174  				t.Errorf("multiple allocations of same IP address to different services with different hostname: %s", svc.AutoAllocatedIPv4Address)
  2175  			}
  2176  			gotIPMap[svc.AutoAllocatedIPv4Address] = svc.Hostname.String()
  2177  			serviceIPMap[svc.Hostname.String()] = svc.AutoAllocatedIPv4Address
  2178  		}
  2179  		for k, v := range originalServices {
  2180  			if gotIPMap[v] != k {
  2181  				t.Errorf("ipaddress changed for service %s. expected: %s, got: %s", k, v, serviceIPMap[k])
  2182  			}
  2183  		}
  2184  		for k, v := range gotIPMap {
  2185  			if net.ParseIP(k) == nil {
  2186  				t.Errorf("invalid ipaddress for service %s. got: %s", v, k)
  2187  			}
  2188  		}
  2189  	}
  2190  
  2191  	// Validate that IP addresses are allocated for original list of services.
  2192  	for k := range originalServices {
  2193  		inServices = append(inServices, &model.Service{
  2194  			Hostname:       host.Name(k),
  2195  			Resolution:     model.ClientSideLB,
  2196  			DefaultAddress: constants.UnspecifiedIP,
  2197  		})
  2198  	}
  2199  	allocateAndValidate()
  2200  
  2201  	// Now add service with duplicated hostname validate that IPs are retained for original services and duplicated reuse the same IP
  2202  	addServices := map[string]bool{
  2203  		"i.com": true,
  2204  	}
  2205  
  2206  	for k := range addServices {
  2207  		inServices = append(inServices, &model.Service{
  2208  			Hostname:       host.Name(k),
  2209  			Resolution:     model.ClientSideLB,
  2210  			DefaultAddress: constants.UnspecifiedIP,
  2211  		})
  2212  	}
  2213  	allocateAndValidate()
  2214  }
  2215  
  2216  func TestWorkloadEntryOnlyMode(t *testing.T) {
  2217  	store, registry, _ := initServiceDiscoveryWithOpts(t, true)
  2218  	createConfigs([]*config.Config{httpStatic}, store, t)
  2219  	svcs := registry.Services()
  2220  	if len(svcs) > 0 {
  2221  		t.Fatalf("expected 0 services, got %d", len(svcs))
  2222  	}
  2223  	svc := registry.GetService("*.google.com")
  2224  	if svc != nil {
  2225  		t.Fatalf("expected nil, got %v", svc)
  2226  	}
  2227  }
  2228  
  2229  func BenchmarkServiceEntryHandler(b *testing.B) {
  2230  	_, sd := initServiceDiscoveryWithoutEvents(b)
  2231  	stopCh := make(chan struct{})
  2232  	go sd.Run(stopCh)
  2233  	defer close(stopCh)
  2234  	for i := 0; i < b.N; i++ {
  2235  		sd.serviceEntryHandler(config.Config{}, *httpDNS, model.EventAdd)
  2236  		sd.serviceEntryHandler(config.Config{}, *httpDNSRR, model.EventAdd)
  2237  		sd.serviceEntryHandler(config.Config{}, *tcpDNS, model.EventAdd)
  2238  		sd.serviceEntryHandler(config.Config{}, *tcpStatic, model.EventAdd)
  2239  
  2240  		sd.serviceEntryHandler(config.Config{}, *httpDNS, model.EventDelete)
  2241  		sd.serviceEntryHandler(config.Config{}, *httpDNSRR, model.EventDelete)
  2242  		sd.serviceEntryHandler(config.Config{}, *tcpDNS, model.EventDelete)
  2243  		sd.serviceEntryHandler(config.Config{}, *tcpStatic, model.EventDelete)
  2244  	}
  2245  }
  2246  
  2247  func BenchmarkWorkloadInstanceHandler(b *testing.B) {
  2248  	store, sd := initServiceDiscoveryWithoutEvents(b)
  2249  	stopCh := make(chan struct{})
  2250  	go sd.Run(stopCh)
  2251  	defer close(stopCh)
  2252  	// Add just the ServiceEntry with selector. We should see no instances
  2253  	createConfigs([]*config.Config{selector, dnsSelector}, store, b)
  2254  
  2255  	// Setup a couple of workload instances for test. These will be selected by the `selector` SE
  2256  	fi1 := &model.WorkloadInstance{
  2257  		Name:      selector.Name,
  2258  		Namespace: selector.Namespace,
  2259  		Endpoint: &model.IstioEndpoint{
  2260  			Address:        "2.2.2.2",
  2261  			Labels:         map[string]string{"app": "wle"},
  2262  			ServiceAccount: spiffe.MustGenSpiffeURI(selector.Name, "default"),
  2263  			TLSMode:        model.IstioMutualTLSModeLabel,
  2264  		},
  2265  	}
  2266  
  2267  	fi2 := &model.WorkloadInstance{
  2268  		Name:      "some-other-name",
  2269  		Namespace: selector.Namespace,
  2270  		Endpoint: &model.IstioEndpoint{
  2271  			Address:        "3.3.3.3",
  2272  			Labels:         map[string]string{"app": "wle"},
  2273  			ServiceAccount: spiffe.MustGenSpiffeURI(selector.Name, "default"),
  2274  			TLSMode:        model.IstioMutualTLSModeLabel,
  2275  		},
  2276  	}
  2277  
  2278  	fi3 := &model.WorkloadInstance{
  2279  		Name:      "another-name",
  2280  		Namespace: dnsSelector.Namespace,
  2281  		Endpoint: &model.IstioEndpoint{
  2282  			Address:        "2.2.2.2",
  2283  			Labels:         map[string]string{"app": "dns-wle"},
  2284  			ServiceAccount: spiffe.MustGenSpiffeURI(dnsSelector.Name, "default"),
  2285  			TLSMode:        model.IstioMutualTLSModeLabel,
  2286  		},
  2287  	}
  2288  	for i := 0; i < b.N; i++ {
  2289  		sd.WorkloadInstanceHandler(fi1, model.EventAdd)
  2290  		sd.WorkloadInstanceHandler(fi2, model.EventAdd)
  2291  		sd.WorkloadInstanceHandler(fi3, model.EventDelete)
  2292  
  2293  		sd.WorkloadInstanceHandler(fi2, model.EventDelete)
  2294  		sd.WorkloadInstanceHandler(fi1, model.EventDelete)
  2295  		sd.WorkloadInstanceHandler(fi3, model.EventDelete)
  2296  	}
  2297  }
  2298  
  2299  func BenchmarkWorkloadEntryHandler(b *testing.B) {
  2300  	// Setup a couple workload entries for test. These will be selected by the `selector` SE
  2301  	wle := createWorkloadEntry("wl", selector.Name,
  2302  		&networking.WorkloadEntry{
  2303  			Address:        "2.2.2.2",
  2304  			Labels:         map[string]string{"app": "wle"},
  2305  			ServiceAccount: "default",
  2306  		})
  2307  	wle2 := createWorkloadEntry("wl2", selector.Name,
  2308  		&networking.WorkloadEntry{
  2309  			Address:        "3.3.3.3",
  2310  			Labels:         map[string]string{"app": "wle"},
  2311  			ServiceAccount: "default",
  2312  		})
  2313  	dnsWle := createWorkloadEntry("dnswl", dnsSelector.Namespace,
  2314  		&networking.WorkloadEntry{
  2315  			Address:        "4.4.4.4",
  2316  			Labels:         map[string]string{"app": "dns-wle"},
  2317  			ServiceAccount: "default",
  2318  		})
  2319  
  2320  	store, sd := initServiceDiscoveryWithoutEvents(b)
  2321  	stopCh := make(chan struct{})
  2322  	go sd.Run(stopCh)
  2323  	defer close(stopCh)
  2324  	// Add just the ServiceEntry with selector. We should see no instances
  2325  	createConfigs([]*config.Config{selector}, store, b)
  2326  
  2327  	for i := 0; i < b.N; i++ {
  2328  		sd.workloadEntryHandler(config.Config{}, *wle, model.EventAdd)
  2329  		sd.workloadEntryHandler(config.Config{}, *dnsWle, model.EventAdd)
  2330  		sd.workloadEntryHandler(config.Config{}, *wle2, model.EventAdd)
  2331  
  2332  		sd.workloadEntryHandler(config.Config{}, *wle, model.EventDelete)
  2333  		sd.workloadEntryHandler(config.Config{}, *dnsWle, model.EventDelete)
  2334  		sd.workloadEntryHandler(config.Config{}, *wle2, model.EventDelete)
  2335  	}
  2336  }
  2337  
  2338  func GetEndpoints(s *model.Service, endpoints *model.EndpointIndex) []*model.IstioEndpoint {
  2339  	return GetEndpointsForPort(s, endpoints, 0)
  2340  }
  2341  
  2342  func GetEndpointsForPort(s *model.Service, endpoints *model.EndpointIndex, port int) []*model.IstioEndpoint {
  2343  	shards, ok := endpoints.ShardsForService(string(s.Hostname), s.Attributes.Namespace)
  2344  	if !ok {
  2345  		return nil
  2346  	}
  2347  	var pn string
  2348  	for _, p := range s.Ports {
  2349  		if p.Port == port {
  2350  			pn = p.Name
  2351  			break
  2352  		}
  2353  	}
  2354  	if pn == "" && port != 0 {
  2355  		return nil
  2356  	}
  2357  	shards.RLock()
  2358  	defer shards.RUnlock()
  2359  	return slices.FilterInPlace(slices.Flatten(maps.Values(shards.Shards)), func(endpoint *model.IstioEndpoint) bool {
  2360  		return pn == "" || endpoint.ServicePortName == pn
  2361  	})
  2362  }