| // Copyright Istio Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package envoyfilter |
| |
| import ( |
| "testing" |
| ) |
| |
| import ( |
| route "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" |
| "github.com/google/go-cmp/cmp" |
| "google.golang.org/protobuf/testing/protocmp" |
| networking "istio.io/api/networking/v1alpha3" |
| ) |
| |
| import ( |
| "github.com/apache/dubbo-go-pixiu/pilot/pkg/model" |
| "github.com/apache/dubbo-go-pixiu/pilot/pkg/serviceregistry/memory" |
| ) |
| |
| func Test_virtualHostMatch(t *testing.T) { |
| type args struct { |
| cp *model.EnvoyFilterConfigPatchWrapper |
| vh *route.VirtualHost |
| } |
| tests := []struct { |
| name string |
| args args |
| want bool |
| }{ |
| { |
| name: "vh is nil", |
| args: args{ |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: false, |
| }, |
| { |
| name: "full match", |
| args: args{ |
| vh: &route.VirtualHost{ |
| Name: "scooby", |
| }, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "scooby", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "mismatch", |
| args: args{ |
| vh: &route.VirtualHost{ |
| Name: "scoobydoo", |
| }, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "scooby", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: false, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| if got := virtualHostMatch(tt.args.vh, tt.args.cp); got != tt.want { |
| t.Errorf("virtualHostMatch() = %v, want %v", got, tt.want) |
| } |
| }) |
| } |
| } |
| |
| func Test_routeConfigurationMatch(t *testing.T) { |
| type args struct { |
| rc *route.RouteConfiguration |
| patchContext networking.EnvoyFilter_PatchContext |
| cp *model.EnvoyFilterConfigPatchWrapper |
| portMap model.GatewayPortMap |
| } |
| tests := []struct { |
| name string |
| args args |
| want bool |
| }{ |
| { |
| name: "nil route match", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{}, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "rc name mismatch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{Name: "scooby.80"}, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "scooby.90"}, |
| }, |
| want: false, |
| }, |
| { |
| name: "sidecar port match", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{PortNumber: 80}, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "80"}, |
| }, |
| want: true, |
| }, |
| { |
| name: "sidecar port mismatch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{PortNumber: 80}, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "90"}, |
| }, |
| want: false, |
| }, |
| { |
| name: "gateway fields match", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 443, |
| PortName: "app1", |
| Gateway: "ns1/gw1", |
| }, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "https.443.app1.gw1.ns1"}, |
| }, |
| want: true, |
| }, |
| { |
| name: "gateway fields mismatch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 443, |
| PortName: "app1", |
| Gateway: "ns1/gw1", |
| }, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "http.80"}, |
| }, |
| want: false, |
| }, |
| { |
| name: "http target port match", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 80, |
| }, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "http.8080"}, |
| portMap: map[int]map[int]struct{}{ |
| 8080: {80: {}, 81: {}}, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "http target port no match", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 9090, |
| }, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "http.9090"}, |
| portMap: map[int]map[int]struct{}{ |
| 8080: {80: {}, 81: {}}, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "https.443.app1.gw1.ns1", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 443, |
| }, |
| }, |
| }, |
| }, |
| rc: &route.RouteConfiguration{Name: "http.8443"}, |
| portMap: map[int]map[int]struct{}{ |
| 8443: {443: {}}, |
| }, |
| }, |
| want: true, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| if got := routeConfigurationMatch(tt.args.patchContext, tt.args.rc, tt.args.cp, tt.args.portMap); got != tt.want { |
| t.Errorf("routeConfigurationMatch() = %v, want %v", got, tt.want) |
| } |
| }) |
| } |
| } |
| |
| func TestApplyRouteConfigurationPatches(t *testing.T) { |
| configPatches := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{ |
| { |
| ApplyTo: networking.EnvoyFilter_ROUTE_CONFIGURATION, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 80, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_MERGE, |
| Value: buildPatchStruct(`{"request_headers_to_remove":["h3", "h4"]}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 80, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Action: networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch_ROUTE, |
| }, |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_MERGE, |
| Value: buildPatchStruct(`{"route": { "prefix_rewrite": "/foo"}}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 80, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Name: "bar", |
| }, |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_REMOVE, |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "allow_any", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_REMOVE, |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_ADD, |
| Value: buildPatchStruct(`{"name":"new-vhost"}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_GATEWAY, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "vhost1", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{Operation: networking.EnvoyFilter_Patch_REMOVE}, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_INBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "vhost2", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{Operation: networking.EnvoyFilter_Patch_REMOVE}, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_ANY, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_MERGE, |
| Value: buildPatchStruct(`{"domains":["domain:80"]}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_ANY, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 9090, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "test.com", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_ADD, |
| Value: buildPatchStruct(`{"name": "route4.0"}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_ANY, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 9090, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "test.com", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_INSERT_FIRST, |
| Value: buildPatchStruct(`{"name": "route0.0"}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_ANY, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 9090, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "test.com", |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Name: "route2.0", |
| }, |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_INSERT_AFTER, |
| Value: buildPatchStruct(`{"name": "route2.5"}`), |
| }, |
| }, |
| { |
| ApplyTo: networking.EnvoyFilter_HTTP_ROUTE, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_ANY, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| PortNumber: 9090, |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "test.com", |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Name: "route2.0", |
| }, |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_INSERT_BEFORE, |
| Value: buildPatchStruct(`{"name": "route1.5"}`), |
| }, |
| }, |
| } |
| |
| sidecarOutboundRC := &route.RouteConfiguration{ |
| Name: "80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "foo.com", |
| Domains: []string{"domain"}, |
| Routes: []*route.Route{ |
| { |
| Name: "foo", |
| Action: &route.Route_Route{ |
| Route: &route.RouteAction{ |
| PrefixRewrite: "/", |
| }, |
| }, |
| }, |
| { |
| Name: "bar", |
| Action: &route.Route_Redirect{ |
| Redirect: &route.RedirectAction{ |
| ResponseCode: 301, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| RequestHeadersToRemove: []string{"h1", "h2"}, |
| } |
| patchedSidecarOutputRC := &route.RouteConfiguration{ |
| Name: "80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "foo.com", |
| Domains: []string{"domain", "domain:80"}, |
| Routes: []*route.Route{ |
| { |
| Name: "foo", |
| Action: &route.Route_Route{ |
| Route: &route.RouteAction{ |
| PrefixRewrite: "/foo", |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| Name: "new-vhost", |
| }, |
| }, |
| RequestHeadersToRemove: []string{"h1", "h2", "h3", "h4"}, |
| } |
| sidecarInboundRC := &route.RouteConfiguration{ |
| Name: "inbound|http|80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "vhost2", |
| }, |
| }, |
| } |
| patchedSidecarInboundRC := &route.RouteConfiguration{ |
| Name: "inbound|http|80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "new-vhost", |
| }, |
| }, |
| } |
| |
| gatewayRC := &route.RouteConfiguration{ |
| Name: "80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "vhost1", |
| Domains: []string{"domain"}, |
| }, |
| { |
| Name: "gateway", |
| Domains: []string{"gateway"}, |
| }, |
| }, |
| } |
| patchedGatewayRC := &route.RouteConfiguration{ |
| Name: "80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "gateway", |
| Domains: []string{"gateway", "domain:80"}, |
| }, |
| { |
| Name: "new-vhost", |
| }, |
| }, |
| } |
| arrayInsert := &route.RouteConfiguration{ |
| Name: "9090", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "test.com", |
| Domains: []string{"domain"}, |
| Routes: []*route.Route{ |
| { |
| Name: "route1.0", |
| Action: &route.Route_Route{ |
| Route: &route.RouteAction{ |
| PrefixRewrite: "/", |
| }, |
| }, |
| }, |
| { |
| Name: "route2.0", |
| Action: &route.Route_Redirect{ |
| Redirect: &route.RedirectAction{ |
| ResponseCode: 301, |
| }, |
| }, |
| }, |
| { |
| Name: "route3.0", |
| Action: &route.Route_Redirect{ |
| Redirect: &route.RedirectAction{ |
| ResponseCode: 404, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| patchedArrayInsert := &route.RouteConfiguration{ |
| Name: "9090", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "test.com", |
| Domains: []string{"domain", "domain:80"}, |
| Routes: []*route.Route{ |
| { |
| Name: "route0.0", |
| }, |
| { |
| Name: "route1.0", |
| Action: &route.Route_Route{ |
| Route: &route.RouteAction{ |
| PrefixRewrite: "/", |
| }, |
| }, |
| }, |
| { |
| Name: "route1.5", |
| }, |
| { |
| Name: "route2.0", |
| Action: &route.Route_Redirect{ |
| Redirect: &route.RedirectAction{ |
| ResponseCode: 301, |
| }, |
| }, |
| }, |
| { |
| Name: "route2.5", |
| }, |
| { |
| Name: "route3.0", |
| Action: &route.Route_Redirect{ |
| Redirect: &route.RedirectAction{ |
| ResponseCode: 404, |
| }, |
| }, |
| }, |
| { |
| Name: "route4.0", |
| }, |
| }, |
| }, |
| { |
| Name: "new-vhost", |
| }, |
| }, |
| } |
| |
| serviceDiscovery := memory.NewServiceDiscovery() |
| env := newTestEnvironment(serviceDiscovery, testMesh, buildEnvoyFilterConfigStore(configPatches)) |
| push := model.NewPushContext() |
| push.InitContext(env, nil, nil) |
| |
| sidecarNode := &model.Proxy{Type: model.SidecarProxy, ConfigNamespace: "not-default"} |
| gatewayNode := &model.Proxy{Type: model.Router, ConfigNamespace: "not-default"} |
| |
| type args struct { |
| patchContext networking.EnvoyFilter_PatchContext |
| proxy *model.Proxy |
| push *model.PushContext |
| routeConfiguration *route.RouteConfiguration |
| } |
| tests := []struct { |
| name string |
| args args |
| want *route.RouteConfiguration |
| }{ |
| { |
| name: "sidecar outbound rds patch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| proxy: sidecarNode, |
| push: push, |
| routeConfiguration: sidecarOutboundRC, |
| }, |
| want: patchedSidecarOutputRC, |
| }, |
| { |
| name: "sidecar inbound rc patch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_INBOUND, |
| proxy: sidecarNode, |
| push: push, |
| routeConfiguration: sidecarInboundRC, |
| }, |
| want: patchedSidecarInboundRC, |
| }, |
| { |
| name: "gateway rds patch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_GATEWAY, |
| proxy: gatewayNode, |
| push: push, |
| routeConfiguration: gatewayRC, |
| }, |
| want: patchedGatewayRC, |
| }, |
| { |
| name: "array insert patch", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_OUTBOUND, |
| proxy: sidecarNode, |
| push: push, |
| routeConfiguration: arrayInsert, |
| }, |
| want: patchedArrayInsert, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| efw := tt.args.push.EnvoyFilters(tt.args.proxy) |
| got := ApplyRouteConfigurationPatches(tt.args.patchContext, tt.args.proxy, |
| efw, tt.args.routeConfiguration) |
| if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" { |
| t.Errorf("ApplyRouteConfigurationPatches(): %s mismatch (-want +got):\n%s", tt.name, diff) |
| } |
| }) |
| } |
| } |
| |
| func TestReplaceVhost(t *testing.T) { |
| configPatches := []*networking.EnvoyFilter_EnvoyConfigObjectPatch{ |
| { |
| ApplyTo: networking.EnvoyFilter_VIRTUAL_HOST, |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| Context: networking.EnvoyFilter_SIDECAR_INBOUND, |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Name: "to-be-replaced", |
| }, |
| }, |
| }, |
| }, |
| Patch: &networking.EnvoyFilter_Patch{ |
| Operation: networking.EnvoyFilter_Patch_REPLACE, |
| Value: buildPatchStruct(`{ |
| "name":"replaced", |
| "domains":["replaced.com"], |
| "rate_limits": [ |
| { |
| "actions": [ |
| { |
| "request_headers": { |
| "header_name": ":path", |
| "descriptor_key": "PATH" |
| } |
| } |
| ] |
| } |
| ] |
| }`), |
| }, |
| }, |
| } |
| |
| sidecarInboundRCToBeReplaced := &route.RouteConfiguration{ |
| Name: "inbound|http|80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "to-be-replaced", |
| Domains: []string{"xxx"}, |
| Routes: []*route.Route{ |
| { |
| Name: "xxx", |
| Action: &route.Route_Route{ |
| Route: &route.RouteAction{ |
| PrefixRewrite: "/xxx", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| replacedSidecarInboundRC := &route.RouteConfiguration{ |
| Name: "inbound|http|80", |
| VirtualHosts: []*route.VirtualHost{ |
| { |
| Name: "replaced", |
| Domains: []string{"replaced.com"}, |
| RateLimits: []*route.RateLimit{ |
| { |
| Actions: []*route.RateLimit_Action{ |
| { |
| ActionSpecifier: &route.RateLimit_Action_RequestHeaders_{ |
| RequestHeaders: &route.RateLimit_Action_RequestHeaders{ |
| HeaderName: ":path", |
| DescriptorKey: "PATH", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| } |
| |
| serviceDiscovery := memory.NewServiceDiscovery() |
| env := newTestEnvironment(serviceDiscovery, testMesh, buildEnvoyFilterConfigStore(configPatches)) |
| push := model.NewPushContext() |
| push.InitContext(env, nil, nil) |
| |
| sidecarNode := &model.Proxy{Type: model.SidecarProxy, ConfigNamespace: "not-default"} |
| |
| type args struct { |
| patchContext networking.EnvoyFilter_PatchContext |
| proxy *model.Proxy |
| push *model.PushContext |
| routeConfiguration *route.RouteConfiguration |
| } |
| tests := []struct { |
| name string |
| args args |
| want *route.RouteConfiguration |
| }{ |
| { |
| name: "sidecar inbound vhost replace", |
| args: args{ |
| patchContext: networking.EnvoyFilter_SIDECAR_INBOUND, |
| proxy: sidecarNode, |
| push: push, |
| routeConfiguration: sidecarInboundRCToBeReplaced, |
| }, |
| want: replacedSidecarInboundRC, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| efw := tt.args.push.EnvoyFilters(tt.args.proxy) |
| got := ApplyRouteConfigurationPatches(tt.args.patchContext, tt.args.proxy, |
| efw, tt.args.routeConfiguration) |
| if diff := cmp.Diff(tt.want, got, protocmp.Transform()); diff != "" { |
| t.Errorf("ReplaceVhost(): %s mismatch (-want +got):\n%s", tt.name, diff) |
| } |
| }) |
| } |
| } |
| |
| func Test_routeMatch(t *testing.T) { |
| type args struct { |
| httpRoute *route.Route |
| cp *model.EnvoyFilterConfigPatchWrapper |
| } |
| tests := []struct { |
| name string |
| args args |
| want bool |
| }{ |
| { |
| name: "route is nil", |
| args: args{ |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{}, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: false, |
| }, |
| { |
| name: "full match by name", |
| args: args{ |
| httpRoute: &route.Route{ |
| Name: "scooby", |
| }, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Name: "scooby", |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "full match by action", |
| args: args{ |
| httpRoute: &route.Route{ |
| Action: &route.Route_Redirect{Redirect: &route.RedirectAction{}}, |
| }, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Action: networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch_REDIRECT, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: true, |
| }, |
| { |
| name: "mis match by action", |
| args: args{ |
| httpRoute: &route.Route{ |
| Action: &route.Route_Redirect{Redirect: &route.RedirectAction{}}, |
| }, |
| cp: &model.EnvoyFilterConfigPatchWrapper{ |
| Match: &networking.EnvoyFilter_EnvoyConfigObjectMatch{ |
| ObjectTypes: &networking.EnvoyFilter_EnvoyConfigObjectMatch_RouteConfiguration{ |
| RouteConfiguration: &networking.EnvoyFilter_RouteConfigurationMatch{ |
| Vhost: &networking.EnvoyFilter_RouteConfigurationMatch_VirtualHostMatch{ |
| Route: &networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch{ |
| Action: networking.EnvoyFilter_RouteConfigurationMatch_RouteMatch_ROUTE, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| want: false, |
| }, |
| } |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| if got := routeMatch(tt.args.httpRoute, tt.args.cp); got != tt.want { |
| t.Errorf("routeMatch() = %v, want %v", got, tt.want) |
| } |
| }) |
| } |
| } |