istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/route/route_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 route_test
    16  
    17  import (
    18  	"log"
    19  	"reflect"
    20  	"testing"
    21  
    22  	envoycore "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    23  	envoyroute "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
    24  	matcher "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
    25  	. "github.com/onsi/gomega"
    26  	"google.golang.org/protobuf/types/known/durationpb"
    27  	"k8s.io/apimachinery/pkg/types"
    28  
    29  	networking "istio.io/api/networking/v1alpha3"
    30  	"istio.io/istio/pilot/pkg/model"
    31  	"istio.io/istio/pilot/pkg/networking/core"
    32  	"istio.io/istio/pilot/pkg/networking/core/route"
    33  	"istio.io/istio/pilot/pkg/networking/util"
    34  	"istio.io/istio/pilot/pkg/xds/filters"
    35  	"istio.io/istio/pilot/test/xdstest"
    36  	"istio.io/istio/pkg/config"
    37  	"istio.io/istio/pkg/config/constants"
    38  	"istio.io/istio/pkg/config/host"
    39  	"istio.io/istio/pkg/config/protocol"
    40  	"istio.io/istio/pkg/config/schema/gvk"
    41  	"istio.io/istio/pkg/util/sets"
    42  )
    43  
    44  func TestBuildHTTPRoutes(t *testing.T) {
    45  	serviceRegistry := map[host.Name]*model.Service{
    46  		"*.example.org": {
    47  			Hostname:       "*.example.org",
    48  			DefaultAddress: "1.1.1.1",
    49  			Ports: model.PortList{
    50  				&model.Port{
    51  					Name:     "default",
    52  					Port:     8080,
    53  					Protocol: protocol.HTTP,
    54  				},
    55  			},
    56  		},
    57  	}
    58  
    59  	node := func(cg *core.ConfigGenTest) *model.Proxy {
    60  		return cg.SetupProxy(&model.Proxy{
    61  			Type:        model.SidecarProxy,
    62  			IPAddresses: []string{"1.1.1.1"},
    63  			ID:          "someID",
    64  			DNSDomain:   "foo.com",
    65  			IstioVersion: &model.IstioVersion{
    66  				Major: 1,
    67  				Minor: 20,
    68  			},
    69  		})
    70  	}
    71  
    72  	nodeWithExtended := func(cg *core.ConfigGenTest) *model.Proxy {
    73  		out := node(cg)
    74  		out.IstioVersion.Minor = 21
    75  		return out
    76  	}
    77  
    78  	gatewayNames := sets.New("some-gateway")
    79  
    80  	t.Run("for virtual service", func(t *testing.T) {
    81  		g := NewWithT(t)
    82  		cg := core.NewConfigGenTest(t, core.TestOptions{})
    83  
    84  		t.Setenv("ISTIO_DEFAULT_REQUEST_TIMEOUT", "0ms")
    85  
    86  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServicePlain, serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
    87  		xdstest.ValidateRoutes(t, routes)
    88  
    89  		g.Expect(err).NotTo(HaveOccurred())
    90  		g.Expect(len(routes)).To(Equal(1))
    91  		// Validate that when timeout is not specified, we disable it based on default value of flag.
    92  		g.Expect(routes[0].GetRoute().Timeout.Seconds).To(Equal(int64(0)))
    93  		// nolint: staticcheck
    94  		g.Expect(routes[0].GetRoute().MaxGrpcTimeout.Seconds).To(Equal(int64(0)))
    95  	})
    96  
    97  	t.Run("for virtual service with HTTP/3 discovery enabled", func(t *testing.T) {
    98  		g := NewWithT(t)
    99  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   100  
   101  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServicePlain, serviceRegistry,
   102  			nil, 8080, gatewayNames, route.RouteOptions{IsHTTP3AltSvcHeaderNeeded: true})
   103  		xdstest.ValidateRoutes(t, routes)
   104  		g.Expect(err).NotTo(HaveOccurred())
   105  		g.Expect(routes[0].GetResponseHeadersToAdd()).To(Equal([]*envoycore.HeaderValueOption{
   106  			{
   107  				Header: &envoycore.HeaderValue{
   108  					Key:   util.AltSvcHeader,
   109  					Value: `h3=":8080"; ma=86400`,
   110  				},
   111  				AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   112  			},
   113  		}))
   114  	})
   115  
   116  	t.Run("for virtual service with timeout", func(t *testing.T) {
   117  		g := NewWithT(t)
   118  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   119  
   120  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithTimeout, serviceRegistry,
   121  			nil, 8080, gatewayNames, route.RouteOptions{})
   122  		xdstest.ValidateRoutes(t, routes)
   123  
   124  		g.Expect(err).NotTo(HaveOccurred())
   125  		g.Expect(len(routes)).To(Equal(1))
   126  		// Validate that when timeout specified, we send the configured timeout to Envoys.
   127  		g.Expect(routes[0].GetRoute().Timeout.Seconds).To(Equal(int64(10)))
   128  		// nolint: staticcheck
   129  		g.Expect(routes[0].GetRoute().MaxGrpcTimeout.Seconds).To(Equal(int64(10)))
   130  	})
   131  
   132  	t.Run("for virtual service with disabled timeout", func(t *testing.T) {
   133  		g := NewWithT(t)
   134  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   135  
   136  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithTimeoutDisabled, serviceRegistry,
   137  			nil, 8080, gatewayNames, route.RouteOptions{})
   138  		xdstest.ValidateRoutes(t, routes)
   139  
   140  		g.Expect(err).NotTo(HaveOccurred())
   141  		g.Expect(len(routes)).To(Equal(1))
   142  		g.Expect(routes[0].GetRoute().Timeout.Seconds).To(Equal(int64(0)))
   143  		// nolint: staticcheck
   144  		g.Expect(routes[0].GetRoute().MaxGrpcTimeout.Seconds).To(Equal(int64(0)))
   145  	})
   146  
   147  	t.Run("for virtual service with catch all route", func(t *testing.T) {
   148  		g := NewWithT(t)
   149  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   150  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithCatchAllRoute,
   151  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   152  		xdstest.ValidateRoutes(t, routes)
   153  
   154  		g.Expect(err).NotTo(HaveOccurred())
   155  		g.Expect(len(routes)).To(Equal(2))
   156  		g.Expect(routes[0].Name).To(Equal("route.non-catch-all"))
   157  		g.Expect(routes[1].Name).To(Equal("route.catch-all"))
   158  	})
   159  
   160  	t.Run("for virtual service with catch all route:port match", func(t *testing.T) {
   161  		g := NewWithT(t)
   162  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   163  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithCatchAllPort,
   164  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   165  		xdstest.ValidateRoutes(t, routes)
   166  
   167  		g.Expect(err).NotTo(HaveOccurred())
   168  		g.Expect(len(routes)).To(Equal(1))
   169  		g.Expect(routes[0].Name).To(Equal("route 1.catch-all for 8080"))
   170  	})
   171  
   172  	t.Run("for internally generated virtual service with ingress semantics", func(t *testing.T) {
   173  		g := NewWithT(t)
   174  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   175  
   176  		vs := virtualServiceWithCatchAllRoute
   177  		if vs.Annotations == nil {
   178  			vs.Annotations = make(map[string]string)
   179  		}
   180  		vs.Annotations[constants.InternalRouteSemantics] = constants.RouteSemanticsIngress
   181  
   182  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), vs,
   183  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   184  		xdstest.ValidateRoutes(t, routes)
   185  
   186  		g.Expect(err).NotTo(HaveOccurred())
   187  		g.Expect(routes[0].Match.PathSpecifier).To(Equal(&envoyroute.RouteMatch_PathSeparatedPrefix{
   188  			PathSeparatedPrefix: "/route/v1",
   189  		}))
   190  		g.Expect(routes[1].Match.PathSpecifier).To(Equal(&envoyroute.RouteMatch_Prefix{
   191  			Prefix: "/",
   192  		}))
   193  	})
   194  
   195  	t.Run("for internally generated virtual service with gateway semantics", func(t *testing.T) {
   196  		g := NewWithT(t)
   197  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   198  
   199  		vs := virtualServiceWithCatchAllRoute
   200  		if vs.Annotations == nil {
   201  			vs.Annotations = make(map[string]string)
   202  		}
   203  		vs.Annotations[constants.InternalRouteSemantics] = constants.RouteSemanticsGateway
   204  
   205  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), vs,
   206  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   207  		xdstest.ValidateRoutes(t, routes)
   208  
   209  		g.Expect(err).NotTo(HaveOccurred())
   210  		g.Expect(routes[0].Match.PathSpecifier).To(Equal(&envoyroute.RouteMatch_PathSeparatedPrefix{
   211  			PathSeparatedPrefix: "/route/v1",
   212  		}))
   213  		g.Expect(routes[0].Action.(*envoyroute.Route_Route).Route.ClusterNotFoundResponseCode).
   214  			To(Equal(envoyroute.RouteAction_INTERNAL_SERVER_ERROR))
   215  		g.Expect(routes[1].Match.PathSpecifier).To(Equal(&envoyroute.RouteMatch_Prefix{
   216  			Prefix: "/",
   217  		}))
   218  		g.Expect(routes[1].Action.(*envoyroute.Route_Route).Route.ClusterNotFoundResponseCode).
   219  			To(Equal(envoyroute.RouteAction_INTERNAL_SERVER_ERROR))
   220  	})
   221  
   222  	t.Run("for virtual service with top level catch all route", func(t *testing.T) {
   223  		g := NewWithT(t)
   224  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   225  
   226  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithCatchAllRouteWeightedDestination,
   227  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   228  		xdstest.ValidateRoutes(t, routes)
   229  
   230  		g.Expect(err).NotTo(HaveOccurred())
   231  		g.Expect(len(routes)).To(Equal(1))
   232  	})
   233  
   234  	t.Run("for virtual service with multi prefix catch all route", func(t *testing.T) {
   235  		g := NewWithT(t)
   236  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   237  
   238  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithCatchAllMultiPrefixRoute,
   239  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   240  		xdstest.ValidateRoutes(t, routes)
   241  
   242  		g.Expect(err).NotTo(HaveOccurred())
   243  		g.Expect(len(routes)).To(Equal(1))
   244  	})
   245  
   246  	t.Run("for virtual service with regex matching on URI", func(t *testing.T) {
   247  		g := NewWithT(t)
   248  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   249  
   250  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRegexMatchingOnURI,
   251  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   252  		xdstest.ValidateRoutes(t, routes)
   253  		g.Expect(err).NotTo(HaveOccurred())
   254  		g.Expect(len(routes)).To(Equal(1))
   255  		g.Expect(routes[0].GetMatch().GetSafeRegex().GetRegex()).To(Equal("\\/(.?)\\/status"))
   256  	})
   257  
   258  	t.Run("for virtual service with stat_prefix set for a match on URI", func(t *testing.T) {
   259  		g := NewWithT(t)
   260  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   261  
   262  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithStatPrefix,
   263  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   264  		xdstest.ValidateRoutes(t, routes)
   265  		g.Expect(err).NotTo(HaveOccurred())
   266  		g.Expect(len(routes)).To(Equal(3))
   267  		g.Expect(routes[0].GetMatch().GetPrefix()).To(Equal("/foo"))
   268  		g.Expect(routes[0].StatPrefix).To(Equal("foo"))
   269  		g.Expect(routes[1].GetMatch().GetPrefix()).To(Equal("/baz"))
   270  		g.Expect(routes[1].StatPrefix).To(Equal(""))
   271  		g.Expect(routes[2].GetMatch().GetPrefix()).To(Equal("/bar"))
   272  		g.Expect(routes[2].StatPrefix).To(Equal(""))
   273  		g.Expect(len(routes[0].GetRoute().GetRetryPolicy().RetryHostPredicate)).To(Equal(1))
   274  	})
   275  
   276  	t.Run("for virtual service with exact matching on JWT claims", func(t *testing.T) {
   277  		g := NewWithT(t)
   278  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   279  
   280  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithExactMatchingOnHeaderForJWTClaims,
   281  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   282  		xdstest.ValidateRoutes(t, routes)
   283  		g.Expect(err).NotTo(HaveOccurred())
   284  		g.Expect(len(routes)).To(Equal(1))
   285  		g.Expect(len(routes[0].GetMatch().GetHeaders())).To(Equal(0))
   286  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[0].GetFilter()).To(Equal("istio_authn"))
   287  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[0].GetInvert()).To(BeFalse())
   288  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[1].GetFilter()).To(Equal("istio_authn"))
   289  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[1].GetInvert()).To(BeTrue())
   290  	})
   291  
   292  	t.Run("for virtual service with exact matching on JWT claims with extended", func(t *testing.T) {
   293  		g := NewWithT(t)
   294  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   295  
   296  		routes, err := route.BuildHTTPRoutesForVirtualService(nodeWithExtended(cg), virtualServiceWithExactMatchingOnHeaderForJWTClaims,
   297  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   298  		xdstest.ValidateRoutes(t, routes)
   299  		g.Expect(err).NotTo(HaveOccurred())
   300  		g.Expect(len(routes)).To(Equal(1))
   301  		g.Expect(len(routes[0].GetMatch().GetHeaders())).To(Equal(0))
   302  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[0].GetFilter()).To(Equal(filters.EnvoyJwtFilterName))
   303  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[0].GetInvert()).To(BeFalse())
   304  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[1].GetFilter()).To(Equal(filters.EnvoyJwtFilterName))
   305  		g.Expect(routes[0].GetMatch().GetDynamicMetadata()[1].GetInvert()).To(BeTrue())
   306  	})
   307  
   308  	t.Run("for virtual service with regex matching on header", func(t *testing.T) {
   309  		g := NewWithT(t)
   310  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   311  
   312  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRegexMatchingOnHeader,
   313  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   314  		xdstest.ValidateRoutes(t, routes)
   315  		g.Expect(err).NotTo(HaveOccurred())
   316  		g.Expect(len(routes)).To(Equal(1))
   317  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetStringMatch().GetSafeRegex().GetRegex()).To(Equal("Bearer .+?\\..+?\\..+?"))
   318  	})
   319  
   320  	t.Run("for virtual service with regex matching on without_header", func(t *testing.T) {
   321  		g := NewWithT(t)
   322  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   323  
   324  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRegexMatchingOnWithoutHeader,
   325  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   326  		xdstest.ValidateRoutes(t, routes)
   327  		g.Expect(err).NotTo(HaveOccurred())
   328  		g.Expect(len(routes)).To(Equal(1))
   329  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetStringMatch().GetSafeRegex().GetRegex()).To(Equal("BAR .+?\\..+?\\..+?"))
   330  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetInvertMatch()).To(Equal(true))
   331  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetTreatMissingHeaderAsEmpty()).To(Equal(true))
   332  	})
   333  
   334  	t.Run("for virtual service with presence matching on header", func(t *testing.T) {
   335  		g := NewWithT(t)
   336  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   337  
   338  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithPresentMatchingOnHeader,
   339  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   340  		g.Expect(err).NotTo(HaveOccurred())
   341  		xdstest.ValidateRoutes(t, routes)
   342  		g.Expect(len(routes)).To(Equal(1))
   343  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetName()).To(Equal("FOO-HEADER"))
   344  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetPresentMatch()).To(Equal(true))
   345  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetInvertMatch()).To(Equal(false))
   346  
   347  		routes, err = route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithPresentMatchingOnHeader2,
   348  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   349  		g.Expect(err).NotTo(HaveOccurred())
   350  		xdstest.ValidateRoutes(t, routes)
   351  		g.Expect(len(routes)).To(Equal(1))
   352  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetName()).To(Equal("FOO-HEADER"))
   353  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetPresentMatch()).To(Equal(true))
   354  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetInvertMatch()).To(Equal(false))
   355  	})
   356  
   357  	t.Run("for virtual service with presence matching on header and without_header", func(t *testing.T) {
   358  		g := NewWithT(t)
   359  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   360  
   361  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithPresentMatchingOnWithoutHeader,
   362  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   363  		g.Expect(err).NotTo(HaveOccurred())
   364  		xdstest.ValidateRoutes(t, routes)
   365  		g.Expect(len(routes)).To(Equal(1))
   366  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetName()).To(Equal("FOO-HEADER"))
   367  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetPresentMatch()).To(Equal(true))
   368  		g.Expect(routes[0].GetMatch().GetHeaders()[0].GetInvertMatch()).To(Equal(true))
   369  	})
   370  
   371  	t.Run("for virtual service with regex matching for all cases on header", func(t *testing.T) {
   372  		cset := createVirtualServiceWithRegexMatchingForAllCasesOnHeader()
   373  
   374  		for _, c := range cset {
   375  			g := NewWithT(t)
   376  			cg := core.NewConfigGenTest(t, core.TestOptions{})
   377  			routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), *c, serviceRegistry, nil,
   378  				8080, gatewayNames, route.RouteOptions{})
   379  			xdstest.ValidateRoutes(t, routes)
   380  			g.Expect(err).NotTo(HaveOccurred())
   381  			g.Expect(len(routes)).To(Equal(1))
   382  			g.Expect(routes[0].GetMatch().GetHeaders()[0].GetName()).To(Equal("FOO-HEADER"))
   383  			g.Expect(routes[0].GetMatch().GetHeaders()[0].GetPresentMatch()).To(Equal(true))
   384  			g.Expect(routes[0].GetMatch().GetHeaders()[0].GetInvertMatch()).To(Equal(false))
   385  			g.Expect(routes[0].GetMatch().GetHeaders()[0].GetTreatMissingHeaderAsEmpty()).To(Equal(false))
   386  		}
   387  	})
   388  
   389  	t.Run("for virtual service with exact matching on query parameter", func(t *testing.T) {
   390  		g := NewWithT(t)
   391  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   392  
   393  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithExactMatchingOnQueryParameter,
   394  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   395  		xdstest.ValidateRoutes(t, routes)
   396  		g.Expect(err).NotTo(HaveOccurred())
   397  		g.Expect(len(routes)).To(Equal(1))
   398  		g.Expect(routes[0].GetMatch().GetQueryParameters()[0].GetStringMatch().GetExact()).To(Equal("foo"))
   399  	})
   400  
   401  	t.Run("for virtual service with prefix matching on query parameter", func(t *testing.T) {
   402  		g := NewWithT(t)
   403  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   404  
   405  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithPrefixMatchingOnQueryParameter,
   406  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   407  		xdstest.ValidateRoutes(t, routes)
   408  		g.Expect(err).NotTo(HaveOccurred())
   409  		g.Expect(len(routes)).To(Equal(1))
   410  		g.Expect(routes[0].GetMatch().GetQueryParameters()[0].GetStringMatch().GetPrefix()).To(Equal("foo-"))
   411  	})
   412  
   413  	t.Run("for virtual service with regex matching on query parameter", func(t *testing.T) {
   414  		g := NewWithT(t)
   415  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   416  
   417  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRegexMatchingOnQueryParameter,
   418  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   419  		xdstest.ValidateRoutes(t, routes)
   420  		g.Expect(err).NotTo(HaveOccurred())
   421  		g.Expect(len(routes)).To(Equal(1))
   422  		g.Expect(routes[0].GetMatch().GetQueryParameters()[0].GetStringMatch().GetSafeRegex().GetRegex()).To(Equal("BAR .+?\\..+?\\..+?"))
   423  	})
   424  
   425  	t.Run("for virtual service with regex matching for all cases on query parameter", func(t *testing.T) {
   426  		cset := createVirtualServiceWithRegexMatchingForAllCasesOnQueryParameter()
   427  
   428  		for _, c := range cset {
   429  			g := NewWithT(t)
   430  			cg := core.NewConfigGenTest(t, core.TestOptions{})
   431  			routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), *c, serviceRegistry, nil,
   432  				8080, gatewayNames, route.RouteOptions{})
   433  			xdstest.ValidateRoutes(t, routes)
   434  			g.Expect(err).NotTo(HaveOccurred())
   435  			g.Expect(len(routes)).To(Equal(1))
   436  			g.Expect(routes[0].GetMatch().GetQueryParameters()[0].GetName()).To(Equal("token"))
   437  			g.Expect(routes[0].GetMatch().GetQueryParameters()[0].GetPresentMatch()).To(Equal(true))
   438  		}
   439  	})
   440  
   441  	t.Run("for virtual service with source namespace matching", func(t *testing.T) {
   442  		g := NewWithT(t)
   443  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   444  
   445  		fooNode := cg.SetupProxy(&model.Proxy{
   446  			ConfigNamespace: "foo",
   447  		})
   448  
   449  		routes, err := route.BuildHTTPRoutesForVirtualService(fooNode, virtualServiceMatchingOnSourceNamespace,
   450  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   451  		xdstest.ValidateRoutes(t, routes)
   452  		g.Expect(err).NotTo(HaveOccurred())
   453  		g.Expect(len(routes)).To(Equal(1))
   454  		g.Expect(routes[0].GetName()).To(Equal("foo"))
   455  
   456  		barNode := cg.SetupProxy(&model.Proxy{
   457  			ConfigNamespace: "bar",
   458  		})
   459  
   460  		routes, err = route.BuildHTTPRoutesForVirtualService(barNode, virtualServiceMatchingOnSourceNamespace,
   461  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   462  		g.Expect(err).NotTo(HaveOccurred())
   463  		g.Expect(len(routes)).To(Equal(1))
   464  		g.Expect(routes[0].GetName()).To(Equal("bar"))
   465  	})
   466  
   467  	t.Run("for virtual service with ring hash", func(t *testing.T) {
   468  		g := NewWithT(t)
   469  		ttl := durationpb.Duration{Nanos: 100}
   470  		cg := core.NewConfigGenTest(t, core.TestOptions{
   471  			Services: exampleService,
   472  			Configs: []config.Config{
   473  				{
   474  					Meta: config.Meta{
   475  						GroupVersionKind: gvk.DestinationRule,
   476  						Name:             "acme",
   477  						Namespace:        "istio-system",
   478  					},
   479  					Spec: &networking.DestinationRule{
   480  						Host: "*.example.org",
   481  						TrafficPolicy: &networking.TrafficPolicy{
   482  							LoadBalancer: &networking.LoadBalancerSettings{
   483  								LbPolicy: &networking.LoadBalancerSettings_ConsistentHash{
   484  									ConsistentHash: &networking.LoadBalancerSettings_ConsistentHashLB{
   485  										HashKey: &networking.LoadBalancerSettings_ConsistentHashLB_HttpCookie{
   486  											HttpCookie: &networking.LoadBalancerSettings_ConsistentHashLB_HTTPCookie{
   487  												Name: "hash-cookie",
   488  												Ttl:  &ttl,
   489  											},
   490  										},
   491  									},
   492  								},
   493  							},
   494  						},
   495  					},
   496  				},
   497  			},
   498  		})
   499  
   500  		proxy := node(cg)
   501  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualServicePlain)
   502  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualServicePlain, serviceRegistry,
   503  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   504  		xdstest.ValidateRoutes(t, routes)
   505  		g.Expect(err).NotTo(HaveOccurred())
   506  		g.Expect(len(routes)).To(Equal(1))
   507  
   508  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   509  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
   510  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
   511  					Name: "hash-cookie",
   512  					Ttl:  &ttl,
   513  				},
   514  			},
   515  		}
   516  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   517  		g.Expect(len(routes[0].GetRoute().GetRetryPolicy().RetryHostPredicate)).To(Equal(0))
   518  	})
   519  
   520  	t.Run("for virtual service with query param based ring hash", func(t *testing.T) {
   521  		g := NewWithT(t)
   522  		cg := core.NewConfigGenTest(t, core.TestOptions{
   523  			Services: exampleService,
   524  			Configs: []config.Config{
   525  				{
   526  					Meta: config.Meta{
   527  						GroupVersionKind: gvk.DestinationRule,
   528  						Name:             "acme",
   529  						Namespace:        "istio-system",
   530  					},
   531  					Spec: &networking.DestinationRule{
   532  						Host: "*.example.org",
   533  						TrafficPolicy: &networking.TrafficPolicy{
   534  							LoadBalancer: &networking.LoadBalancerSettings{
   535  								LbPolicy: &networking.LoadBalancerSettings_ConsistentHash{
   536  									ConsistentHash: &networking.LoadBalancerSettings_ConsistentHashLB{
   537  										HashKey: &networking.LoadBalancerSettings_ConsistentHashLB_HttpQueryParameterName{
   538  											HttpQueryParameterName: "query",
   539  										},
   540  									},
   541  								},
   542  							},
   543  						},
   544  					},
   545  				},
   546  			},
   547  		})
   548  
   549  		proxy := node(cg)
   550  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualServicePlain)
   551  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualServicePlain, serviceRegistry,
   552  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   553  		xdstest.ValidateRoutes(t, routes)
   554  		g.Expect(err).NotTo(HaveOccurred())
   555  		g.Expect(len(routes)).To(Equal(1))
   556  
   557  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   558  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_QueryParameter_{
   559  				QueryParameter: &envoyroute.RouteAction_HashPolicy_QueryParameter{
   560  					Name: "query",
   561  				},
   562  			},
   563  		}
   564  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   565  		g.Expect(len(routes[0].GetRoute().GetRetryPolicy().RetryHostPredicate)).To(Equal(0))
   566  	})
   567  
   568  	t.Run("for virtual service with subsets with ring hash", func(t *testing.T) {
   569  		g := NewWithT(t)
   570  		virtualService := config.Config{
   571  			Meta: config.Meta{
   572  				GroupVersionKind: gvk.VirtualService,
   573  				Name:             "acme",
   574  			},
   575  			Spec: virtualServiceWithSubset,
   576  		}
   577  		cg := core.NewConfigGenTest(t, core.TestOptions{
   578  			Services: exampleService,
   579  			Configs: []config.Config{
   580  				virtualService,
   581  				{
   582  					Meta: config.Meta{
   583  						GroupVersionKind: gvk.DestinationRule,
   584  						Name:             "acme",
   585  						Namespace:        "istio-system",
   586  					},
   587  					Spec: &networking.DestinationRule{
   588  						Host:    "*.example.org",
   589  						Subsets: []*networking.Subset{networkingSubset},
   590  					},
   591  				},
   592  			},
   593  		})
   594  
   595  		proxy := node(cg)
   596  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualService)
   597  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualService, serviceRegistry,
   598  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   599  		xdstest.ValidateRoutes(t, routes)
   600  		g.Expect(err).NotTo(HaveOccurred())
   601  		g.Expect(len(routes)).To(Equal(1))
   602  
   603  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   604  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
   605  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
   606  					Name: "other-cookie",
   607  					Ttl:  nil,
   608  				},
   609  			},
   610  		}
   611  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   612  	})
   613  
   614  	t.Run("for virtual service with subsets with port level settings with ring hash", func(t *testing.T) {
   615  		g := NewWithT(t)
   616  		virtualService := config.Config{
   617  			Meta: config.Meta{
   618  				GroupVersionKind: gvk.VirtualService,
   619  				Name:             "acme",
   620  			},
   621  			Spec: virtualServiceWithSubsetWithPortLevelSettings,
   622  		}
   623  		cg := core.NewConfigGenTest(t, core.TestOptions{
   624  			Services: exampleService,
   625  			Configs: []config.Config{
   626  				virtualService,
   627  				{
   628  					Meta: config.Meta{
   629  						GroupVersionKind: gvk.DestinationRule,
   630  						Name:             "acme",
   631  						Namespace:        "istio-system",
   632  					},
   633  					Spec: portLevelDestinationRuleWithSubsetPolicy,
   634  				},
   635  			},
   636  		})
   637  
   638  		proxy := node(cg)
   639  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualService)
   640  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualService, serviceRegistry,
   641  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   642  		xdstest.ValidateRoutes(t, routes)
   643  		g.Expect(err).NotTo(HaveOccurred())
   644  		g.Expect(len(routes)).To(Equal(1))
   645  
   646  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   647  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
   648  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
   649  					Name: "port-level-settings-cookie",
   650  					Ttl:  nil,
   651  				},
   652  			},
   653  		}
   654  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   655  	})
   656  
   657  	t.Run("for virtual service with subsets and top level traffic policy with ring hash", func(t *testing.T) {
   658  		g := NewWithT(t)
   659  
   660  		virtualService := config.Config{
   661  			Meta: config.Meta{
   662  				GroupVersionKind: gvk.VirtualService,
   663  				Name:             "acme",
   664  			},
   665  			Spec: virtualServiceWithSubset,
   666  		}
   667  
   668  		cnfg := config.Config{
   669  			Meta: config.Meta{
   670  				GroupVersionKind: gvk.DestinationRule,
   671  				Name:             "acme",
   672  				Namespace:        "istio-system",
   673  			},
   674  		}
   675  		rule := networkingDestinationRule
   676  		rule.Subsets = []*networking.Subset{networkingSubset}
   677  		cnfg.Spec = networkingDestinationRule
   678  
   679  		cg := core.NewConfigGenTest(t, core.TestOptions{
   680  			Services: exampleService,
   681  			Configs:  []config.Config{cnfg, virtualService},
   682  		})
   683  
   684  		proxy := node(cg)
   685  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualService)
   686  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualService, serviceRegistry,
   687  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   688  		xdstest.ValidateRoutes(t, routes)
   689  		g.Expect(err).NotTo(HaveOccurred())
   690  		g.Expect(len(routes)).To(Equal(1))
   691  
   692  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   693  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
   694  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
   695  					Name: "other-cookie",
   696  					Ttl:  nil,
   697  				},
   698  			},
   699  		}
   700  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   701  	})
   702  
   703  	t.Run("port selector based traffic policy", func(t *testing.T) {
   704  		g := NewWithT(t)
   705  
   706  		cg := core.NewConfigGenTest(t, core.TestOptions{
   707  			Services: exampleService,
   708  			Configs: []config.Config{{
   709  				Meta: config.Meta{
   710  					GroupVersionKind: gvk.DestinationRule,
   711  					Name:             "acme",
   712  					Namespace:        "istio-system",
   713  				},
   714  				Spec: portLevelDestinationRule,
   715  			}},
   716  		})
   717  
   718  		proxy := node(cg)
   719  		gatewayNames := sets.New("some-gateway")
   720  		hashByDestination := route.GetConsistentHashForVirtualService(cg.PushContext(), proxy, virtualServicePlain)
   721  		routes, err := route.BuildHTTPRoutesForVirtualService(proxy, virtualServicePlain, serviceRegistry,
   722  			hashByDestination, 8080, gatewayNames, route.RouteOptions{})
   723  		xdstest.ValidateRoutes(t, routes)
   724  		g.Expect(err).NotTo(HaveOccurred())
   725  		g.Expect(len(routes)).To(Equal(1))
   726  
   727  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
   728  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
   729  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
   730  					Name: "hash-cookie",
   731  					Ttl:  nil,
   732  				},
   733  			},
   734  		}
   735  		g.Expect(routes[0].GetRoute().GetHashPolicy()).To(ConsistOf(hashPolicy))
   736  	})
   737  
   738  	t.Run("for header operations for single cluster", func(t *testing.T) {
   739  		g := NewWithT(t)
   740  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   741  
   742  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithHeaderOperationsForSingleCluster,
   743  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   744  		xdstest.ValidateRoutes(t, routes)
   745  		g.Expect(err).NotTo(HaveOccurred())
   746  		g.Expect(len(routes)).To(Equal(1))
   747  
   748  		r := routes[0]
   749  		g.Expect(len(r.RequestHeadersToAdd)).To(Equal(4))
   750  		g.Expect(len(r.ResponseHeadersToAdd)).To(Equal(4))
   751  		g.Expect(len(r.RequestHeadersToRemove)).To(Equal(2))
   752  		g.Expect(len(r.ResponseHeadersToRemove)).To(Equal(2))
   753  
   754  		g.Expect(r.RequestHeadersToAdd).To(Equal([]*envoycore.HeaderValueOption{
   755  			{
   756  				Header: &envoycore.HeaderValue{
   757  					Key:   "x-req-set",
   758  					Value: "v1",
   759  				},
   760  				AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   761  			},
   762  			{
   763  				Header: &envoycore.HeaderValue{
   764  					Key:   "x-req-add",
   765  					Value: "v2",
   766  				},
   767  				AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   768  			},
   769  			{
   770  				Header: &envoycore.HeaderValue{
   771  					Key:   "x-route-req-set",
   772  					Value: "v1",
   773  				},
   774  				AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   775  			},
   776  			{
   777  				Header: &envoycore.HeaderValue{
   778  					Key:   "x-route-req-add",
   779  					Value: "v2",
   780  				},
   781  				AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   782  			},
   783  		}))
   784  		g.Expect(r.RequestHeadersToRemove).To(Equal([]string{"x-req-remove", "x-route-req-remove"}))
   785  
   786  		g.Expect(r.ResponseHeadersToAdd).To(Equal([]*envoycore.HeaderValueOption{
   787  			{
   788  				Header: &envoycore.HeaderValue{
   789  					Key:   "x-resp-set",
   790  					Value: "v1",
   791  				},
   792  				AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   793  			},
   794  			{
   795  				Header: &envoycore.HeaderValue{
   796  					Key:   "x-resp-add",
   797  					Value: "v2",
   798  				},
   799  				AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   800  			},
   801  			{
   802  				Header: &envoycore.HeaderValue{
   803  					Key:   "x-route-resp-set",
   804  					Value: "v1",
   805  				},
   806  				AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   807  			},
   808  			{
   809  				Header: &envoycore.HeaderValue{
   810  					Key:   "x-route-resp-add",
   811  					Value: "v2",
   812  				},
   813  				AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   814  			},
   815  		}))
   816  		g.Expect(r.ResponseHeadersToRemove).To(Equal([]string{"x-resp-remove", "x-route-resp-remove"}))
   817  
   818  		routeAction, ok := r.GetAction().(*envoyroute.Route_Route)
   819  		g.Expect(ok).NotTo(BeFalse())
   820  		g.Expect(routeAction.Route.GetHostRewriteLiteral()).To(Equal("foo.extsvc.com"))
   821  	})
   822  
   823  	t.Run("for header operations for weighted cluster", func(t *testing.T) {
   824  		g := NewWithT(t)
   825  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   826  
   827  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithHeaderOperationsForWeightedCluster,
   828  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
   829  		xdstest.ValidateRoutes(t, routes)
   830  		g.Expect(err).NotTo(HaveOccurred())
   831  		g.Expect(len(routes)).To(Equal(1))
   832  
   833  		r := routes[0]
   834  		routeAction, ok := r.GetAction().(*envoyroute.Route_Route)
   835  		g.Expect(ok).NotTo(BeFalse())
   836  
   837  		weightedCluster := routeAction.Route.GetWeightedClusters()
   838  		g.Expect(weightedCluster).NotTo(BeNil())
   839  		g.Expect(len(weightedCluster.GetClusters())).To(Equal(2))
   840  
   841  		expectResults := []struct {
   842  			reqAdd     []*envoycore.HeaderValueOption
   843  			reqRemove  []string
   844  			respAdd    []*envoycore.HeaderValueOption
   845  			respRemove []string
   846  			authority  string
   847  		}{
   848  			{
   849  				reqAdd: []*envoycore.HeaderValueOption{
   850  					{
   851  						Header: &envoycore.HeaderValue{
   852  							Key:   "x-route-req-set-blue",
   853  							Value: "v1",
   854  						},
   855  						AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   856  					},
   857  					{
   858  						Header: &envoycore.HeaderValue{
   859  							Key:   "x-route-req-add-blue",
   860  							Value: "v2",
   861  						},
   862  						AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   863  					},
   864  				},
   865  				reqRemove: []string{"x-route-req-remove-blue"},
   866  				respAdd: []*envoycore.HeaderValueOption{
   867  					{
   868  						Header: &envoycore.HeaderValue{
   869  							Key:   "x-route-resp-set-blue",
   870  							Value: "v1",
   871  						},
   872  						AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   873  					},
   874  					{
   875  						Header: &envoycore.HeaderValue{
   876  							Key:   "x-route-resp-add-blue",
   877  							Value: "v2",
   878  						},
   879  						AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   880  					},
   881  				},
   882  				respRemove: []string{"x-route-resp-remove-blue"},
   883  				authority:  "blue.foo.extsvc.com",
   884  			},
   885  			{
   886  				reqAdd: []*envoycore.HeaderValueOption{
   887  					{
   888  						Header: &envoycore.HeaderValue{
   889  							Key:   "x-route-req-set-green",
   890  							Value: "v1",
   891  						},
   892  						AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   893  					},
   894  					{
   895  						Header: &envoycore.HeaderValue{
   896  							Key:   "x-route-req-add-green",
   897  							Value: "v2",
   898  						},
   899  						AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   900  					},
   901  				},
   902  				reqRemove: []string{"x-route-req-remove-green"},
   903  				respAdd: []*envoycore.HeaderValueOption{
   904  					{
   905  						Header: &envoycore.HeaderValue{
   906  							Key:   "x-route-resp-set-green",
   907  							Value: "v1",
   908  						},
   909  						AppendAction: envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
   910  					},
   911  					{
   912  						Header: &envoycore.HeaderValue{
   913  							Key:   "x-route-resp-add-green",
   914  							Value: "v2",
   915  						},
   916  						AppendAction: envoycore.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
   917  					},
   918  				},
   919  				respRemove: []string{"x-route-resp-remove-green"},
   920  				authority:  "green.foo.extsvc.com",
   921  			},
   922  		}
   923  
   924  		for i, expectResult := range expectResults {
   925  			cluster := weightedCluster.GetClusters()[i]
   926  			g.Expect(cluster.RequestHeadersToAdd).To(Equal(expectResult.reqAdd))
   927  			g.Expect(cluster.RequestHeadersToRemove).To(Equal(expectResult.reqRemove))
   928  			g.Expect(cluster.ResponseHeadersToAdd).To(Equal(expectResult.respAdd))
   929  			g.Expect(cluster.RequestHeadersToRemove).To(Equal(expectResult.reqRemove))
   930  			g.Expect(cluster.GetHostRewriteLiteral()).To(Equal(expectResult.authority))
   931  		}
   932  	})
   933  
   934  	t.Run("for redirect code", func(t *testing.T) {
   935  		g := NewWithT(t)
   936  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   937  
   938  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRedirect, serviceRegistry,
   939  			nil, 8080, gatewayNames, route.RouteOptions{})
   940  		xdstest.ValidateRoutes(t, routes)
   941  		g.Expect(err).NotTo(HaveOccurred())
   942  		g.Expect(len(routes)).To(Equal(1))
   943  
   944  		redirectAction, ok := routes[0].Action.(*envoyroute.Route_Redirect)
   945  		g.Expect(ok).NotTo(BeFalse())
   946  		g.Expect(redirectAction.Redirect.ResponseCode).To(Equal(envoyroute.RedirectAction_PERMANENT_REDIRECT))
   947  	})
   948  
   949  	t.Run("for path prefix redirect", func(t *testing.T) {
   950  		g := NewWithT(t)
   951  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   952  
   953  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRedirectPathPrefix, serviceRegistry,
   954  			nil, 8080, gatewayNames, route.RouteOptions{})
   955  		xdstest.ValidateRoutes(t, routes)
   956  		g.Expect(err).NotTo(HaveOccurred())
   957  		g.Expect(len(routes)).To(Equal(1))
   958  
   959  		redirectAction, ok := routes[0].Action.(*envoyroute.Route_Redirect)
   960  		g.Expect(ok).NotTo(BeFalse())
   961  		g.Expect(redirectAction.Redirect.PathRewriteSpecifier).To(Equal(&envoyroute.RedirectAction_PrefixRewrite{
   962  			PrefixRewrite: "/replace-prefix",
   963  		}))
   964  	})
   965  
   966  	t.Run("for host rewrite", func(t *testing.T) {
   967  		g := NewWithT(t)
   968  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   969  
   970  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRewriteHost, serviceRegistry,
   971  			nil, 8080, gatewayNames, route.RouteOptions{})
   972  		xdstest.ValidateRoutes(t, routes)
   973  		g.Expect(err).NotTo(HaveOccurred())
   974  		g.Expect(len(routes)).To(Equal(1))
   975  
   976  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
   977  		g.Expect(ok).NotTo(BeFalse())
   978  		g.Expect(routeAction.Route.HostRewriteSpecifier).To(Equal(&envoyroute.RouteAction_HostRewriteLiteral{
   979  			HostRewriteLiteral: "bar.example.org",
   980  		}))
   981  	})
   982  
   983  	t.Run("for full path rewrite", func(t *testing.T) {
   984  		g := NewWithT(t)
   985  		cg := core.NewConfigGenTest(t, core.TestOptions{})
   986  
   987  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRewriteFullPath, serviceRegistry,
   988  			nil, 8080, gatewayNames, route.RouteOptions{})
   989  		xdstest.ValidateRoutes(t, routes)
   990  		g.Expect(err).NotTo(HaveOccurred())
   991  		g.Expect(len(routes)).To(Equal(1))
   992  
   993  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
   994  		g.Expect(ok).NotTo(BeFalse())
   995  
   996  		g.Expect(routeAction.Route.RegexRewrite).To(Equal(&matcher.RegexMatchAndSubstitute{
   997  			Pattern: &matcher.RegexMatcher{
   998  				Regex: "/.*",
   999  			},
  1000  			Substitution: "/replace-full",
  1001  		}))
  1002  	})
  1003  
  1004  	t.Run("for prefix path rewrite", func(t *testing.T) {
  1005  		g := NewWithT(t)
  1006  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1007  
  1008  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRewritePrefixPath, serviceRegistry,
  1009  			nil, 8080, gatewayNames, route.RouteOptions{})
  1010  		xdstest.ValidateRoutes(t, routes)
  1011  		g.Expect(err).NotTo(HaveOccurred())
  1012  		g.Expect(len(routes)).To(Equal(1))
  1013  
  1014  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
  1015  		g.Expect(ok).NotTo(BeFalse())
  1016  		g.Expect(routeAction.Route.PrefixRewrite).To(Equal("/replace-prefix"))
  1017  	})
  1018  
  1019  	t.Run("for empty prefix path rewrite", func(t *testing.T) {
  1020  		g := NewWithT(t)
  1021  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1022  
  1023  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithEmptyRewritePrefixPath, serviceRegistry,
  1024  			nil, 8080, gatewayNames, route.RouteOptions{})
  1025  		xdstest.ValidateRoutes(t, routes)
  1026  		g.Expect(err).NotTo(HaveOccurred())
  1027  		g.Expect(len(routes)).To(Equal(1))
  1028  
  1029  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
  1030  		g.Expect(ok).NotTo(BeFalse())
  1031  		g.Expect(routeAction.Route.RegexRewrite).To(Equal(&matcher.RegexMatchAndSubstitute{
  1032  			Pattern: &matcher.RegexMatcher{
  1033  				Regex: `^/prefix-to-be-removed(/?)(.*)`,
  1034  			},
  1035  			Substitution: `/\2`,
  1036  		}))
  1037  	})
  1038  
  1039  	t.Run("for path and host rewrite", func(t *testing.T) {
  1040  		g := NewWithT(t)
  1041  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1042  
  1043  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg),
  1044  			virtualServiceWithRewriteFullPathAndHost,
  1045  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
  1046  		xdstest.ValidateRoutes(t, routes)
  1047  		g.Expect(err).NotTo(HaveOccurred())
  1048  		g.Expect(len(routes)).To(Equal(1))
  1049  
  1050  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
  1051  		g.Expect(ok).NotTo(BeFalse())
  1052  		g.Expect(routeAction.Route.HostRewriteSpecifier).To(Equal(&envoyroute.RouteAction_HostRewriteLiteral{
  1053  			HostRewriteLiteral: "bar.example.org",
  1054  		}))
  1055  		g.Expect(routeAction.Route.RegexRewrite).To(Equal(&matcher.RegexMatchAndSubstitute{
  1056  			Pattern: &matcher.RegexMatcher{
  1057  				Regex: "/.*",
  1058  			},
  1059  			Substitution: "/replace-full",
  1060  		}))
  1061  	})
  1062  
  1063  	t.Run("for path regex match with regex rewrite", func(t *testing.T) {
  1064  		g := NewWithT(t)
  1065  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1066  
  1067  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg),
  1068  			virtualServiceWithPathRegexMatchRegexRewrite,
  1069  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
  1070  		xdstest.ValidateRoutes(t, routes)
  1071  		g.Expect(err).NotTo(HaveOccurred())
  1072  		g.Expect(len(routes)).To(Equal(1))
  1073  
  1074  		routeAction, ok := routes[0].Action.(*envoyroute.Route_Route)
  1075  		g.Expect(ok).NotTo(BeFalse())
  1076  		g.Expect(routeAction.Route.RegexRewrite).To(Equal(&matcher.RegexMatchAndSubstitute{
  1077  			Pattern: &matcher.RegexMatcher{
  1078  				Regex: "^/service/([^/]+)(/.*)$",
  1079  			},
  1080  			Substitution: "\\2/instance/\\1",
  1081  		}))
  1082  	})
  1083  
  1084  	t.Run("for redirect uri prefix '%PREFIX()%' that is without gateway semantics", func(t *testing.T) {
  1085  		g := NewWithT(t)
  1086  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1087  
  1088  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg),
  1089  			virtualServiceWithRedirectPathPrefixNoGatewaySematics,
  1090  			serviceRegistry, nil, 8080, gatewayNames, route.RouteOptions{})
  1091  		xdstest.ValidateRoutes(t, routes)
  1092  		g.Expect(err).NotTo(HaveOccurred())
  1093  		g.Expect(len(routes)).To(Equal(1))
  1094  
  1095  		redirectAction, ok := routes[0].Action.(*envoyroute.Route_Redirect)
  1096  		g.Expect(ok).NotTo(BeFalse())
  1097  		g.Expect(redirectAction.Redirect.PathRewriteSpecifier).To(Equal(&envoyroute.RedirectAction_PathRedirect{
  1098  			PathRedirect: "%PREFIX()%/replace-full",
  1099  		}))
  1100  	})
  1101  
  1102  	t.Run("for full path redirect", func(t *testing.T) {
  1103  		g := NewWithT(t)
  1104  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1105  
  1106  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRedirectFullPath, serviceRegistry,
  1107  			nil, 8080, gatewayNames, route.RouteOptions{})
  1108  		xdstest.ValidateRoutes(t, routes)
  1109  		g.Expect(err).NotTo(HaveOccurred())
  1110  		g.Expect(len(routes)).To(Equal(1))
  1111  
  1112  		redirectAction, ok := routes[0].Action.(*envoyroute.Route_Redirect)
  1113  		g.Expect(ok).NotTo(BeFalse())
  1114  		g.Expect(redirectAction.Redirect.PathRewriteSpecifier).To(Equal(&envoyroute.RedirectAction_PathRedirect{
  1115  			PathRedirect: "/replace-full-path",
  1116  		}))
  1117  	})
  1118  
  1119  	t.Run("for redirect and header manipulation", func(t *testing.T) {
  1120  		g := NewWithT(t)
  1121  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1122  
  1123  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithRedirectAndSetHeader, serviceRegistry,
  1124  			nil, 8080, gatewayNames, route.RouteOptions{})
  1125  		xdstest.ValidateRoutes(t, routes)
  1126  		g.Expect(err).NotTo(HaveOccurred())
  1127  		g.Expect(len(routes)).To(Equal(1))
  1128  
  1129  		redirectAction, ok := routes[0].Action.(*envoyroute.Route_Redirect)
  1130  		g.Expect(ok).NotTo(BeFalse())
  1131  		g.Expect(redirectAction.Redirect.ResponseCode).To(Equal(envoyroute.RedirectAction_PERMANENT_REDIRECT))
  1132  		g.Expect(len(routes[0].ResponseHeadersToAdd)).To(Equal(1))
  1133  		g.Expect(routes[0].ResponseHeadersToAdd[0].AppendAction).To(Equal(envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD))
  1134  		g.Expect(routes[0].ResponseHeadersToAdd[0].Header.Key).To(Equal("Strict-Transport-Security"))
  1135  		g.Expect(routes[0].ResponseHeadersToAdd[0].Header.Value).To(Equal("max-age=31536000; includeSubDomains; preload"))
  1136  	})
  1137  
  1138  	t.Run("for direct response code", func(t *testing.T) {
  1139  		g := NewWithT(t)
  1140  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1141  
  1142  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithDirectResponse, serviceRegistry,
  1143  			nil, 8080, gatewayNames, route.RouteOptions{})
  1144  		xdstest.ValidateRoutes(t, routes)
  1145  		g.Expect(err).NotTo(HaveOccurred())
  1146  		g.Expect(len(routes)).To(Equal(1))
  1147  
  1148  		directResponseAction, ok := routes[0].Action.(*envoyroute.Route_DirectResponse)
  1149  		g.Expect(ok).NotTo(BeFalse())
  1150  		g.Expect(directResponseAction.DirectResponse.Status).To(Equal(uint32(200)))
  1151  		g.Expect(directResponseAction.DirectResponse.Body.Specifier.(*envoycore.DataSource_InlineString).InlineString).To(Equal("hello"))
  1152  	})
  1153  
  1154  	t.Run("for direct response code and header manipulation", func(t *testing.T) {
  1155  		g := NewWithT(t)
  1156  		cg := core.NewConfigGenTest(t, core.TestOptions{})
  1157  
  1158  		routes, err := route.BuildHTTPRoutesForVirtualService(node(cg), virtualServiceWithDirectResponseAndSetHeader, serviceRegistry,
  1159  			nil, 8080, gatewayNames, route.RouteOptions{})
  1160  		xdstest.ValidateRoutes(t, routes)
  1161  		g.Expect(err).NotTo(HaveOccurred())
  1162  		g.Expect(len(routes)).To(Equal(1))
  1163  
  1164  		directResponseAction, ok := routes[0].Action.(*envoyroute.Route_DirectResponse)
  1165  		g.Expect(ok).NotTo(BeFalse())
  1166  		g.Expect(directResponseAction.DirectResponse.Status).To(Equal(uint32(200)))
  1167  		g.Expect(directResponseAction.DirectResponse.Body.Specifier.(*envoycore.DataSource_InlineString).InlineString).To(Equal("hello"))
  1168  		g.Expect(len(routes[0].ResponseHeadersToAdd)).To(Equal(1))
  1169  		g.Expect(routes[0].ResponseHeadersToAdd[0].AppendAction).To(Equal(envoycore.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD))
  1170  		g.Expect(routes[0].ResponseHeadersToAdd[0].Header.Key).To(Equal("Strict-Transport-Security"))
  1171  		g.Expect(routes[0].ResponseHeadersToAdd[0].Header.Value).To(Equal("max-age=31536000; includeSubDomains; preload"))
  1172  	})
  1173  
  1174  	t.Run("for no virtualservice but has destinationrule with consistentHash loadbalancer", func(t *testing.T) {
  1175  		g := NewWithT(t)
  1176  		cg := core.NewConfigGenTest(t, core.TestOptions{
  1177  			Configs: []config.Config{
  1178  				{
  1179  					Meta: config.Meta{
  1180  						GroupVersionKind: gvk.DestinationRule,
  1181  						Name:             "acme",
  1182  						Namespace:        "istio-system",
  1183  					},
  1184  					Spec: networkingDestinationRule,
  1185  				},
  1186  			},
  1187  			Services: exampleService,
  1188  		})
  1189  		vhosts := route.BuildSidecarVirtualHostWrapper(nil, node(cg), cg.PushContext(), serviceRegistry,
  1190  			[]config.Config{}, 8080, map[host.Name]types.NamespacedName{},
  1191  		)
  1192  		g.Expect(vhosts[0].Routes[0].Action.(*envoyroute.Route_Route).Route.HashPolicy).NotTo(BeNil())
  1193  	})
  1194  	t.Run("for no virtualservice but has destinationrule with portLevel consistentHash loadbalancer", func(t *testing.T) {
  1195  		g := NewWithT(t)
  1196  		cg := core.NewConfigGenTest(t, core.TestOptions{
  1197  			Configs: []config.Config{
  1198  				{
  1199  					Meta: config.Meta{
  1200  						GroupVersionKind: gvk.DestinationRule,
  1201  						Name:             "acme",
  1202  						Namespace:        "istio-system",
  1203  					},
  1204  					Spec: networkingDestinationRuleWithPortLevelTrafficPolicy,
  1205  				},
  1206  			},
  1207  			Services: exampleService,
  1208  		})
  1209  		vhosts := route.BuildSidecarVirtualHostWrapper(nil, node(cg), cg.PushContext(), serviceRegistry,
  1210  			[]config.Config{}, 8080, map[host.Name]types.NamespacedName{},
  1211  		)
  1212  
  1213  		hashPolicy := &envoyroute.RouteAction_HashPolicy{
  1214  			PolicySpecifier: &envoyroute.RouteAction_HashPolicy_Cookie_{
  1215  				Cookie: &envoyroute.RouteAction_HashPolicy_Cookie{
  1216  					Name: "hash-cookie-1",
  1217  				},
  1218  			},
  1219  		}
  1220  		g.Expect(vhosts[0].Routes[0].Action.(*envoyroute.Route_Route).Route.HashPolicy).To(ConsistOf(hashPolicy))
  1221  	})
  1222  
  1223  	t.Run("for virtualservices and services with overlapping wildcard hosts", func(t *testing.T) {
  1224  		g := NewWithT(t)
  1225  		cg := core.NewConfigGenTest(t, core.TestOptions{
  1226  			Configs: []config.Config{
  1227  				virtualServiceWithWildcardHost,
  1228  				virtualServiceWithNestedWildcardHost,
  1229  				virtualServiceWithGoogleWildcardHost,
  1230  			},
  1231  			Services: []*model.Service{exampleWildcardService, exampleNestedWildcardService},
  1232  		})
  1233  
  1234  		// Redefine the service registry for this test
  1235  		serviceRegistry := map[host.Name]*model.Service{
  1236  			"*.example.org":             exampleWildcardService,
  1237  			"goodbye.hello.example.org": exampleNestedWildcardService,
  1238  		}
  1239  
  1240  		wildcardIndex := map[host.Name]types.NamespacedName{
  1241  			"*.example.org":       virtualServiceWithWildcardHost.NamespacedName(),
  1242  			"*.hello.example.org": virtualServiceWithNestedWildcardHost.NamespacedName(),
  1243  		}
  1244  
  1245  		vhosts := route.BuildSidecarVirtualHostWrapper(nil, node(cg), cg.PushContext(), serviceRegistry,
  1246  			[]config.Config{
  1247  				virtualServiceWithWildcardHost,
  1248  				virtualServiceWithNestedWildcardHost,
  1249  				virtualServiceWithGoogleWildcardHost,
  1250  			}, 8080,
  1251  			wildcardIndex,
  1252  		)
  1253  		log.Printf("%#v", vhosts)
  1254  		// *.example.org, *.hello.example.org. The *.google.com VS is missing from virtualHosts because
  1255  		// it is not attached to a service
  1256  		g.Expect(vhosts).To(HaveLen(2))
  1257  		for _, vhost := range vhosts {
  1258  			g.Expect(vhost.Services).To(HaveLen(1))
  1259  			g.Expect(vhost.Routes).To(HaveLen(1))
  1260  		}
  1261  	})
  1262  
  1263  	t.Run("for virtualservices with with wildcard hosts outside of the serviceregistry (on port 80)", func(t *testing.T) {
  1264  		g := NewWithT(t)
  1265  		cg := core.NewConfigGenTest(t, core.TestOptions{
  1266  			Configs: []config.Config{
  1267  				virtualServiceWithWildcardHost,
  1268  				virtualServiceWithNestedWildcardHost,
  1269  				virtualServiceWithGoogleWildcardHost,
  1270  			},
  1271  			Services: []*model.Service{exampleWildcardService, exampleNestedWildcardService},
  1272  		})
  1273  
  1274  		// Redefine the service registry for this test
  1275  		serviceRegistry := map[host.Name]*model.Service{
  1276  			"*.example.org":             exampleWildcardService,
  1277  			"goodbye.hello.example.org": exampleNestedWildcardService,
  1278  		}
  1279  
  1280  		// note that the VS containing *.google.com doesn't have an entry in the wildcard index
  1281  		wildcardIndex := map[host.Name]types.NamespacedName{
  1282  			"*.example.org":       virtualServiceWithWildcardHost.NamespacedName(),
  1283  			"*.hello.example.org": virtualServiceWithNestedWildcardHost.NamespacedName(),
  1284  		}
  1285  
  1286  		vhosts := route.BuildSidecarVirtualHostWrapper(nil, node(cg), cg.PushContext(), serviceRegistry,
  1287  			[]config.Config{virtualServiceWithGoogleWildcardHost}, 80, wildcardIndex,
  1288  		)
  1289  		// The service hosts (*.example.org and goodbye.hello.example.org) and the unattached VS host (*.google.com)
  1290  		g.Expect(vhosts).To(HaveLen(3))
  1291  		for _, vhost := range vhosts {
  1292  			if len(vhost.VirtualServiceHosts) > 0 && vhost.VirtualServiceHosts[0] == "*.google.com" {
  1293  				// The *.google.com VS shouldn't have any services
  1294  				g.Expect(vhost.Services).To(HaveLen(0))
  1295  			} else {
  1296  				// The other two VSs should have one service each
  1297  				g.Expect(vhost.Services).To(HaveLen(1))
  1298  			}
  1299  			// All VSs should have one route
  1300  			g.Expect(vhost.Routes).To(HaveLen(1))
  1301  		}
  1302  	})
  1303  }
  1304  
  1305  func loadBalancerPolicy(name string) *networking.LoadBalancerSettings_ConsistentHash {
  1306  	return &networking.LoadBalancerSettings_ConsistentHash{
  1307  		ConsistentHash: &networking.LoadBalancerSettings_ConsistentHashLB{
  1308  			HashKey: &networking.LoadBalancerSettings_ConsistentHashLB_HttpCookie{
  1309  				HttpCookie: &networking.LoadBalancerSettings_ConsistentHashLB_HTTPCookie{
  1310  					Name: name,
  1311  				},
  1312  			},
  1313  		},
  1314  	}
  1315  }
  1316  
  1317  var virtualServiceWithSubset = &networking.VirtualService{
  1318  	Hosts:    []string{},
  1319  	Gateways: []string{"some-gateway"},
  1320  	Http: []*networking.HTTPRoute{
  1321  		{
  1322  			Route: []*networking.HTTPRouteDestination{
  1323  				{
  1324  					Destination: &networking.Destination{
  1325  						Subset: "some-subset",
  1326  						Host:   "*.example.org",
  1327  						Port: &networking.PortSelector{
  1328  							Number: 65000,
  1329  						},
  1330  					},
  1331  					Weight: 100,
  1332  				},
  1333  			},
  1334  		},
  1335  	},
  1336  }
  1337  
  1338  var virtualServiceWithSubsetWithPortLevelSettings = &networking.VirtualService{
  1339  	Hosts:    []string{},
  1340  	Gateways: []string{"some-gateway"},
  1341  	Http: []*networking.HTTPRoute{
  1342  		{
  1343  			Route: []*networking.HTTPRouteDestination{
  1344  				{
  1345  					Destination: &networking.Destination{
  1346  						Subset: "port-level-settings-subset",
  1347  						Host:   "*.example.org",
  1348  						Port: &networking.PortSelector{
  1349  							Number: 8484,
  1350  						},
  1351  					},
  1352  					Weight: 100,
  1353  				},
  1354  			},
  1355  		},
  1356  	},
  1357  }
  1358  
  1359  var virtualServicePlain = config.Config{
  1360  	Meta: config.Meta{
  1361  		GroupVersionKind: gvk.VirtualService,
  1362  		Name:             "acme",
  1363  	},
  1364  	Spec: &networking.VirtualService{
  1365  		Hosts:    []string{},
  1366  		Gateways: []string{"some-gateway"},
  1367  		Http: []*networking.HTTPRoute{
  1368  			{
  1369  				Route: []*networking.HTTPRouteDestination{
  1370  					{
  1371  						Destination: &networking.Destination{
  1372  							Host: "*.example.org",
  1373  							Port: &networking.PortSelector{
  1374  								Number: 8484,
  1375  							},
  1376  						},
  1377  						Weight: 100,
  1378  					},
  1379  				},
  1380  			},
  1381  		},
  1382  	},
  1383  }
  1384  
  1385  var virtualServiceWithTimeout = config.Config{
  1386  	Meta: config.Meta{
  1387  		GroupVersionKind: gvk.VirtualService,
  1388  		Name:             "acme",
  1389  	},
  1390  	Spec: &networking.VirtualService{
  1391  		Hosts:    []string{},
  1392  		Gateways: []string{"some-gateway"},
  1393  		Http: []*networking.HTTPRoute{
  1394  			{
  1395  				Route: []*networking.HTTPRouteDestination{
  1396  					{
  1397  						Destination: &networking.Destination{
  1398  							Host: "*.example.org",
  1399  							Port: &networking.PortSelector{
  1400  								Number: 8484,
  1401  							},
  1402  						},
  1403  						Weight: 100,
  1404  					},
  1405  				},
  1406  				Timeout: &durationpb.Duration{
  1407  					Seconds: 10,
  1408  				},
  1409  			},
  1410  		},
  1411  	},
  1412  }
  1413  
  1414  var virtualServiceWithTimeoutDisabled = config.Config{
  1415  	Meta: config.Meta{
  1416  		GroupVersionKind: gvk.VirtualService,
  1417  		Name:             "acme",
  1418  	},
  1419  	Spec: &networking.VirtualService{
  1420  		Hosts:    []string{},
  1421  		Gateways: []string{"some-gateway"},
  1422  		Http: []*networking.HTTPRoute{
  1423  			{
  1424  				Route: []*networking.HTTPRouteDestination{
  1425  					{
  1426  						Destination: &networking.Destination{
  1427  							Host: "*.example.org",
  1428  							Port: &networking.PortSelector{
  1429  								Number: 8484,
  1430  							},
  1431  						},
  1432  						Weight: 100,
  1433  					},
  1434  				},
  1435  				Timeout: &durationpb.Duration{
  1436  					Seconds: 0,
  1437  				},
  1438  			},
  1439  		},
  1440  	},
  1441  }
  1442  
  1443  var virtualServiceWithCatchAllRoute = config.Config{
  1444  	Meta: config.Meta{
  1445  		GroupVersionKind: gvk.VirtualService,
  1446  		Name:             "acme",
  1447  	},
  1448  	Spec: &networking.VirtualService{
  1449  		Hosts:    []string{},
  1450  		Gateways: []string{"some-gateway"},
  1451  		Http: []*networking.HTTPRoute{
  1452  			{
  1453  				Name: "route",
  1454  				Match: []*networking.HTTPMatchRequest{
  1455  					{
  1456  						Name: "non-catch-all",
  1457  						Uri: &networking.StringMatch{
  1458  							MatchType: &networking.StringMatch_Prefix{
  1459  								Prefix: "/route/v1",
  1460  							},
  1461  						},
  1462  					},
  1463  					{
  1464  						Name: "catch-all",
  1465  						Uri: &networking.StringMatch{
  1466  							MatchType: &networking.StringMatch_Prefix{
  1467  								Prefix: "/",
  1468  							},
  1469  						},
  1470  					},
  1471  				},
  1472  				Route: []*networking.HTTPRouteDestination{
  1473  					{
  1474  						Destination: &networking.Destination{
  1475  							Host: "*.example.org",
  1476  							Port: &networking.PortSelector{
  1477  								Number: 8484,
  1478  							},
  1479  						},
  1480  						Weight: 100,
  1481  					},
  1482  				},
  1483  			},
  1484  		},
  1485  	},
  1486  }
  1487  
  1488  var virtualServiceWithCatchAllPort = config.Config{
  1489  	Meta: config.Meta{
  1490  		GroupVersionKind: gvk.VirtualService,
  1491  		Name:             "acme",
  1492  	},
  1493  	Spec: &networking.VirtualService{
  1494  		Hosts:    []string{},
  1495  		Gateways: []string{"some-gateway"},
  1496  		Http: []*networking.HTTPRoute{
  1497  			{
  1498  				Name: "route 1",
  1499  				Match: []*networking.HTTPMatchRequest{
  1500  					{
  1501  						Name: "catch-all for 8080",
  1502  						Port: 8080,
  1503  					},
  1504  				},
  1505  				Route: []*networking.HTTPRouteDestination{
  1506  					{
  1507  						Destination: &networking.Destination{
  1508  							Host: "example1.default.svc.cluster.local",
  1509  							Port: &networking.PortSelector{
  1510  								Number: 8484,
  1511  							},
  1512  						},
  1513  					},
  1514  				},
  1515  			},
  1516  			{
  1517  				Name: "route 2",
  1518  				Match: []*networking.HTTPMatchRequest{
  1519  					{
  1520  						Name: "header match",
  1521  						Headers: map[string]*networking.StringMatch{
  1522  							"cookie": {
  1523  								MatchType: &networking.StringMatch_Exact{Exact: "canary"},
  1524  							},
  1525  						},
  1526  					},
  1527  				},
  1528  				Route: []*networking.HTTPRouteDestination{
  1529  					{
  1530  						Destination: &networking.Destination{
  1531  							Host: "example2.default.svc.cluster.local",
  1532  							Port: &networking.PortSelector{
  1533  								Number: 8484,
  1534  							},
  1535  						},
  1536  					},
  1537  				},
  1538  			},
  1539  			{
  1540  				Name: "route 3",
  1541  				Route: []*networking.HTTPRouteDestination{
  1542  					{
  1543  						Destination: &networking.Destination{
  1544  							Host: "example1.default.svc.cluster.local",
  1545  							Port: &networking.PortSelector{
  1546  								Number: 8484,
  1547  							},
  1548  						},
  1549  					},
  1550  				},
  1551  			},
  1552  		},
  1553  	},
  1554  }
  1555  
  1556  var virtualServiceWithWildcardHost = config.Config{
  1557  	Meta: config.Meta{
  1558  		GroupVersionKind: gvk.VirtualService,
  1559  		Name:             "wildcard",
  1560  	},
  1561  	Spec: &networking.VirtualService{
  1562  		Hosts: []string{"*.example.org"},
  1563  		Http: []*networking.HTTPRoute{
  1564  			{
  1565  				Match: []*networking.HTTPMatchRequest{
  1566  					{
  1567  						Name: "https",
  1568  						Port: uint32(8080),
  1569  					},
  1570  				},
  1571  				Route: []*networking.HTTPRouteDestination{
  1572  					{
  1573  						Destination: &networking.Destination{
  1574  							Host: "*.example.org",
  1575  							Port: &networking.PortSelector{
  1576  								Number: 8080,
  1577  							},
  1578  						},
  1579  					},
  1580  				},
  1581  			},
  1582  		},
  1583  	},
  1584  }
  1585  
  1586  var virtualServiceWithNestedWildcardHost = config.Config{
  1587  	Meta: config.Meta{
  1588  		GroupVersionKind: gvk.VirtualService,
  1589  		Name:             "nested-wildcard",
  1590  	},
  1591  	Spec: &networking.VirtualService{
  1592  		Hosts: []string{"*.hello.example.org"},
  1593  		Http: []*networking.HTTPRoute{
  1594  			{
  1595  				Match: []*networking.HTTPMatchRequest{
  1596  					{
  1597  						Name: "https",
  1598  						Port: uint32(8080),
  1599  					},
  1600  				},
  1601  				Route: []*networking.HTTPRouteDestination{
  1602  					{
  1603  						Destination: &networking.Destination{
  1604  							Host: "*.hello.example.org",
  1605  							Port: &networking.PortSelector{
  1606  								Number: 8080,
  1607  							},
  1608  						},
  1609  					},
  1610  				},
  1611  			},
  1612  		},
  1613  	},
  1614  }
  1615  
  1616  var virtualServiceWithGoogleWildcardHost = config.Config{
  1617  	Meta: config.Meta{
  1618  		GroupVersionKind: gvk.VirtualService,
  1619  		Name:             "google-wildcard",
  1620  	},
  1621  	Spec: &networking.VirtualService{
  1622  		Hosts: []string{"*.google.com"},
  1623  		Http: []*networking.HTTPRoute{
  1624  			{
  1625  				Match: []*networking.HTTPMatchRequest{
  1626  					{
  1627  						Uri: &networking.StringMatch{
  1628  							MatchType: &networking.StringMatch_Prefix{
  1629  								Prefix: "/",
  1630  							},
  1631  						},
  1632  					},
  1633  				},
  1634  				Route: []*networking.HTTPRouteDestination{
  1635  					{
  1636  						Destination: &networking.Destination{
  1637  							Host: "internal-google.default.svc.cluster.local",
  1638  						},
  1639  					},
  1640  				},
  1641  			},
  1642  		},
  1643  	},
  1644  }
  1645  
  1646  var virtualServiceWithCatchAllMultiPrefixRoute = config.Config{
  1647  	Meta: config.Meta{
  1648  		GroupVersionKind: gvk.VirtualService,
  1649  		Name:             "acme",
  1650  	},
  1651  	Spec: &networking.VirtualService{
  1652  		Hosts:    []string{},
  1653  		Gateways: []string{"some-gateway"},
  1654  		Http: []*networking.HTTPRoute{
  1655  			{
  1656  				Match: []*networking.HTTPMatchRequest{
  1657  					{
  1658  						Name: "catch-all",
  1659  						Uri: &networking.StringMatch{
  1660  							MatchType: &networking.StringMatch_Prefix{
  1661  								Prefix: "/",
  1662  							},
  1663  						},
  1664  						SourceLabels: map[string]string{
  1665  							"matchingNoSrc": "xxx",
  1666  						},
  1667  					},
  1668  					{
  1669  						Name: "specific match",
  1670  						Uri: &networking.StringMatch{
  1671  							MatchType: &networking.StringMatch_Prefix{
  1672  								Prefix: "/a",
  1673  							},
  1674  						},
  1675  					},
  1676  				},
  1677  				Route: []*networking.HTTPRouteDestination{
  1678  					{
  1679  						Destination: &networking.Destination{
  1680  							Host: "*.example.org",
  1681  							Port: &networking.PortSelector{
  1682  								Number: 8484,
  1683  							},
  1684  						},
  1685  						Weight: 100,
  1686  					},
  1687  				},
  1688  			},
  1689  		},
  1690  	},
  1691  }
  1692  
  1693  var virtualServiceWithCatchAllRouteWeightedDestination = config.Config{
  1694  	Meta: config.Meta{
  1695  		GroupVersionKind: gvk.VirtualService,
  1696  		Name:             "acme",
  1697  	},
  1698  	Spec: &networking.VirtualService{
  1699  		Hosts:    []string{"headers.test.istio.io"},
  1700  		Gateways: []string{"some-gateway"},
  1701  		Http: []*networking.HTTPRoute{
  1702  			{
  1703  				Match: []*networking.HTTPMatchRequest{
  1704  					{
  1705  						Name: "headers-only",
  1706  						Headers: map[string]*networking.StringMatch{
  1707  							"version": {
  1708  								MatchType: &networking.StringMatch_Exact{
  1709  									Exact: "v2",
  1710  								},
  1711  							},
  1712  						},
  1713  						SourceLabels: map[string]string{
  1714  							"version": "v1",
  1715  						},
  1716  					},
  1717  				},
  1718  				Route: []*networking.HTTPRouteDestination{
  1719  					{
  1720  						Destination: &networking.Destination{
  1721  							Host:   "c-weighted.extsvc.com",
  1722  							Subset: "v2",
  1723  						},
  1724  						Weight: 100,
  1725  					},
  1726  				},
  1727  			},
  1728  			{
  1729  				Route: []*networking.HTTPRouteDestination{
  1730  					{
  1731  						Destination: &networking.Destination{
  1732  							Host:   "c-weighted.extsvc.com",
  1733  							Subset: "v1",
  1734  						},
  1735  						Weight: 100,
  1736  					},
  1737  				},
  1738  			},
  1739  		},
  1740  	},
  1741  }
  1742  
  1743  var virtualServiceWithHeaderOperationsForSingleCluster = config.Config{
  1744  	Meta: config.Meta{
  1745  		GroupVersionKind: gvk.VirtualService,
  1746  		Name:             "acme",
  1747  	},
  1748  	Spec: &networking.VirtualService{
  1749  		Hosts:    []string{"headers.test.istio.io"},
  1750  		Gateways: []string{"some-gateway"},
  1751  		Http: []*networking.HTTPRoute{
  1752  			{
  1753  				Route: []*networking.HTTPRouteDestination{
  1754  					{
  1755  						Destination: &networking.Destination{
  1756  							Host:   "c-weighted.extsvc.com",
  1757  							Subset: "v1",
  1758  						},
  1759  						Headers: &networking.Headers{
  1760  							Request: &networking.Headers_HeaderOperations{
  1761  								Set:    map[string]string{"x-route-req-set": "v1", ":authority": "internal.foo.extsvc.com"},
  1762  								Add:    map[string]string{"x-route-req-add": "v2", ":authority": "internal.bar.extsvc.com"},
  1763  								Remove: []string{"x-route-req-remove"},
  1764  							},
  1765  							Response: &networking.Headers_HeaderOperations{
  1766  								Set:    map[string]string{"x-route-resp-set": "v1"},
  1767  								Add:    map[string]string{"x-route-resp-add": "v2"},
  1768  								Remove: []string{"x-route-resp-remove"},
  1769  							},
  1770  						},
  1771  						Weight: 100,
  1772  					},
  1773  				},
  1774  				Headers: &networking.Headers{
  1775  					Request: &networking.Headers_HeaderOperations{
  1776  						Set:    map[string]string{"x-req-set": "v1", ":authority": "foo.extsvc.com"},
  1777  						Add:    map[string]string{"x-req-add": "v2", ":authority": "bar.extsvc.com"},
  1778  						Remove: []string{"x-req-remove"},
  1779  					},
  1780  					Response: &networking.Headers_HeaderOperations{
  1781  						Set:    map[string]string{"x-resp-set": "v1"},
  1782  						Add:    map[string]string{"x-resp-add": "v2"},
  1783  						Remove: []string{"x-resp-remove"},
  1784  					},
  1785  				},
  1786  			},
  1787  		},
  1788  	},
  1789  }
  1790  
  1791  var virtualServiceWithHeaderOperationsForWeightedCluster = config.Config{
  1792  	Meta: config.Meta{
  1793  		GroupVersionKind: gvk.VirtualService,
  1794  		Name:             "acme",
  1795  	},
  1796  	Spec: &networking.VirtualService{
  1797  		Hosts:    []string{"headers.test.istio.io"},
  1798  		Gateways: []string{"some-gateway"},
  1799  		Http: []*networking.HTTPRoute{
  1800  			{
  1801  				Route: []*networking.HTTPRouteDestination{
  1802  					{
  1803  						Destination: &networking.Destination{
  1804  							Host:   "c-weighted.extsvc.com",
  1805  							Subset: "blue",
  1806  						},
  1807  						Headers: &networking.Headers{
  1808  							Request: &networking.Headers_HeaderOperations{
  1809  								Set:    map[string]string{"x-route-req-set-blue": "v1", ":authority": "blue.foo.extsvc.com"},
  1810  								Add:    map[string]string{"x-route-req-add-blue": "v2", ":authority": "blue.bar.extsvc.com"},
  1811  								Remove: []string{"x-route-req-remove-blue"},
  1812  							},
  1813  							Response: &networking.Headers_HeaderOperations{
  1814  								Set:    map[string]string{"x-route-resp-set-blue": "v1"},
  1815  								Add:    map[string]string{"x-route-resp-add-blue": "v2"},
  1816  								Remove: []string{"x-route-resp-remove-blue"},
  1817  							},
  1818  						},
  1819  						Weight: 9,
  1820  					},
  1821  					{
  1822  						Destination: &networking.Destination{
  1823  							Host:   "c-weighted.extsvc.com",
  1824  							Subset: "green",
  1825  						},
  1826  						Headers: &networking.Headers{
  1827  							Request: &networking.Headers_HeaderOperations{
  1828  								Set:    map[string]string{"x-route-req-set-green": "v1", ":authority": "green.foo.extsvc.com"},
  1829  								Add:    map[string]string{"x-route-req-add-green": "v2", ":authority": "green.bar.extsvc.com"},
  1830  								Remove: []string{"x-route-req-remove-green"},
  1831  							},
  1832  							Response: &networking.Headers_HeaderOperations{
  1833  								Set:    map[string]string{"x-route-resp-set-green": "v1"},
  1834  								Add:    map[string]string{"x-route-resp-add-green": "v2"},
  1835  								Remove: []string{"x-route-resp-remove-green"},
  1836  							},
  1837  						},
  1838  						Weight: 1,
  1839  					},
  1840  				},
  1841  				Headers: &networking.Headers{
  1842  					Request: &networking.Headers_HeaderOperations{
  1843  						Set:    map[string]string{"x-req-set": "v1", ":authority": "foo.extsvc.com"},
  1844  						Add:    map[string]string{"x-req-add": "v2", ":authority": "bar.extsvc.com"},
  1845  						Remove: []string{"x-req-remove"},
  1846  					},
  1847  					Response: &networking.Headers_HeaderOperations{
  1848  						Set:    map[string]string{"x-resp-set": "v1"},
  1849  						Add:    map[string]string{"x-resp-add": "v2"},
  1850  						Remove: []string{"x-resp-remove"},
  1851  					},
  1852  				},
  1853  			},
  1854  		},
  1855  	},
  1856  }
  1857  
  1858  var virtualServiceWithRedirect = config.Config{
  1859  	Meta: config.Meta{
  1860  		GroupVersionKind: gvk.VirtualService,
  1861  		Name:             "acme",
  1862  	},
  1863  	Spec: &networking.VirtualService{
  1864  		Hosts:    []string{},
  1865  		Gateways: []string{"some-gateway"},
  1866  		Http: []*networking.HTTPRoute{
  1867  			{
  1868  				Redirect: &networking.HTTPRedirect{
  1869  					Uri:          "example.org",
  1870  					Authority:    "some-authority.default.svc.cluster.local",
  1871  					RedirectCode: 308,
  1872  				},
  1873  			},
  1874  		},
  1875  	},
  1876  }
  1877  
  1878  var virtualServiceWithRedirectPathPrefix = config.Config{
  1879  	Meta: config.Meta{
  1880  		GroupVersionKind: gvk.VirtualService,
  1881  		Name:             "acme",
  1882  		Annotations: map[string]string{
  1883  			"internal.istio.io/route-semantics": "gateway",
  1884  		},
  1885  	},
  1886  	Spec: &networking.VirtualService{
  1887  		Hosts:    []string{},
  1888  		Gateways: []string{"some-gateway"},
  1889  		Http: []*networking.HTTPRoute{
  1890  			{
  1891  				Redirect: &networking.HTTPRedirect{
  1892  					Uri:          "%PREFIX()%/replace-prefix",
  1893  					Authority:    "some-authority.default.svc.cluster.local",
  1894  					RedirectCode: 308,
  1895  				},
  1896  			},
  1897  		},
  1898  	},
  1899  }
  1900  
  1901  var virtualServiceWithRedirectPathPrefixNoGatewaySematics = config.Config{
  1902  	Meta: config.Meta{
  1903  		GroupVersionKind: gvk.VirtualService,
  1904  		Name:             "acme",
  1905  	},
  1906  	Spec: &networking.VirtualService{
  1907  		Hosts:    []string{},
  1908  		Gateways: []string{"some-gateway"},
  1909  		Http: []*networking.HTTPRoute{
  1910  			{
  1911  				Redirect: &networking.HTTPRedirect{
  1912  					Uri:          "%PREFIX()%/replace-full",
  1913  					Authority:    "some-authority.default.svc.cluster.local",
  1914  					RedirectCode: 308,
  1915  				},
  1916  			},
  1917  		},
  1918  	},
  1919  }
  1920  
  1921  var virtualServiceWithRedirectFullPath = config.Config{
  1922  	Meta: config.Meta{
  1923  		GroupVersionKind: gvk.VirtualService,
  1924  		Name:             "acme",
  1925  	},
  1926  	Spec: &networking.VirtualService{
  1927  		Hosts:    []string{},
  1928  		Gateways: []string{"some-gateway"},
  1929  		Http: []*networking.HTTPRoute{
  1930  			{
  1931  				Redirect: &networking.HTTPRedirect{
  1932  					Uri:          "/replace-full-path",
  1933  					Authority:    "some-authority.default.svc.cluster.local",
  1934  					RedirectCode: 308,
  1935  				},
  1936  			},
  1937  		},
  1938  	},
  1939  }
  1940  
  1941  var virtualServiceWithRewriteHost = config.Config{
  1942  	Meta: config.Meta{
  1943  		GroupVersionKind: gvk.VirtualService,
  1944  		Name:             "acme",
  1945  		Annotations: map[string]string{
  1946  			"internal.istio.io/route-semantics": "gateway",
  1947  		},
  1948  	},
  1949  	Spec: &networking.VirtualService{
  1950  		Hosts:    []string{},
  1951  		Gateways: []string{"some-gateway"},
  1952  		Http: []*networking.HTTPRoute{
  1953  			{
  1954  				Match: []*networking.HTTPMatchRequest{
  1955  					{
  1956  						Name: "host-rewrite",
  1957  					},
  1958  				},
  1959  				Rewrite: &networking.HTTPRewrite{
  1960  					Authority: "bar.example.org",
  1961  				},
  1962  				Route: []*networking.HTTPRouteDestination{
  1963  					{
  1964  						Destination: &networking.Destination{
  1965  							Host: "foo.example.org",
  1966  						},
  1967  						Weight: 100,
  1968  					},
  1969  				},
  1970  			},
  1971  		},
  1972  	},
  1973  }
  1974  
  1975  var virtualServiceWithRewritePrefixPath = config.Config{
  1976  	Meta: config.Meta{
  1977  		GroupVersionKind: gvk.VirtualService,
  1978  		Name:             "acme",
  1979  		Annotations: map[string]string{
  1980  			"internal.istio.io/route-semantics": "gateway",
  1981  		},
  1982  	},
  1983  	Spec: &networking.VirtualService{
  1984  		Hosts:    []string{},
  1985  		Gateways: []string{"some-gateway"},
  1986  		Http: []*networking.HTTPRoute{
  1987  			{
  1988  				Match: []*networking.HTTPMatchRequest{
  1989  					{
  1990  						Name: "prefix-path-rewrite",
  1991  					},
  1992  				},
  1993  				Rewrite: &networking.HTTPRewrite{
  1994  					Uri: "/replace-prefix",
  1995  				},
  1996  				Route: []*networking.HTTPRouteDestination{
  1997  					{
  1998  						Destination: &networking.Destination{
  1999  							Host: "foo.example.org",
  2000  						},
  2001  						Weight: 100,
  2002  					},
  2003  				},
  2004  			},
  2005  		},
  2006  	},
  2007  }
  2008  
  2009  var virtualServiceWithEmptyRewritePrefixPath = config.Config{
  2010  	Meta: config.Meta{
  2011  		GroupVersionKind: gvk.VirtualService,
  2012  		Name:             "acme",
  2013  		Annotations: map[string]string{
  2014  			"internal.istio.io/route-semantics": "gateway",
  2015  		},
  2016  	},
  2017  	Spec: &networking.VirtualService{
  2018  		Hosts:    []string{},
  2019  		Gateways: []string{"some-gateway"},
  2020  		Http: []*networking.HTTPRoute{
  2021  			{
  2022  				Match: []*networking.HTTPMatchRequest{
  2023  					{
  2024  						Name: "prefix-path-rewrite",
  2025  						Uri: &networking.StringMatch{
  2026  							MatchType: &networking.StringMatch_Prefix{Prefix: "/prefix-to-be-removed"},
  2027  						},
  2028  					},
  2029  				},
  2030  				Rewrite: &networking.HTTPRewrite{
  2031  					Uri: "/",
  2032  				},
  2033  				Route: []*networking.HTTPRouteDestination{
  2034  					{
  2035  						Destination: &networking.Destination{
  2036  							Host: "foo.example.org",
  2037  						},
  2038  						Weight: 100,
  2039  					},
  2040  				},
  2041  			},
  2042  		},
  2043  	},
  2044  }
  2045  
  2046  var virtualServiceWithRewriteFullPath = config.Config{
  2047  	Meta: config.Meta{
  2048  		GroupVersionKind: gvk.VirtualService,
  2049  		Name:             "acme",
  2050  		Annotations: map[string]string{
  2051  			"internal.istio.io/route-semantics": "gateway",
  2052  		},
  2053  	},
  2054  	Spec: &networking.VirtualService{
  2055  		Hosts:    []string{},
  2056  		Gateways: []string{"some-gateway"},
  2057  		Http: []*networking.HTTPRoute{
  2058  			{
  2059  				Match: []*networking.HTTPMatchRequest{
  2060  					{
  2061  						Name: "full-path-rewrite",
  2062  					},
  2063  				},
  2064  				Rewrite: &networking.HTTPRewrite{
  2065  					UriRegexRewrite: &networking.RegexRewrite{
  2066  						Match:   "/.*",
  2067  						Rewrite: "/replace-full",
  2068  					},
  2069  				},
  2070  				Route: []*networking.HTTPRouteDestination{
  2071  					{
  2072  						Destination: &networking.Destination{
  2073  							Host: "foo.example.org",
  2074  						},
  2075  						Weight: 100,
  2076  					},
  2077  				},
  2078  			},
  2079  		},
  2080  	},
  2081  }
  2082  
  2083  var virtualServiceWithRewriteFullPathAndHost = config.Config{
  2084  	Meta: config.Meta{
  2085  		GroupVersionKind: gvk.VirtualService,
  2086  		Name:             "acme",
  2087  		Annotations: map[string]string{
  2088  			"internal.istio.io/route-semantics": "gateway",
  2089  		},
  2090  	},
  2091  	Spec: &networking.VirtualService{
  2092  		Hosts:    []string{},
  2093  		Gateways: []string{"some-gateway"},
  2094  		Http: []*networking.HTTPRoute{
  2095  			{
  2096  				Match: []*networking.HTTPMatchRequest{
  2097  					{
  2098  						Name: "full-path-and-host-rewrite",
  2099  					},
  2100  				},
  2101  				Rewrite: &networking.HTTPRewrite{
  2102  					UriRegexRewrite: &networking.RegexRewrite{
  2103  						Match:   "/.*",
  2104  						Rewrite: "/replace-full",
  2105  					},
  2106  					Authority: "bar.example.org",
  2107  				},
  2108  				Route: []*networking.HTTPRouteDestination{
  2109  					{
  2110  						Destination: &networking.Destination{
  2111  							Host: "foo.example.org",
  2112  						},
  2113  						Weight: 100,
  2114  					},
  2115  				},
  2116  			},
  2117  		},
  2118  	},
  2119  }
  2120  
  2121  var virtualServiceWithPathRegexMatchRegexRewrite = config.Config{
  2122  	Meta: config.Meta{
  2123  		GroupVersionKind: gvk.VirtualService,
  2124  		Name:             "acme",
  2125  		Annotations: map[string]string{
  2126  			"internal.istio.io/route-semantics": "gateway",
  2127  		},
  2128  	},
  2129  	Spec: &networking.VirtualService{
  2130  		Hosts:    []string{},
  2131  		Gateways: []string{"some-gateway"},
  2132  		Http: []*networking.HTTPRoute{
  2133  			{
  2134  				Match: []*networking.HTTPMatchRequest{
  2135  					{
  2136  						Name: "full-path-and-host-rewrite",
  2137  						Uri: &networking.StringMatch{
  2138  							MatchType: &networking.StringMatch_Regex{
  2139  								Regex: "^/service/[^/]+/.*$",
  2140  							},
  2141  						},
  2142  					},
  2143  				},
  2144  				Rewrite: &networking.HTTPRewrite{
  2145  					UriRegexRewrite: &networking.RegexRewrite{
  2146  						Match:   "^/service/([^/]+)(/.*)$",
  2147  						Rewrite: "\\2/instance/\\1",
  2148  					},
  2149  				},
  2150  				Route: []*networking.HTTPRouteDestination{
  2151  					{
  2152  						Destination: &networking.Destination{
  2153  							Host: "foo.example.org",
  2154  						},
  2155  						Weight: 100,
  2156  					},
  2157  				},
  2158  			},
  2159  		},
  2160  	},
  2161  }
  2162  
  2163  var virtualServiceWithRedirectAndSetHeader = config.Config{
  2164  	Meta: config.Meta{
  2165  		GroupVersionKind: gvk.VirtualService,
  2166  		Name:             "acme",
  2167  	},
  2168  	Spec: &networking.VirtualService{
  2169  		Hosts:    []string{},
  2170  		Gateways: []string{"some-gateway"},
  2171  		Http: []*networking.HTTPRoute{
  2172  			{
  2173  				Redirect: &networking.HTTPRedirect{
  2174  					Uri:          "example.org",
  2175  					Authority:    "some-authority.default.svc.cluster.local",
  2176  					RedirectCode: 308,
  2177  				},
  2178  				Headers: &networking.Headers{
  2179  					Response: &networking.Headers_HeaderOperations{
  2180  						Set: map[string]string{
  2181  							"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
  2182  						},
  2183  					},
  2184  				},
  2185  			},
  2186  		},
  2187  	},
  2188  }
  2189  
  2190  var virtualServiceWithDirectResponse = config.Config{
  2191  	Meta: config.Meta{
  2192  		GroupVersionKind: gvk.VirtualService,
  2193  		Name:             "acme",
  2194  	},
  2195  	Spec: &networking.VirtualService{
  2196  		Hosts:    []string{},
  2197  		Gateways: []string{"some-gateway"},
  2198  		Http: []*networking.HTTPRoute{
  2199  			{
  2200  				DirectResponse: &networking.HTTPDirectResponse{
  2201  					Status: 200,
  2202  					Body: &networking.HTTPBody{
  2203  						Specifier: &networking.HTTPBody_String_{String_: "hello"},
  2204  					},
  2205  				},
  2206  			},
  2207  		},
  2208  	},
  2209  }
  2210  
  2211  var virtualServiceWithDirectResponseAndSetHeader = config.Config{
  2212  	Meta: config.Meta{
  2213  		GroupVersionKind: gvk.VirtualService,
  2214  		Name:             "acme",
  2215  	},
  2216  	Spec: &networking.VirtualService{
  2217  		Hosts:    []string{},
  2218  		Gateways: []string{"some-gateway"},
  2219  		Http: []*networking.HTTPRoute{
  2220  			{
  2221  				DirectResponse: &networking.HTTPDirectResponse{
  2222  					Status: 200,
  2223  					Body: &networking.HTTPBody{
  2224  						Specifier: &networking.HTTPBody_String_{String_: "hello"},
  2225  					},
  2226  				},
  2227  				Headers: &networking.Headers{
  2228  					Response: &networking.Headers_HeaderOperations{
  2229  						Set: map[string]string{
  2230  							"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
  2231  						},
  2232  					},
  2233  				},
  2234  			},
  2235  		},
  2236  	},
  2237  }
  2238  
  2239  var virtualServiceWithRegexMatchingOnURI = config.Config{
  2240  	Meta: config.Meta{
  2241  		GroupVersionKind: gvk.VirtualService,
  2242  		Name:             "acme",
  2243  	},
  2244  	Spec: &networking.VirtualService{
  2245  		Hosts:    []string{},
  2246  		Gateways: []string{"some-gateway"},
  2247  		Http: []*networking.HTTPRoute{
  2248  			{
  2249  				Match: []*networking.HTTPMatchRequest{
  2250  					{
  2251  						Name: "status",
  2252  						Uri: &networking.StringMatch{
  2253  							MatchType: &networking.StringMatch_Regex{
  2254  								Regex: "\\/(.?)\\/status",
  2255  							},
  2256  						},
  2257  					},
  2258  				},
  2259  				Redirect: &networking.HTTPRedirect{
  2260  					Uri:          "example.org",
  2261  					Authority:    "some-authority.default.svc.cluster.local",
  2262  					RedirectCode: 308,
  2263  				},
  2264  			},
  2265  		},
  2266  	},
  2267  }
  2268  
  2269  var virtualServiceWithExactMatchingOnHeaderForJWTClaims = config.Config{
  2270  	Meta: config.Meta{
  2271  		GroupVersionKind: gvk.VirtualService,
  2272  		Name:             "acme",
  2273  	},
  2274  	Spec: &networking.VirtualService{
  2275  		Hosts:    []string{},
  2276  		Gateways: []string{"some-gateway"},
  2277  		Http: []*networking.HTTPRoute{
  2278  			{
  2279  				Match: []*networking.HTTPMatchRequest{
  2280  					{
  2281  						Name: "auth",
  2282  						Headers: map[string]*networking.StringMatch{
  2283  							"@request.auth.claims.Foo": {
  2284  								MatchType: &networking.StringMatch_Exact{
  2285  									Exact: "Bar",
  2286  								},
  2287  							},
  2288  						},
  2289  						WithoutHeaders: map[string]*networking.StringMatch{
  2290  							"@request.auth.claims.Bla": {
  2291  								MatchType: &networking.StringMatch_Exact{
  2292  									Exact: "Bar",
  2293  								},
  2294  							},
  2295  						},
  2296  					},
  2297  				},
  2298  				Redirect: &networking.HTTPRedirect{
  2299  					Uri:          "example.org",
  2300  					Authority:    "some-authority.default.svc.cluster.local",
  2301  					RedirectCode: 308,
  2302  				},
  2303  			},
  2304  		},
  2305  	},
  2306  }
  2307  
  2308  var virtualServiceWithRegexMatchingOnHeader = config.Config{
  2309  	Meta: config.Meta{
  2310  		GroupVersionKind: gvk.VirtualService,
  2311  		Name:             "acme",
  2312  	},
  2313  	Spec: &networking.VirtualService{
  2314  		Hosts:    []string{},
  2315  		Gateways: []string{"some-gateway"},
  2316  		Http: []*networking.HTTPRoute{
  2317  			{
  2318  				Match: []*networking.HTTPMatchRequest{
  2319  					{
  2320  						Name: "auth",
  2321  						Headers: map[string]*networking.StringMatch{
  2322  							"Authentication": {
  2323  								MatchType: &networking.StringMatch_Regex{
  2324  									Regex: "Bearer .+?\\..+?\\..+?",
  2325  								},
  2326  							},
  2327  						},
  2328  					},
  2329  				},
  2330  				Redirect: &networking.HTTPRedirect{
  2331  					Uri:          "example.org",
  2332  					Authority:    "some-authority.default.svc.cluster.local",
  2333  					RedirectCode: 308,
  2334  				},
  2335  			},
  2336  		},
  2337  	},
  2338  }
  2339  
  2340  func createVirtualServiceWithRegexMatchingForAllCasesOnHeader() []*config.Config {
  2341  	ret := []*config.Config{}
  2342  	regex := "*"
  2343  	ret = append(ret, &config.Config{
  2344  		Meta: config.Meta{
  2345  			GroupVersionKind: gvk.VirtualService,
  2346  			Name:             "acme",
  2347  		},
  2348  		Spec: &networking.VirtualService{
  2349  			Hosts:    []string{},
  2350  			Gateways: []string{"some-gateway"},
  2351  			Http: []*networking.HTTPRoute{
  2352  				{
  2353  					Match: []*networking.HTTPMatchRequest{
  2354  						{
  2355  							Name: "presence",
  2356  							Headers: map[string]*networking.StringMatch{
  2357  								"FOO-HEADER": {
  2358  									MatchType: &networking.StringMatch_Regex{
  2359  										Regex: regex,
  2360  									},
  2361  								},
  2362  							},
  2363  						},
  2364  					},
  2365  					Redirect: &networking.HTTPRedirect{
  2366  						Uri:          "example.org",
  2367  						Authority:    "some-authority.default.svc.cluster.local",
  2368  						RedirectCode: 308,
  2369  					},
  2370  				},
  2371  			},
  2372  		},
  2373  	})
  2374  
  2375  	return ret
  2376  }
  2377  
  2378  var virtualServiceWithRegexMatchingOnWithoutHeader = config.Config{
  2379  	Meta: config.Meta{
  2380  		GroupVersionKind: gvk.VirtualService,
  2381  		Name:             "acme",
  2382  	},
  2383  	Spec: &networking.VirtualService{
  2384  		Hosts:    []string{},
  2385  		Gateways: []string{"some-gateway"},
  2386  		Http: []*networking.HTTPRoute{
  2387  			{
  2388  				Match: []*networking.HTTPMatchRequest{
  2389  					{
  2390  						Name: "without-test",
  2391  						WithoutHeaders: map[string]*networking.StringMatch{
  2392  							"FOO-HEADER": {
  2393  								MatchType: &networking.StringMatch_Regex{
  2394  									Regex: "BAR .+?\\..+?\\..+?",
  2395  								},
  2396  							},
  2397  						},
  2398  					},
  2399  				},
  2400  				Redirect: &networking.HTTPRedirect{
  2401  					Uri:          "example.org",
  2402  					Authority:    "some-authority.default.svc.cluster.local",
  2403  					RedirectCode: 308,
  2404  				},
  2405  			},
  2406  		},
  2407  	},
  2408  }
  2409  
  2410  var virtualServiceWithPresentMatchingOnHeader = config.Config{
  2411  	Meta: config.Meta{
  2412  		GroupVersionKind: gvk.VirtualService,
  2413  		Name:             "acme",
  2414  	},
  2415  	Spec: &networking.VirtualService{
  2416  		Hosts:    []string{},
  2417  		Gateways: []string{"some-gateway"},
  2418  		Http: []*networking.HTTPRoute{
  2419  			{
  2420  				Match: []*networking.HTTPMatchRequest{
  2421  					{
  2422  						Name: "presence",
  2423  						Headers: map[string]*networking.StringMatch{
  2424  							"FOO-HEADER": nil,
  2425  						},
  2426  					},
  2427  				},
  2428  				Redirect: &networking.HTTPRedirect{
  2429  					Uri:          "example.org",
  2430  					Authority:    "some-authority.default.svc.cluster.local",
  2431  					RedirectCode: 308,
  2432  				},
  2433  			},
  2434  		},
  2435  	},
  2436  }
  2437  
  2438  var virtualServiceWithPresentMatchingOnHeader2 = config.Config{
  2439  	Meta: config.Meta{
  2440  		GroupVersionKind: gvk.VirtualService,
  2441  		Name:             "acme",
  2442  	},
  2443  	Spec: &networking.VirtualService{
  2444  		Hosts:    []string{},
  2445  		Gateways: []string{"some-gateway"},
  2446  		Http: []*networking.HTTPRoute{
  2447  			{
  2448  				Match: []*networking.HTTPMatchRequest{
  2449  					{
  2450  						Name: "presence",
  2451  						Headers: map[string]*networking.StringMatch{
  2452  							"FOO-HEADER": {},
  2453  						},
  2454  					},
  2455  				},
  2456  				Redirect: &networking.HTTPRedirect{
  2457  					Uri:          "example.org",
  2458  					Authority:    "some-authority.default.svc.cluster.local",
  2459  					RedirectCode: 308,
  2460  				},
  2461  			},
  2462  		},
  2463  	},
  2464  }
  2465  
  2466  var virtualServiceWithPresentMatchingOnWithoutHeader = config.Config{
  2467  	Meta: config.Meta{
  2468  		GroupVersionKind: gvk.VirtualService,
  2469  		Name:             "acme",
  2470  	},
  2471  	Spec: &networking.VirtualService{
  2472  		Hosts:    []string{},
  2473  		Gateways: []string{"some-gateway"},
  2474  		Http: []*networking.HTTPRoute{
  2475  			{
  2476  				Match: []*networking.HTTPMatchRequest{
  2477  					{
  2478  						Name: "presence",
  2479  						WithoutHeaders: map[string]*networking.StringMatch{
  2480  							"FOO-HEADER": nil,
  2481  						},
  2482  					},
  2483  				},
  2484  				Redirect: &networking.HTTPRedirect{
  2485  					Uri:          "example.org",
  2486  					Authority:    "some-authority.default.svc.cluster.local",
  2487  					RedirectCode: 308,
  2488  				},
  2489  			},
  2490  		},
  2491  	},
  2492  }
  2493  
  2494  var virtualServiceWithExactMatchingOnQueryParameter = config.Config{
  2495  	Meta: config.Meta{
  2496  		GroupVersionKind: gvk.VirtualService,
  2497  		Name:             "acme",
  2498  	},
  2499  	Spec: &networking.VirtualService{
  2500  		Hosts:    []string{},
  2501  		Gateways: []string{"some-gateway"},
  2502  		Http: []*networking.HTTPRoute{
  2503  			{
  2504  				Match: []*networking.HTTPMatchRequest{
  2505  					{
  2506  						Name: "auth",
  2507  						QueryParams: map[string]*networking.StringMatch{
  2508  							"token": {
  2509  								MatchType: &networking.StringMatch_Exact{
  2510  									Exact: "foo",
  2511  								},
  2512  							},
  2513  						},
  2514  					},
  2515  				},
  2516  				Redirect: &networking.HTTPRedirect{
  2517  					Uri:          "example.org",
  2518  					Authority:    "some-authority.default.svc.cluster.local",
  2519  					RedirectCode: 308,
  2520  				},
  2521  			},
  2522  		},
  2523  	},
  2524  }
  2525  
  2526  var virtualServiceWithPrefixMatchingOnQueryParameter = config.Config{
  2527  	Meta: config.Meta{
  2528  		GroupVersionKind: gvk.VirtualService,
  2529  		Name:             "acme",
  2530  	},
  2531  	Spec: &networking.VirtualService{
  2532  		Hosts:    []string{},
  2533  		Gateways: []string{"some-gateway"},
  2534  		Http: []*networking.HTTPRoute{
  2535  			{
  2536  				Match: []*networking.HTTPMatchRequest{
  2537  					{
  2538  						Name: "auth",
  2539  						QueryParams: map[string]*networking.StringMatch{
  2540  							"token": {
  2541  								MatchType: &networking.StringMatch_Prefix{
  2542  									Prefix: "foo-",
  2543  								},
  2544  							},
  2545  						},
  2546  					},
  2547  				},
  2548  				Redirect: &networking.HTTPRedirect{
  2549  					Uri:          "example.org",
  2550  					Authority:    "some-authority.default.svc.cluster.local",
  2551  					RedirectCode: 308,
  2552  				},
  2553  			},
  2554  		},
  2555  	},
  2556  }
  2557  
  2558  var virtualServiceWithRegexMatchingOnQueryParameter = config.Config{
  2559  	Meta: config.Meta{
  2560  		GroupVersionKind: gvk.VirtualService,
  2561  		Name:             "acme",
  2562  	},
  2563  	Spec: &networking.VirtualService{
  2564  		Hosts:    []string{},
  2565  		Gateways: []string{"some-gateway"},
  2566  		Http: []*networking.HTTPRoute{
  2567  			{
  2568  				Match: []*networking.HTTPMatchRequest{
  2569  					{
  2570  						Name: "auth",
  2571  						QueryParams: map[string]*networking.StringMatch{
  2572  							"token": {
  2573  								MatchType: &networking.StringMatch_Regex{
  2574  									Regex: "BAR .+?\\..+?\\..+?",
  2575  								},
  2576  							},
  2577  						},
  2578  					},
  2579  				},
  2580  				Redirect: &networking.HTTPRedirect{
  2581  					Uri:          "example.org",
  2582  					Authority:    "some-authority.default.svc.cluster.local",
  2583  					RedirectCode: 308,
  2584  				},
  2585  			},
  2586  		},
  2587  	},
  2588  }
  2589  
  2590  func createVirtualServiceWithRegexMatchingForAllCasesOnQueryParameter() []*config.Config {
  2591  	ret := []*config.Config{}
  2592  	regex := "*"
  2593  	ret = append(ret, &config.Config{
  2594  		Meta: config.Meta{
  2595  			GroupVersionKind: gvk.VirtualService,
  2596  			Name:             "acme",
  2597  		},
  2598  		Spec: &networking.VirtualService{
  2599  			Hosts:    []string{},
  2600  			Gateways: []string{"some-gateway"},
  2601  			Http: []*networking.HTTPRoute{
  2602  				{
  2603  					Match: []*networking.HTTPMatchRequest{
  2604  						{
  2605  							Name: "presence",
  2606  							QueryParams: map[string]*networking.StringMatch{
  2607  								"token": {
  2608  									MatchType: &networking.StringMatch_Regex{
  2609  										Regex: regex,
  2610  									},
  2611  								},
  2612  							},
  2613  						},
  2614  					},
  2615  					Redirect: &networking.HTTPRedirect{
  2616  						Uri:          "example.org",
  2617  						Authority:    "some-authority.default.svc.cluster.local",
  2618  						RedirectCode: 308,
  2619  					},
  2620  				},
  2621  			},
  2622  		},
  2623  	})
  2624  
  2625  	return ret
  2626  }
  2627  
  2628  var virtualServiceMatchingOnSourceNamespace = config.Config{
  2629  	Meta: config.Meta{
  2630  		GroupVersionKind: gvk.VirtualService,
  2631  		Name:             "acme",
  2632  	},
  2633  	Spec: &networking.VirtualService{
  2634  		Hosts: []string{},
  2635  		Http: []*networking.HTTPRoute{
  2636  			{
  2637  				Name: "foo",
  2638  				Match: []*networking.HTTPMatchRequest{
  2639  					{
  2640  						SourceNamespace: "foo",
  2641  					},
  2642  				},
  2643  				Route: []*networking.HTTPRouteDestination{
  2644  					{
  2645  						Destination: &networking.Destination{
  2646  							Host: "foo.example.org",
  2647  							Port: &networking.PortSelector{
  2648  								Number: 8484,
  2649  							},
  2650  						},
  2651  						Weight: 100,
  2652  					},
  2653  				},
  2654  			},
  2655  			{
  2656  				Name: "bar",
  2657  				Match: []*networking.HTTPMatchRequest{
  2658  					{
  2659  						SourceNamespace: "bar",
  2660  					},
  2661  				},
  2662  				Route: []*networking.HTTPRouteDestination{
  2663  					{
  2664  						Destination: &networking.Destination{
  2665  							Host: "bar.example.org",
  2666  							Port: &networking.PortSelector{
  2667  								Number: 8484,
  2668  							},
  2669  						},
  2670  						Weight: 100,
  2671  					},
  2672  				},
  2673  			},
  2674  		},
  2675  	},
  2676  }
  2677  
  2678  var virtualServiceWithStatPrefix = config.Config{
  2679  	Meta: config.Meta{
  2680  		GroupVersionKind: gvk.VirtualService,
  2681  		Name:             "acme",
  2682  	},
  2683  	Spec: &networking.VirtualService{
  2684  		Hosts: []string{},
  2685  		Http: []*networking.HTTPRoute{
  2686  			{
  2687  				Name: "foo",
  2688  				Match: []*networking.HTTPMatchRequest{
  2689  					{
  2690  						Name: "foo",
  2691  						Uri: &networking.StringMatch{
  2692  							MatchType: &networking.StringMatch_Prefix{
  2693  								Prefix: "/foo",
  2694  							},
  2695  						},
  2696  						StatPrefix: "foo",
  2697  					},
  2698  					{
  2699  						Name: "baz",
  2700  						Uri: &networking.StringMatch{
  2701  							MatchType: &networking.StringMatch_Prefix{
  2702  								Prefix: "/baz",
  2703  							},
  2704  						},
  2705  					},
  2706  				},
  2707  				Route: []*networking.HTTPRouteDestination{
  2708  					{
  2709  						Destination: &networking.Destination{
  2710  							Host: "foo.example.org",
  2711  							Port: &networking.PortSelector{
  2712  								Number: 8484,
  2713  							},
  2714  						},
  2715  						Weight: 100,
  2716  					},
  2717  				},
  2718  			},
  2719  			{
  2720  				Name: "bar",
  2721  				Match: []*networking.HTTPMatchRequest{
  2722  					{
  2723  						Name: "bar",
  2724  						Uri: &networking.StringMatch{
  2725  							MatchType: &networking.StringMatch_Prefix{
  2726  								Prefix: "/bar",
  2727  							},
  2728  						},
  2729  					},
  2730  				},
  2731  				Route: []*networking.HTTPRouteDestination{
  2732  					{
  2733  						Destination: &networking.Destination{
  2734  							Host: "bar.example.org",
  2735  							Port: &networking.PortSelector{
  2736  								Number: 8484,
  2737  							},
  2738  						},
  2739  						Weight: 100,
  2740  					},
  2741  				},
  2742  			},
  2743  		},
  2744  	},
  2745  }
  2746  
  2747  var portLevelDestinationRule = &networking.DestinationRule{
  2748  	Host:    "*.example.org",
  2749  	Subsets: []*networking.Subset{},
  2750  	TrafficPolicy: &networking.TrafficPolicy{
  2751  		PortLevelSettings: []*networking.TrafficPolicy_PortTrafficPolicy{
  2752  			{
  2753  				LoadBalancer: &networking.LoadBalancerSettings{
  2754  					LbPolicy: loadBalancerPolicy("hash-cookie"),
  2755  				},
  2756  				Port: &networking.PortSelector{
  2757  					Number: 8484,
  2758  				},
  2759  			},
  2760  		},
  2761  	},
  2762  }
  2763  
  2764  var portLevelDestinationRuleWithSubsetPolicy = &networking.DestinationRule{
  2765  	Host:    "*.example.org",
  2766  	Subsets: []*networking.Subset{networkingSubsetWithPortLevelSettings},
  2767  	TrafficPolicy: &networking.TrafficPolicy{
  2768  		PortLevelSettings: []*networking.TrafficPolicy_PortTrafficPolicy{
  2769  			{
  2770  				LoadBalancer: &networking.LoadBalancerSettings{
  2771  					LbPolicy: loadBalancerPolicy("hash-cookie"),
  2772  				},
  2773  				Port: &networking.PortSelector{
  2774  					Number: 8484,
  2775  				},
  2776  			},
  2777  		},
  2778  	},
  2779  }
  2780  
  2781  var networkingDestinationRule = &networking.DestinationRule{
  2782  	Host:    "*.example.org",
  2783  	Subsets: []*networking.Subset{},
  2784  	TrafficPolicy: &networking.TrafficPolicy{
  2785  		LoadBalancer: &networking.LoadBalancerSettings{
  2786  			LbPolicy: loadBalancerPolicy("hash-cookie"),
  2787  		},
  2788  	},
  2789  }
  2790  
  2791  var (
  2792  	exampleService         = []*model.Service{{Hostname: "*.example.org", Attributes: model.ServiceAttributes{Namespace: "istio-system"}}}
  2793  	exampleWildcardService = &model.Service{
  2794  		Hostname:   "*.example.org",
  2795  		Attributes: model.ServiceAttributes{Namespace: "istio-system"},
  2796  		Ports:      []*model.Port{{Port: 8080, Protocol: "HTTP"}},
  2797  	}
  2798  	exampleNestedWildcardService = &model.Service{
  2799  		Hostname:   "goodbye.hello.example.org",
  2800  		Attributes: model.ServiceAttributes{Namespace: "istio-system"},
  2801  		Ports:      []*model.Port{{Port: 8080, Protocol: "HTTP"}},
  2802  	}
  2803  )
  2804  
  2805  var networkingDestinationRuleWithPortLevelTrafficPolicy = &networking.DestinationRule{
  2806  	Host: "*.example.org",
  2807  	TrafficPolicy: &networking.TrafficPolicy{
  2808  		LoadBalancer: &networking.LoadBalancerSettings{
  2809  			LbPolicy: loadBalancerPolicy("hash-cookie"),
  2810  		},
  2811  		PortLevelSettings: []*networking.TrafficPolicy_PortTrafficPolicy{
  2812  			{
  2813  				LoadBalancer: &networking.LoadBalancerSettings{
  2814  					LbPolicy: loadBalancerPolicy("hash-cookie-1"),
  2815  				},
  2816  				Port: &networking.PortSelector{
  2817  					Number: 8080,
  2818  				},
  2819  			},
  2820  		},
  2821  	},
  2822  }
  2823  
  2824  var networkingSubset = &networking.Subset{
  2825  	Name:   "some-subset",
  2826  	Labels: map[string]string{},
  2827  	TrafficPolicy: &networking.TrafficPolicy{
  2828  		LoadBalancer: &networking.LoadBalancerSettings{
  2829  			LbPolicy: &networking.LoadBalancerSettings_ConsistentHash{
  2830  				ConsistentHash: &networking.LoadBalancerSettings_ConsistentHashLB{
  2831  					HashKey: &networking.LoadBalancerSettings_ConsistentHashLB_HttpCookie{
  2832  						HttpCookie: &networking.LoadBalancerSettings_ConsistentHashLB_HTTPCookie{
  2833  							Name: "other-cookie",
  2834  						},
  2835  					},
  2836  				},
  2837  			},
  2838  		},
  2839  	},
  2840  }
  2841  
  2842  var networkingSubsetWithPortLevelSettings = &networking.Subset{
  2843  	Name:   "port-level-settings-subset",
  2844  	Labels: map[string]string{},
  2845  	TrafficPolicy: &networking.TrafficPolicy{
  2846  		PortLevelSettings: []*networking.TrafficPolicy_PortTrafficPolicy{
  2847  			{
  2848  				LoadBalancer: &networking.LoadBalancerSettings{
  2849  					LbPolicy: loadBalancerPolicy("port-level-settings-cookie"),
  2850  				},
  2851  				Port: &networking.PortSelector{
  2852  					Number: 8484,
  2853  				},
  2854  			},
  2855  		},
  2856  	},
  2857  }
  2858  
  2859  func TestSortVHostRoutes(t *testing.T) {
  2860  	first := []*envoyroute.Route{
  2861  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/"}}},
  2862  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Path{Path: "/path1"}}},
  2863  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/prefix1"}}},
  2864  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2865  			SafeRegex: &matcher.RegexMatcher{
  2866  				Regex: ".*?regex1",
  2867  			},
  2868  		}}},
  2869  	}
  2870  	wantFirst := []*envoyroute.Route{
  2871  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Path{Path: "/path1"}}},
  2872  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/prefix1"}}},
  2873  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2874  			SafeRegex: &matcher.RegexMatcher{
  2875  				Regex: ".*?regex1",
  2876  			},
  2877  		}}},
  2878  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/"}}},
  2879  	}
  2880  	second := []*envoyroute.Route{
  2881  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Path{Path: "/path12"}}},
  2882  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/prefix12"}}},
  2883  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2884  			SafeRegex: &matcher.RegexMatcher{
  2885  				Regex: ".*?regex12",
  2886  			},
  2887  		}}},
  2888  		{Match: &envoyroute.RouteMatch{
  2889  			PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2890  				SafeRegex: &matcher.RegexMatcher{
  2891  					Regex: "*",
  2892  				},
  2893  			},
  2894  			Headers: []*envoyroute.HeaderMatcher{
  2895  				{
  2896  					Name: "foo",
  2897  					HeaderMatchSpecifier: &envoyroute.HeaderMatcher_StringMatch{
  2898  						StringMatch: &matcher.StringMatcher{MatchPattern: &matcher.StringMatcher_Exact{Exact: "bar"}},
  2899  					},
  2900  					InvertMatch: false,
  2901  				},
  2902  			},
  2903  		}},
  2904  	}
  2905  
  2906  	wantSecond := []*envoyroute.Route{
  2907  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Path{Path: "/path12"}}},
  2908  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_Prefix{Prefix: "/prefix12"}}},
  2909  		{Match: &envoyroute.RouteMatch{PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2910  			SafeRegex: &matcher.RegexMatcher{
  2911  				Regex: ".*?regex12",
  2912  			},
  2913  		}}},
  2914  		{Match: &envoyroute.RouteMatch{
  2915  			PathSpecifier: &envoyroute.RouteMatch_SafeRegex{
  2916  				SafeRegex: &matcher.RegexMatcher{
  2917  					Regex: "*",
  2918  				},
  2919  			},
  2920  			Headers: []*envoyroute.HeaderMatcher{
  2921  				{
  2922  					Name: "foo",
  2923  					HeaderMatchSpecifier: &envoyroute.HeaderMatcher_StringMatch{
  2924  						StringMatch: &matcher.StringMatcher{MatchPattern: &matcher.StringMatcher_Exact{Exact: "bar"}},
  2925  					},
  2926  					InvertMatch: false,
  2927  				},
  2928  			},
  2929  		}},
  2930  	}
  2931  
  2932  	testCases := []struct {
  2933  		name     string
  2934  		in       []*envoyroute.Route
  2935  		expected []*envoyroute.Route
  2936  	}{
  2937  		{
  2938  			name:     "routes with catchall match",
  2939  			in:       first,
  2940  			expected: wantFirst,
  2941  		},
  2942  		{
  2943  			name:     "routes without catchall match",
  2944  			in:       second,
  2945  			expected: wantSecond,
  2946  		},
  2947  	}
  2948  
  2949  	for _, tc := range testCases {
  2950  		t.Run(tc.name, func(t *testing.T) {
  2951  			got := route.SortVHostRoutes(tc.in)
  2952  			if !reflect.DeepEqual(tc.expected, got) {
  2953  				t.Errorf("SortVHostRoutes: \n")
  2954  				t.Errorf("got: \n")
  2955  				for _, g := range got {
  2956  					t.Errorf("%v\n", g.Match.PathSpecifier)
  2957  				}
  2958  				t.Errorf("want: \n")
  2959  				for _, g := range tc.expected {
  2960  					t.Errorf("%v\n", g.Match.PathSpecifier)
  2961  				}
  2962  			}
  2963  		})
  2964  	}
  2965  }