From 24d32241939f1f440871a82b28d829faf21eecf1 Mon Sep 17 00:00:00 2001 From: jeveleth Date: Fri, 8 Nov 2019 16:20:59 -0800 Subject: [PATCH 1/2] deploy: enable http2 on TLS port by default --- deploy/manifests/base/custom-types.yaml | 4 ++++ deploy/manifests/base/kong-ingress-dbless.yaml | 2 ++ deploy/single/all-in-one-dbless.yaml | 6 ++++++ deploy/single/all-in-one-postgres-enterprise.yaml | 6 ++++++ deploy/single/all-in-one-postgres.yaml | 6 ++++++ 5 files changed, 24 insertions(+) diff --git a/deploy/manifests/base/custom-types.yaml b/deploy/manifests/base/custom-types.yaml index 33adb8bc7f..2099cac502 100644 --- a/deploy/manifests/base/custom-types.yaml +++ b/deploy/manifests/base/custom-types.yaml @@ -171,6 +171,8 @@ spec: enum: - http - https + - grpc + - grpcs https_redirect_status_code: type: integer proxy: @@ -181,6 +183,8 @@ spec: enum: - http - https + - grpc + - grpcs path: type: string pattern: ^/.*$ diff --git a/deploy/manifests/base/kong-ingress-dbless.yaml b/deploy/manifests/base/kong-ingress-dbless.yaml index fc087f4cdd..db9ed0a17c 100644 --- a/deploy/manifests/base/kong-ingress-dbless.yaml +++ b/deploy/manifests/base/kong-ingress-dbless.yaml @@ -39,6 +39,8 @@ spec: value: /dev/stderr - name: KONG_ADMIN_LISTEN value: 127.0.0.1:8444 ssl + - name: KONG_PROXY_LISTEN + value: 0.0.0.0:8000, 0.0.0.0:8443 ssl http2 lifecycle: preStop: exec: diff --git a/deploy/single/all-in-one-dbless.yaml b/deploy/single/all-in-one-dbless.yaml index 20308df502..d03d5b26f0 100644 --- a/deploy/single/all-in-one-dbless.yaml +++ b/deploy/single/all-in-one-dbless.yaml @@ -99,6 +99,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string read_timeout: minimum: 0 @@ -131,6 +133,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string type: array regex_priority: @@ -511,6 +515,8 @@ spec: value: /dev/stderr - name: KONG_ADMIN_LISTEN value: 127.0.0.1:8444 ssl + - name: KONG_PROXY_LISTEN + value: 0.0.0.0:8000, 0.0.0.0:8443 ssl http2 image: kong:1.3 lifecycle: preStop: diff --git a/deploy/single/all-in-one-postgres-enterprise.yaml b/deploy/single/all-in-one-postgres-enterprise.yaml index 3f192cf54c..7c362d47a2 100644 --- a/deploy/single/all-in-one-postgres-enterprise.yaml +++ b/deploy/single/all-in-one-postgres-enterprise.yaml @@ -99,6 +99,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string read_timeout: minimum: 0 @@ -131,6 +133,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string type: array regex_priority: @@ -534,6 +538,8 @@ spec: value: /dev/stderr - name: KONG_ADMIN_LISTEN value: 127.0.0.1:8444 ssl + - name: KONG_PROXY_LISTEN + value: 0.0.0.0:8000, 0.0.0.0:8443 ssl http2 image: kong-docker-kong-enterprise-edition-docker.bintray.io/kong-enterprise-edition:0.36-2-alpine lifecycle: preStop: diff --git a/deploy/single/all-in-one-postgres.yaml b/deploy/single/all-in-one-postgres.yaml index 429eb9eb93..337b94b855 100644 --- a/deploy/single/all-in-one-postgres.yaml +++ b/deploy/single/all-in-one-postgres.yaml @@ -99,6 +99,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string read_timeout: minimum: 0 @@ -131,6 +133,8 @@ spec: enum: - http - https + - grpc + - grpcs type: string type: array regex_priority: @@ -529,6 +533,8 @@ spec: value: /dev/stderr - name: KONG_ADMIN_LISTEN value: 127.0.0.1:8444 ssl + - name: KONG_PROXY_LISTEN + value: 0.0.0.0:8000, 0.0.0.0:8443 ssl http2 image: kong:1.3 lifecycle: preStop: From c999d6c97a4a357209096ca4608b6c92b608e2c5 Mon Sep 17 00:00:00 2001 From: jeveleth Date: Fri, 8 Nov 2019 16:21:39 -0800 Subject: [PATCH 2/2] feat: add grpc and grpcs support to KongIngress --- internal/ingress/annotations/annotations.go | 21 +- .../ingress/annotations/annotations_test.go | 24 ++ internal/ingress/controller/parser/parser.go | 134 ++++++- .../ingress/controller/parser/parser_test.go | 374 +++++++++++++++++- 4 files changed, 529 insertions(+), 24 deletions(-) diff --git a/internal/ingress/annotations/annotations.go b/internal/ingress/annotations/annotations.go index 308ca171f2..9509f52c55 100644 --- a/internal/ingress/annotations/annotations.go +++ b/internal/ingress/annotations/annotations.go @@ -29,8 +29,12 @@ const ( configurationAnnotationKey = "configuration.konghq.com" + protocolAnnotationKey = "configuration.konghq.com/protocol" + + protocolsAnnotationKey = "configuration.konghq.com/protocols" + // DefaultIngressClass defines the default class used - // by Kong's ingres controller. + // by Kong's ingress controller. DefaultIngressClass = "kong" ) @@ -48,7 +52,7 @@ func validIngress(ingressAnnotationValue, ingressClass string) bool { return ingressAnnotationValue == ingressClass } -// IngressClassValidatorFunc returns a function which can valid if an object +// IngressClassValidatorFunc returns a function which can validate if an Object // belongs to an the ingressClass or not. func IngressClassValidatorFunc( ingressClass string) func(obj metav1.Object) bool { @@ -60,8 +64,7 @@ func IngressClassValidatorFunc( } // IngressClassValidatorFuncFromObjectMeta returns a function which -// can valid if an ObjectMeta -// belongs to an the ingressClass or not. +// can validate if an ObjectMeta belongs to an the ingressClass or not. func IngressClassValidatorFuncFromObjectMeta( ingressClass string) func(obj *metav1.ObjectMeta) bool { @@ -95,6 +98,16 @@ func ExtractConfigurationName(anns map[string]string) string { return anns[configurationAnnotationKey] } +// ExtractProtocolName extracts the protocol supplied in the annotation +func ExtractProtocolName(anns map[string]string) string { + return anns[protocolAnnotationKey] +} + +// ExtractProtocolNames extracts the protocols supplied in the annotation +func ExtractProtocolNames(anns map[string]string) []string { + return strings.Split(anns[protocolsAnnotationKey], ",") +} + // HasServiceUpstreamAnnotation returns true if the annotation // ingress.kubernetes.io/service-upstream is set to "true" in anns. func HasServiceUpstreamAnnotation(anns map[string]string) bool { diff --git a/internal/ingress/annotations/annotations_test.go b/internal/ingress/annotations/annotations_test.go index 770a900a6c..891eb4219d 100644 --- a/internal/ingress/annotations/annotations_test.go +++ b/internal/ingress/annotations/annotations_test.go @@ -17,6 +17,7 @@ limitations under the License. package annotations import ( + "reflect" "testing" v1 "k8s.io/api/core/v1" @@ -49,6 +50,29 @@ func TestExtractConfigurationName(t *testing.T) { } } +func TestExtractProtocolName(t *testing.T) { + data := map[string]string{ + "configuration.konghq.com/protocol": "grpc", + } + + pn := ExtractProtocolName(data) + if pn != "grpc" { + t.Errorf("expected grpc as configuration name but got %v", pn) + } +} + +func TestExtractProtocolNames(t *testing.T) { + data := map[string]string{ + "configuration.konghq.com/protocols": "grpc,grpcs", + } + + s := []string{"grpc", "grpcs"} + + pns := ExtractProtocolNames(data) + if !reflect.DeepEqual(pns, s) { + t.Errorf("expected grpc,grpcs as configuration name but got %v", pns) + } +} func TestIngrssClassValidatorFunc(t *testing.T) { tests := []struct { ingress string diff --git a/internal/ingress/controller/parser/parser.go b/internal/ingress/controller/parser/parser.go index 045d4ac86f..176e949ff0 100644 --- a/internal/ingress/controller/parser/parser.go +++ b/internal/ingress/controller/parser/parser.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "fmt" "reflect" + "regexp" "sort" "strings" @@ -110,6 +111,8 @@ var supportedCreds = sets.NewString( "oauth2", ) +var validProtocols = regexp.MustCompile(`\Ahttps$|\Ahttp$|\Agrpc$|\Agrpcs$`) + // New returns a new parser backed with store. func New(store store.Storer) Parser { return Parser{store: store} @@ -497,26 +500,30 @@ func (p *Parser) parseIngressRules( func (p *Parser) fillOverrides(state KongState) error { for i := 0; i < len(state.Services); i++ { // Services + var anns map[string]string + svc, err := p.store.GetService( + state.Services[i].Namespace, + state.Services[i].Backend.ServiceName) + if err != nil { + glog.Errorf("error getting services %v", err) + } + anns = svc.Annotations kongIngress, err := p.getKongIngressForService( - state.Services[i].Namespace, state.Services[i].Backend.ServiceName) - if err == nil { - overrideService(&state.Services[i], kongIngress) - } else { - glog.Error(errors.Wrapf(err, "fetching KongIngress for service %v/%v", - state.Services[i].Namespace, - state.Services[i].Backend.ServiceName)) + state.Services[i].Namespace, + state.Services[i].Backend.ServiceName) + if err != nil { + glog.Errorf("error getting kongIngress %v", err) } + overrideService(&state.Services[i], kongIngress, anns) // Routes for j := 0; j < len(state.Services[i].Routes); j++ { kongIngress, err := p.getKongIngressFromIngress( &state.Services[i].Routes[j].Ingress) - if err == nil { - overrideRoute(&state.Services[i].Routes[j], kongIngress) - } else { - glog.Error(errors.Wrapf(err, "fetching KongIngress for Ingress '%v' in namespace '%v'", - state.Services[i].Routes[j].Ingress.Name, state.Services[i].Routes[j].Ingress.Namespace)) + if err != nil { + glog.Errorf("error getting kongIngress %v", err) } + overrideRoute(&state.Services[i].Routes[j], kongIngress) } } @@ -534,9 +541,10 @@ func (p *Parser) fillOverrides(state KongState) error { return nil } -func overrideService(service *Service, +// overrideServiceByKongIngress sets Service fields by KongIngress +func overrideServiceByKongIngress(service *Service, kongIngress *configurationv1.KongIngress) { - if service == nil || kongIngress == nil || kongIngress.Proxy == nil { + if kongIngress == nil || kongIngress.Proxy == nil { return } s := kongIngress.Proxy @@ -560,13 +568,40 @@ func overrideService(service *Service, } } -func overrideRoute(route *Route, +// overrideServiceByAnnotation sets the Service protocol via annotation +func overrideServiceByAnnotation(service *Service, + anns map[string]string) { + protocol := annotations.ExtractProtocolName(anns) + if protocol == "" || validateProtocol(protocol) != true { + return + } + service.Protocol = kong.String(protocol) +} + +// overrideService sets Service fields by KongIngress first, then by annotation +func overrideService(service *Service, + kongIngress *configurationv1.KongIngress, + anns map[string]string) { + if service == nil { + return + } + overrideServiceByKongIngress(service, kongIngress) + overrideServiceByAnnotation(service, anns) + + if *service.Protocol == "grpc" || *service.Protocol == "grpcs" { + // grpc(s) doesn't accept a path + service.Path = nil + } +} + +// overrideRouteByKongIngress sets Route fields by KongIngress +func overrideRouteByKongIngress(route *Route, kongIngress *configurationv1.KongIngress) { - if route == nil || kongIngress == nil || kongIngress.Route == nil { + if kongIngress == nil || kongIngress.Route == nil { return } - r := kongIngress.Route + r := kongIngress.Route if len(r.Methods) != 0 { route.Methods = cloneStringPointerSlice(r.Methods...) } @@ -590,6 +625,69 @@ func overrideRoute(route *Route, } } +// normalizeProtocols prevents users from mismatching grpc/http +func normalizeProtocols(route *Route) { + protocols := route.Protocols + var http, grpc bool + + for _, protocol := range protocols { + if strings.Contains(*protocol, "grpc") { + grpc = true + } + if strings.Contains(*protocol, "http") { + http = true + } + if validateProtocol(*protocol) != true { + http = true + } + } + + if grpc && http { + route.Protocols = kong.StringSlice("http", "https") + } +} + +// validateProtocol returns a bool of whether string is a valid protocol +func validateProtocol(protocol string) bool { + match := validProtocols.MatchString(protocol) + return match +} + +// overrideRouteByAnnotation sets Route protocols via annotation +func overrideRouteByAnnotation(route *Route, anns map[string]string) { + if anns == nil { + return + } + protocols := annotations.ExtractProtocolNames(anns) + var prots []*string + for _, prot := range protocols { + if validateProtocol(prot) != true { + return + } + prots = append(prots, kong.String(prot)) + } + + route.Protocols = prots +} + +// overrideRoute sets Route fields by KongIngress first, then by annotation +func overrideRoute(route *Route, + kongIngress *configurationv1.KongIngress) { + if route == nil { + return + } + overrideRouteByKongIngress(route, kongIngress) + overrideRouteByAnnotation(route, route.Ingress.Annotations) + normalizeProtocols(route) + for _, val := range route.Protocols { + if *val == "grpc" || *val == "grpcs" { + // grpc(s) doesn't accept strip_path + route.StripPath = nil + break + } + } +} + func cloneStringPointerSlice(array ...*string) []*string { var res []*string for _, s := range array { @@ -854,7 +952,7 @@ func (p *Parser) getKongIngressForService(namespace, serviceName string) ( return p.store.GetKongIngress(svc.Namespace, confName) } -// getKongIngress checks if the Ingress contains an annotation for configuration +// getKongIngressFromIngress checks if the Ingress contains an annotation for configuration // or if exists a KongIngress object with the same name than the Ingress func (p *Parser) getKongIngressFromIngress(ing *networking.Ingress) ( *configurationv1.KongIngress, error) { diff --git a/internal/ingress/controller/parser/parser_test.go b/internal/ingress/controller/parser/parser_test.go index c6d11289fb..fa895994c9 100644 --- a/internal/ingress/controller/parser/parser_test.go +++ b/internal/ingress/controller/parser/parser_test.go @@ -555,6 +555,7 @@ func TestOverrideService(t *testing.T) { inService Service inKongIngresss configurationv1.KongIngress outService Service + inAnnotation map[string]string }{ { Service{ @@ -578,6 +579,7 @@ func TestOverrideService(t *testing.T) { Path: kong.String("/"), }, }, + map[string]string{}, }, { Service{ @@ -603,6 +605,7 @@ func TestOverrideService(t *testing.T) { Path: kong.String("/"), }, }, + map[string]string{}, }, { Service{ @@ -629,6 +632,7 @@ func TestOverrideService(t *testing.T) { Retries: kong.Int(0), }, }, + map[string]string{}, }, { Service{ @@ -654,6 +658,7 @@ func TestOverrideService(t *testing.T) { Path: kong.String("/new-path"), }, }, + map[string]string{}, }, { Service{ @@ -680,6 +685,7 @@ func TestOverrideService(t *testing.T) { Retries: kong.Int(1), }, }, + map[string]string{}, }, { Service{ @@ -710,16 +716,195 @@ func TestOverrideService(t *testing.T) { WriteTimeout: kong.Int(100), }, }, + map[string]string{}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpc"), + Path: nil, + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{ + Protocol: kong.String("grpc"), + }, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpc"), + Path: nil, + }, + }, + map[string]string{}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: nil, + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{ + Protocol: kong.String("grpcs"), + }, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpcs"), + Path: nil, + }, + }, + map[string]string{}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{ + Protocol: kong.String("grpcs"), + }, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpcs"), + Path: nil, + }, + }, + map[string]string{"configuration.konghq.com/protocol": "grpcs"}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{ + Protocol: kong.String("grpcs"), + }, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpc"), + Path: nil, + }, + }, + map[string]string{"configuration.konghq.com/protocol": "grpc"}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{}, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("grpcs"), + Path: nil, + }, + }, + map[string]string{"configuration.konghq.com/protocol": "grpcs"}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{ + Protocol: kong.String("grpcs"), + }, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + map[string]string{"configuration.konghq.com/protocol": "https"}, + }, + { + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + configurationv1.KongIngress{ + Proxy: &kong.Service{}, + }, + Service{ + Service: kong.Service{ + Host: kong.String("foo.com"), + Port: kong.Int(80), + Name: kong.String("foo"), + Protocol: kong.String("https"), + Path: kong.String("/"), + }, + }, + map[string]string{"configuration.konghq.com/protocol": "https"}, }, } for _, testcase := range testTable { - overrideService(&testcase.inService, &testcase.inKongIngresss) + overrideService(&testcase.inService, &testcase.inKongIngresss, testcase.inAnnotation) assert.Equal(testcase.inService, testcase.outService) } assert.NotPanics(func() { - overrideService(nil, nil) + overrideService(nil, nil, nil) }) } @@ -830,6 +1015,25 @@ func TestOverrideRoute(t *testing.T) { }, }, }, + { + Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com"), + }, + }, + configurationv1.KongIngress{ + Route: &kong.Route{ + Protocols: kong.StringSlice("grpc", "grpcs"), + }, + }, + Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com"), + Protocols: kong.StringSlice("grpc", "grpcs"), + StripPath: nil, + }, + }, + }, } for _, testcase := range testTable { @@ -842,6 +1046,172 @@ func TestOverrideRoute(t *testing.T) { }) } +func TestOverrideRoutePriority(t *testing.T) { + assert := assert.New(t) + var route Route + route = Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + } + var kongIngress configurationv1.KongIngress + kongIngress = configurationv1.KongIngress{ + Route: &kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + } + + var netIngress networking.Ingress + + netIngress = networking.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "configuration.konghq.com/protocols": "grpc,grpcs", + }, + }, + } + + route = Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + Ingress: netIngress, + } + overrideRoute(&route, &kongIngress) + assert.Equal(route.Hosts, kong.StringSlice("foo.com", "bar.com")) + assert.Equal(route.Protocols, kong.StringSlice("grpc", "grpcs")) +} + +func TestOverrideRouteByKongIngress(t *testing.T) { + assert := assert.New(t) + var route Route + route = Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + } + var kongIngress configurationv1.KongIngress + kongIngress = configurationv1.KongIngress{ + Route: &kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + } + + overrideRouteByKongIngress(&route, &kongIngress) + assert.Equal(route.Hosts, kong.StringSlice("foo.com", "bar.com")) + assert.NotPanics(func() { + overrideRoute(nil, nil) + }) +} +func TestOverrideRouteByAnnotation(t *testing.T) { + assert := assert.New(t) + var route Route + route = Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + } + + var netIngress networking.Ingress + + netIngress = networking.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + "configuration.konghq.com/protocols": "grpc,grpcs", + }, + }, + } + + route = Route{ + Route: kong.Route{ + Hosts: kong.StringSlice("foo.com", "bar.com"), + }, + Ingress: netIngress, + } + overrideRouteByAnnotation(&route, route.Ingress.GetAnnotations()) + assert.Equal(route.Hosts, kong.StringSlice("foo.com", "bar.com")) + assert.Equal(route.Protocols, kong.StringSlice("grpc", "grpcs")) + + assert.NotPanics(func() { + overrideRoute(nil, nil) + }) +} + +func TestNormalizeProtocols(t *testing.T) { + assert := assert.New(t) + testTable := []struct { + inRoute Route + outRoute Route + }{ + { + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("grpc", "grpcs"), + }, + }, + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("grpc", "grpcs"), + }, + }, + }, + { + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("http", "https"), + }, + }, + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("http", "https"), + }, + }, + }, + { + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("grpc", "https"), + }, + }, + Route{ + Route: kong.Route{ + Protocols: kong.StringSlice("http", "https"), + }, + }, + }, + } + + for _, testcase := range testTable { + normalizeProtocols(&testcase.inRoute) + assert.Equal(testcase.inRoute.Protocols, testcase.outRoute.Protocols) + } + + assert.NotPanics(func() { + overrideUpstream(nil, nil) + }) +} + +func TestValidateProtocol(t *testing.T) { + assert := assert.New(t) + testTable := []struct { + input string + result bool + }{ + {"http", true}, + {"https", true}, + {"grpc", true}, + {"grpcs", true}, + {"grcpsfdsafdsfafdshttp", false}, + } + for _, testcase := range testTable { + isMatch := validateProtocol(testcase.input) + assert.Equal(isMatch, testcase.result) + } + + assert.NotPanics(func() { + overrideUpstream(nil, nil) + }) +} func TestOverrideUpstream(t *testing.T) { assert := assert.New(t)