From 4367fc4e359472db43d509f6b550535d63ef0166 Mon Sep 17 00:00:00 2001 From: "Alex Ellis (VMware)" <alexellis2@gmail.com> Date: Fri, 24 Aug 2018 10:28:10 +0100 Subject: [PATCH] Add test coverage for buildUpstreamRequest Signed-off-by: Alex Ellis (VMware) <alexellis2@gmail.com> --- gateway/build.sh | 2 +- gateway/handlers/forwarding_proxy.go | 30 +---- gateway/handlers/forwarding_proxy_test.go | 130 +++++++++++++++++++++- 3 files changed, 130 insertions(+), 32 deletions(-) diff --git a/gateway/build.sh b/gateway/build.sh index 763879e9..37b70f12 100755 --- a/gateway/build.sh +++ b/gateway/build.sh @@ -19,7 +19,7 @@ if [ "$1" ] ; then fi fi -NS=openfaas +NS=alexellis echo Building $NS/gateway:$eTAG diff --git a/gateway/handlers/forwarding_proxy.go b/gateway/handlers/forwarding_proxy.go index cff99ea8..4eac6f5b 100644 --- a/gateway/handlers/forwarding_proxy.go +++ b/gateway/handlers/forwarding_proxy.go @@ -16,15 +16,15 @@ import ( "github.com/prometheus/client_golang/prometheus" ) -// Parse out the service name (group 1) and rest of path (group 2). +// functionMatcher parses out the service name (group 1) and rest of path (group 2). var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)") // Indicies and meta-data for functionMatcher regex parts const ( hasPathCount = 3 - routeIndex = 0 - nameIndex = 1 - pathIndex = 2 + routeIndex = 0 // routeIndex corresponds to /function/ or /async-function/ + nameIndex = 1 // nameIndex is the function name + pathIndex = 2 // pathIndex is the path i.e. /employee/:id/ ) // HTTPNotifier notify about HTTP request/response @@ -218,28 +218,6 @@ func (f TransparentURLPathTransformer) Transform(r *http.Request) string { return r.URL.Path } -// FunctionPathTruncatingURLPathTransformer always truncated the path to "/". -type FunctionPathTruncatingURLPathTransformer struct { -} - -// Transform always return a path of "/". -func (f FunctionPathTruncatingURLPathTransformer) Transform(r *http.Request) string { - ret := r.URL.Path - - if ret != "" { - matcher := functionMatcher.Copy() - parts := matcher.FindStringSubmatch(ret) - // In the following regex, in the case of a match the r.URL.Path will be at `0`, - // the function name at `1` and the rest of the path (the part we are interested in) - // at `2`. For this transformer, all we need to do is confirm it is a function. - if len(parts) == hasPathCount { - ret = "/" - } - } - - return ret -} - // FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path. type FunctionPrefixTrimmingURLPathTransformer struct { } diff --git a/gateway/handlers/forwarding_proxy_test.go b/gateway/handlers/forwarding_proxy_test.go index 963d6b74..3cb50762 100644 --- a/gateway/handlers/forwarding_proxy_test.go +++ b/gateway/handlers/forwarding_proxy_test.go @@ -2,6 +2,7 @@ package handlers import ( "bytes" + "fmt" "io/ioutil" "net/http" "net/url" @@ -151,12 +152,126 @@ func Test_getServiceName(t *testing.T) { } } -func Test_buildUpstreamRequest_Body_Method_Query_Path(t *testing.T) { +func Test_buildUpstreamRequest_WithPathNoQuery(t *testing.T) { srcBytes := []byte("hello world") - path := "/my/deep/path" + functionPath := "/employee/info/300" + + requestPath := fmt.Sprintf("/function/xyz%s", functionPath) + + reader := bytes.NewReader(srcBytes) + request, _ := http.NewRequest(http.MethodPost, requestPath, reader) + request.Header.Set("X-Source", "unit-test") + + queryWant := "" + if request.URL.RawQuery != queryWant { + + t.Errorf("Query - want: %s, got: %s", queryWant, request.URL.RawQuery) + t.Fail() + } + + transformer := FunctionPrefixTrimmingURLPathTransformer{} + transformedPath := transformer.Transform(request) + + wantTransformedPath := functionPath + if transformedPath != wantTransformedPath { + t.Errorf("transformedPath want: %s, got %s", wantTransformedPath, transformedPath) + } + + upstream := buildUpstreamRequest(request, "http://xyz:8080", transformedPath) + + if request.Method != upstream.Method { + t.Errorf("Method - want: %s, got: %s", request.Method, upstream.Method) + t.Fail() + } + + upstreamBytes, _ := ioutil.ReadAll(upstream.Body) + + if string(upstreamBytes) != string(srcBytes) { + t.Errorf("Body - want: %s, got: %s", string(upstreamBytes), string(srcBytes)) + t.Fail() + } + + if request.Header.Get("X-Source") != upstream.Header.Get("X-Source") { + t.Errorf("Header X-Source - want: %s, got: %s", request.Header.Get("X-Source"), upstream.Header.Get("X-Source")) + t.Fail() + } + + if request.URL.RawQuery != upstream.URL.RawQuery { + t.Errorf("URL.RawQuery - want: %s, got: %s", request.URL.RawQuery, upstream.URL.RawQuery) + t.Fail() + } + + if functionPath != upstream.URL.Path { + t.Errorf("URL.Path - want: %s, got: %s", functionPath, upstream.URL.Path) + t.Fail() + } + +} + +func Test_buildUpstreamRequest_WithNoPathNoQuery(t *testing.T) { + srcBytes := []byte("hello world") + functionPath := "/" + + requestPath := fmt.Sprintf("/function/xyz%s", functionPath) reader := bytes.NewReader(srcBytes) - request, _ := http.NewRequest(http.MethodPost, "/function/xyz"+path+"?code=1", reader) + request, _ := http.NewRequest(http.MethodPost, requestPath, reader) + request.Header.Set("X-Source", "unit-test") + + queryWant := "" + if request.URL.RawQuery != queryWant { + + t.Errorf("Query - want: %s, got: %s", queryWant, request.URL.RawQuery) + t.Fail() + } + + transformer := FunctionPrefixTrimmingURLPathTransformer{} + transformedPath := transformer.Transform(request) + + wantTransformedPath := "/" + if transformedPath != wantTransformedPath { + t.Errorf("transformedPath want: %s, got %s", wantTransformedPath, transformedPath) + } + + upstream := buildUpstreamRequest(request, "http://xyz:8080", transformedPath) + + if request.Method != upstream.Method { + t.Errorf("Method - want: %s, got: %s", request.Method, upstream.Method) + t.Fail() + } + + upstreamBytes, _ := ioutil.ReadAll(upstream.Body) + + if string(upstreamBytes) != string(srcBytes) { + t.Errorf("Body - want: %s, got: %s", string(upstreamBytes), string(srcBytes)) + t.Fail() + } + + if request.Header.Get("X-Source") != upstream.Header.Get("X-Source") { + t.Errorf("Header X-Source - want: %s, got: %s", request.Header.Get("X-Source"), upstream.Header.Get("X-Source")) + t.Fail() + } + + if request.URL.RawQuery != upstream.URL.RawQuery { + t.Errorf("URL.RawQuery - want: %s, got: %s", request.URL.RawQuery, upstream.URL.RawQuery) + t.Fail() + } + + if functionPath != upstream.URL.Path { + t.Errorf("URL.Path - want: %s, got: %s", functionPath, upstream.URL.Path) + t.Fail() + } + +} + +func Test_buildUpstreamRequest_WithPathAndQuery(t *testing.T) { + srcBytes := []byte("hello world") + functionPath := "/employee/info/300" + + requestPath := fmt.Sprintf("/function/xyz%s?code=1", functionPath) + + reader := bytes.NewReader(srcBytes) + request, _ := http.NewRequest(http.MethodPost, requestPath, reader) request.Header.Set("X-Source", "unit-test") if request.URL.RawQuery != "code=1" { @@ -167,6 +282,11 @@ func Test_buildUpstreamRequest_Body_Method_Query_Path(t *testing.T) { transformer := FunctionPrefixTrimmingURLPathTransformer{} transformedPath := transformer.Transform(request) + wantTransformedPath := functionPath + if transformedPath != wantTransformedPath { + t.Errorf("transformedPath want: %s, got %s", wantTransformedPath, transformedPath) + } + upstream := buildUpstreamRequest(request, "http://xyz:8080", transformedPath) if request.Method != upstream.Method { @@ -191,8 +311,8 @@ func Test_buildUpstreamRequest_Body_Method_Query_Path(t *testing.T) { t.Fail() } - if path != upstream.URL.Path { - t.Errorf("URL.Path - want: %s, got: %s", path, upstream.URL.Path) + if functionPath != upstream.URL.Path { + t.Errorf("URL.Path - want: %s, got: %s", functionPath, upstream.URL.Path) t.Fail() } -- GitLab