mirror of
https://github.com/openfaas/faas.git
synced 2025-06-22 23:03:24 +00:00
Add test coverage for buildUpstreamRequest
Signed-off-by: Alex Ellis (VMware) <alexellis2@gmail.com>
This commit is contained in:
committed by
Alex Ellis
parent
2f98ca8802
commit
4367fc4e35
@ -19,7 +19,7 @@ if [ "$1" ] ; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
NS=openfaas
|
NS=alexellis
|
||||||
|
|
||||||
echo Building $NS/gateway:$eTAG
|
echo Building $NS/gateway:$eTAG
|
||||||
|
|
||||||
|
@ -16,15 +16,15 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus"
|
"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/([^/?]+)([^?]*)")
|
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")
|
||||||
|
|
||||||
// Indicies and meta-data for functionMatcher regex parts
|
// Indicies and meta-data for functionMatcher regex parts
|
||||||
const (
|
const (
|
||||||
hasPathCount = 3
|
hasPathCount = 3
|
||||||
routeIndex = 0
|
routeIndex = 0 // routeIndex corresponds to /function/ or /async-function/
|
||||||
nameIndex = 1
|
nameIndex = 1 // nameIndex is the function name
|
||||||
pathIndex = 2
|
pathIndex = 2 // pathIndex is the path i.e. /employee/:id/
|
||||||
)
|
)
|
||||||
|
|
||||||
// HTTPNotifier notify about HTTP request/response
|
// HTTPNotifier notify about HTTP request/response
|
||||||
@ -218,28 +218,6 @@ func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
|
|||||||
return r.URL.Path
|
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.
|
// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
|
||||||
type FunctionPrefixTrimmingURLPathTransformer struct {
|
type FunctionPrefixTrimmingURLPathTransformer struct {
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -151,22 +152,31 @@ 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")
|
srcBytes := []byte("hello world")
|
||||||
path := "/my/deep/path"
|
functionPath := "/employee/info/300"
|
||||||
|
|
||||||
|
requestPath := fmt.Sprintf("/function/xyz%s", functionPath)
|
||||||
|
|
||||||
reader := bytes.NewReader(srcBytes)
|
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")
|
request.Header.Set("X-Source", "unit-test")
|
||||||
|
|
||||||
if request.URL.RawQuery != "code=1" {
|
queryWant := ""
|
||||||
t.Errorf("Query - want: %s, got: %s", "code=1", request.URL.RawQuery)
|
if request.URL.RawQuery != queryWant {
|
||||||
|
|
||||||
|
t.Errorf("Query - want: %s, got: %s", queryWant, request.URL.RawQuery)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
transformer := FunctionPrefixTrimmingURLPathTransformer{}
|
transformer := FunctionPrefixTrimmingURLPathTransformer{}
|
||||||
transformedPath := transformer.Transform(request)
|
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)
|
upstream := buildUpstreamRequest(request, "http://xyz:8080", transformedPath)
|
||||||
|
|
||||||
if request.Method != upstream.Method {
|
if request.Method != upstream.Method {
|
||||||
@ -191,8 +201,118 @@ func Test_buildUpstreamRequest_Body_Method_Query_Path(t *testing.T) {
|
|||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if path != upstream.URL.Path {
|
if functionPath != upstream.URL.Path {
|
||||||
t.Errorf("URL.Path - want: %s, got: %s", path, 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, 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" {
|
||||||
|
t.Errorf("Query - want: %s, got: %s", "code=1", 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()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user