mirror of
https://github.com/openfaas/faas.git
synced 2025-06-25 00:03:24 +00:00
Re-vendor queue-worker publisher for reconnect
- re-vendor queue-worker for publisher via 0.6.0 - bump queue-worker version to 0.6.0 in docker-compose.yml for AMD64 - use new naming for NATS of nats -> NATS in variables where required - add default reconnect of 60 times, 2 seconds apart. Signed-off-by: Alex Ellis (VMware) <alexellis2@gmail.com>
This commit is contained in:
committed by
Alex Ellis
parent
e63150ef70
commit
b4a550327d
134
gateway/vendor/github.com/openfaas/faas-provider/proxy/handler_test.go
generated
vendored
Normal file
134
gateway/vendor/github.com/openfaas/faas-provider/proxy/handler_test.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type testBaseURLResolver struct {
|
||||
testServerBase string
|
||||
err error
|
||||
}
|
||||
|
||||
func (tr *testBaseURLResolver) Resolve(name string) (url.URL, error) {
|
||||
if tr.err != nil {
|
||||
return url.URL{}, tr.err
|
||||
}
|
||||
|
||||
return url.URL{
|
||||
Scheme: "http",
|
||||
Host: tr.testServerBase,
|
||||
}, nil
|
||||
}
|
||||
func Test_NewHandlerFunc_Panic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("should panic if resolver is nil")
|
||||
}
|
||||
}()
|
||||
|
||||
NewHandlerFunc(time.Second, nil)
|
||||
}
|
||||
|
||||
func Test_NewHandlerFunc_NoPanic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
t.Errorf("should not panic if resolver is not nil")
|
||||
}
|
||||
}()
|
||||
|
||||
proxyFunc := NewHandlerFunc(time.Second, &testBaseURLResolver{})
|
||||
if proxyFunc == nil {
|
||||
t.Errorf("proxy handler func is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ProxyHandler_NonAllowedMethods(t *testing.T) {
|
||||
|
||||
proxyFunc := NewHandlerFunc(time.Second, &testBaseURLResolver{})
|
||||
|
||||
nonAllowedMethods := []string{
|
||||
http.MethodHead, http.MethodConnect, http.MethodOptions, http.MethodTrace,
|
||||
}
|
||||
|
||||
for _, method := range nonAllowedMethods {
|
||||
t.Run(method+" method is not allowed", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(method, "http://example.com/foo", nil)
|
||||
proxyFunc(w, req)
|
||||
resp := w.Result()
|
||||
if resp.StatusCode != http.StatusMethodNotAllowed {
|
||||
t.Errorf("expected status code `%d`, got `%d`", http.StatusMethodNotAllowed, resp.StatusCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ProxyHandler_MissingFunctionNameError(t *testing.T) {
|
||||
proxyFunc := NewHandlerFunc(time.Second, &testBaseURLResolver{"", nil})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
|
||||
req = mux.SetURLVars(req, map[string]string{"name": ""})
|
||||
|
||||
proxyFunc(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
|
||||
respBody := w.Body.String()
|
||||
if respBody != errMissingFunctionName {
|
||||
t.Errorf("expected error message `%s`, got `%s`", errMissingFunctionName, respBody)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ProxyHandler_ResolveError(t *testing.T) {
|
||||
logs := &bytes.Buffer{}
|
||||
log.SetOutput(logs)
|
||||
|
||||
resolveErr := errors.New("can not find test service `foo`")
|
||||
proxyFunc := NewHandlerFunc(time.Second, &testBaseURLResolver{"", resolveErr})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
|
||||
req = mux.SetURLVars(req, map[string]string{"name": "foo"})
|
||||
|
||||
proxyFunc(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status code `%d`, got `%d`", http.StatusBadRequest, w.Code)
|
||||
}
|
||||
|
||||
respBody := w.Body.String()
|
||||
if respBody != "Cannot find service: foo." {
|
||||
t.Errorf("expected error message `%s`, got `%s`", "Cannot find service: foo.", respBody)
|
||||
}
|
||||
|
||||
if !strings.Contains(logs.String(), resolveErr.Error()) {
|
||||
t.Errorf("expected logs to contain `%s`", resolveErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ProxyHandler_Proxy_Success(t *testing.T) {
|
||||
t.Skip("Test not implemented yet")
|
||||
// testFuncService := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// w.WriteHeader(http.StatusOK)
|
||||
// }))
|
||||
// proxyFunc := NewHandlerFunc(time.Second, &testBaseURLResolver{testFuncService.URL, nil})
|
||||
|
||||
// w := httptest.NewRecorder()
|
||||
// req := httptest.NewRequest("GET", "http://example.com/foo", nil)
|
||||
// req = mux.SetURLVars(req, map[string]string{"name": "foo"})
|
||||
|
||||
// proxyFunc(w, req)
|
||||
}
|
221
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy.go
generated
vendored
Normal file
221
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy.go
generated
vendored
Normal file
@ -0,0 +1,221 @@
|
||||
// Package proxy provides a default function invocation proxy method for OpenFaaS providers.
|
||||
//
|
||||
// The function proxy logic is used by the Gateway when `direct_functions` is set to false.
|
||||
// This means that the provider will direct call the function and return the results. This
|
||||
// involves resolving the function by name and then copying the result into the original HTTP
|
||||
// request.
|
||||
//
|
||||
// openfaas-provider has implemented a standard HTTP HandlerFunc that will handle setting
|
||||
// timeout values, parsing the request path, and copying the request/response correctly.
|
||||
// bootstrapHandlers := bootTypes.FaaSHandlers{
|
||||
// FunctionProxy: proxy.NewHandlerFunc(timeout, resolver),
|
||||
// DeleteHandler: handlers.MakeDeleteHandler(clientset),
|
||||
// DeployHandler: handlers.MakeDeployHandler(clientset),
|
||||
// FunctionReader: handlers.MakeFunctionReader(clientset),
|
||||
// ReplicaReader: handlers.MakeReplicaReader(clientset),
|
||||
// ReplicaUpdater: handlers.MakeReplicaUpdater(clientset),
|
||||
// InfoHandler: handlers.MakeInfoHandler(),
|
||||
// }
|
||||
//
|
||||
// proxy.NewHandlerFunc is optional, but does simplify the logic of your provider.
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const (
|
||||
watchdogPort = "8080"
|
||||
defaultContentType = "text/plain"
|
||||
errMissingFunctionName = "Please provide a valid route /function/function_name."
|
||||
)
|
||||
|
||||
// BaseURLResolver URL resolver for proxy requests
|
||||
//
|
||||
// The FaaS provider implementation is responsible for providing the resolver function implementation.
|
||||
// BaseURLResolver.Resolve will receive the function name and should return the URL of the
|
||||
// function service.
|
||||
type BaseURLResolver interface {
|
||||
Resolve(functionName string) (url.URL, error)
|
||||
}
|
||||
|
||||
// NewHandlerFunc creates a standard http.HandlerFunc to proxy function requests.
|
||||
// The returned http.HandlerFunc will ensure:
|
||||
//
|
||||
// - proper proxy request timeouts
|
||||
// - proxy requests for GET, POST, PATCH, PUT, and DELETE
|
||||
// - path parsing including support for extracing the function name, sub-paths, and query paremeters
|
||||
// - passing and setting the `X-Forwarded-Host` and `X-Forwarded-For` headers
|
||||
// - logging errors and proxy request timing to stdout
|
||||
//
|
||||
// Note that this will panic if `resolver` is nil.
|
||||
func NewHandlerFunc(timeout time.Duration, resolver BaseURLResolver) http.HandlerFunc {
|
||||
if resolver == nil {
|
||||
panic("NewHandlerFunc: empty proxy handler resolver, cannot be nil")
|
||||
}
|
||||
|
||||
proxyClient := http.Client{
|
||||
// these Transport values ensure that the http Client will eventually timeout and prevents
|
||||
// infinite retries. The default http.Client configure these timeouts. The specific
|
||||
// values tuned via performance testing/benchmarking
|
||||
//
|
||||
// Additional context can be found at
|
||||
// - https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779
|
||||
// - https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: timeout,
|
||||
KeepAlive: 1 * time.Second,
|
||||
}).DialContext,
|
||||
IdleConnTimeout: 120 * time.Millisecond,
|
||||
ExpectContinueTimeout: 1500 * time.Millisecond,
|
||||
},
|
||||
Timeout: timeout,
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Body != nil {
|
||||
defer r.Body.Close()
|
||||
}
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodPatch,
|
||||
http.MethodDelete,
|
||||
http.MethodGet:
|
||||
|
||||
proxyRequest(w, r, proxyClient, resolver)
|
||||
|
||||
default:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proxyRequest handles the actual resolution of and then request to the function service.
|
||||
func proxyRequest(w http.ResponseWriter, originalReq *http.Request, proxyClient http.Client, resolver BaseURLResolver) {
|
||||
ctx := originalReq.Context()
|
||||
|
||||
pathVars := mux.Vars(originalReq)
|
||||
functionName := pathVars["name"]
|
||||
if functionName == "" {
|
||||
writeError(w, http.StatusBadRequest, errMissingFunctionName)
|
||||
return
|
||||
}
|
||||
|
||||
functionAddr, resolveErr := resolver.Resolve(functionName)
|
||||
if resolveErr != nil {
|
||||
// TODO: Should record the 404/not found error in Prometheus.
|
||||
log.Printf("resolver error: cannot find %s: %s\n", functionName, resolveErr.Error())
|
||||
writeError(w, http.StatusNotFound, "Cannot find service: %s.", functionName)
|
||||
return
|
||||
}
|
||||
|
||||
proxyReq, err := buildProxyRequest(originalReq, functionAddr, pathVars["params"])
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "Failed to resolve service: %s.", functionName)
|
||||
return
|
||||
}
|
||||
defer proxyReq.Body.Close()
|
||||
|
||||
start := time.Now()
|
||||
response, err := proxyClient.Do(proxyReq.WithContext(ctx))
|
||||
seconds := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("error with proxy request to: %s, %s\n", proxyReq.URL.String(), err.Error())
|
||||
|
||||
writeError(w, http.StatusInternalServerError, "Can't reach service for: %s.", functionName)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%s took %f seconds\n", functionName, seconds.Seconds())
|
||||
|
||||
clientHeader := w.Header()
|
||||
copyHeaders(clientHeader, &response.Header)
|
||||
w.Header().Set("Content-Type", getContentType(response.Header, originalReq.Header))
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
io.Copy(w, response.Body)
|
||||
}
|
||||
|
||||
// buildProxyRequest creates a request object for the proxy request, it will ensure that
|
||||
// the original request headers are preserved as well as setting openfaas system headers
|
||||
func buildProxyRequest(originalReq *http.Request, baseURL url.URL, extraPath string) (*http.Request, error) {
|
||||
|
||||
host := baseURL.Host
|
||||
if baseURL.Port() == "" {
|
||||
host = baseURL.Host + ":" + watchdogPort
|
||||
}
|
||||
|
||||
url := url.URL{
|
||||
Scheme: baseURL.Scheme,
|
||||
Host: host,
|
||||
Path: extraPath,
|
||||
RawQuery: originalReq.URL.RawQuery,
|
||||
}
|
||||
|
||||
upstreamReq, err := http.NewRequest(originalReq.Method, url.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
copyHeaders(upstreamReq.Header, &originalReq.Header)
|
||||
|
||||
if len(originalReq.Host) > 0 && upstreamReq.Header.Get("X-Forwarded-Host") == "" {
|
||||
upstreamReq.Header["X-Forwarded-Host"] = []string{originalReq.Host}
|
||||
}
|
||||
if upstreamReq.Header.Get("X-Forwarded-For") == "" {
|
||||
upstreamReq.Header["X-Forwarded-For"] = []string{originalReq.RemoteAddr}
|
||||
}
|
||||
|
||||
if originalReq.Body != nil {
|
||||
upstreamReq.Body = originalReq.Body
|
||||
}
|
||||
|
||||
return upstreamReq, nil
|
||||
}
|
||||
|
||||
// copyHeaders clones the header values from the source into the destination.
|
||||
func copyHeaders(destination http.Header, source *http.Header) {
|
||||
for k, v := range *source {
|
||||
vClone := make([]string, len(v))
|
||||
copy(vClone, v)
|
||||
destination[k] = vClone
|
||||
}
|
||||
}
|
||||
|
||||
// getContentType resolves the correct Content-Type for a proxied function.
|
||||
func getContentType(request http.Header, proxyResponse http.Header) (headerContentType string) {
|
||||
responseHeader := proxyResponse.Get("Content-Type")
|
||||
requestHeader := request.Get("Content-Type")
|
||||
|
||||
if len(responseHeader) > 0 {
|
||||
headerContentType = responseHeader
|
||||
} else if len(requestHeader) > 0 {
|
||||
headerContentType = requestHeader
|
||||
} else {
|
||||
headerContentType = defaultContentType
|
||||
}
|
||||
|
||||
return headerContentType
|
||||
}
|
||||
|
||||
// writeError sets the response status code and write formats the provided message as the
|
||||
// response body
|
||||
func writeError(w http.ResponseWriter, statusCode int, msg string, args ...interface{}) {
|
||||
w.WriteHeader(statusCode)
|
||||
w.Write([]byte(fmt.Sprintf(msg, args...)))
|
||||
}
|
385
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy_test.go
generated
vendored
Normal file
385
gateway/vendor/github.com/openfaas/faas-provider/proxy/proxy_test.go
generated
vendored
Normal file
@ -0,0 +1,385 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func varHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(fmt.Sprintf("name: %s params: %s", vars["name"], vars["params"])))
|
||||
}
|
||||
|
||||
func testResolver(functionName string) (url.URL, error) {
|
||||
return url.URL{
|
||||
Scheme: "http",
|
||||
Host: functionName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Test_pathParsing(t *testing.T) {
|
||||
tt := []struct {
|
||||
name string
|
||||
functionPath string
|
||||
functionName string
|
||||
extraPath string
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
"simple_name_match",
|
||||
"/function/echo",
|
||||
"echo",
|
||||
"",
|
||||
200,
|
||||
},
|
||||
{
|
||||
"simple_name_match_with_trailing_slash",
|
||||
"/function/echo/",
|
||||
"echo",
|
||||
"",
|
||||
200,
|
||||
},
|
||||
{
|
||||
"name_match_with_additional_path_values",
|
||||
"/function/echo/subPath/extras",
|
||||
"echo",
|
||||
"subPath/extras",
|
||||
200,
|
||||
},
|
||||
{
|
||||
"name_match_with_additional_path_values_and_querystring",
|
||||
"/function/echo/subPath/extras?query=true",
|
||||
"echo",
|
||||
"subPath/extras",
|
||||
200,
|
||||
},
|
||||
{
|
||||
"not_found_if_no_name",
|
||||
"/function/",
|
||||
"",
|
||||
"",
|
||||
404,
|
||||
},
|
||||
}
|
||||
|
||||
// Need to create a router that we can pass the request through so that the vars will be added to the context
|
||||
router := mux.NewRouter()
|
||||
router.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}", varHandler)
|
||||
router.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/", varHandler)
|
||||
router.HandleFunc("/function/{name:[-a-zA-Z_0-9]+}/{params:.*}", varHandler)
|
||||
|
||||
for _, s := range tt {
|
||||
t.Run(s.name, func(t *testing.T) {
|
||||
rr := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", s.functionPath, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
router.ServeHTTP(rr, req)
|
||||
if rr.Code != s.statusCode {
|
||||
t.Fatalf("unexpected status code; got: %d, expected: %d", rr.Code, s.statusCode)
|
||||
}
|
||||
|
||||
body := rr.Body.String()
|
||||
expectedBody := fmt.Sprintf("name: %s params: %s", s.functionName, s.extraPath)
|
||||
if s.statusCode == http.StatusOK && body != expectedBody {
|
||||
t.Fatalf("incorrect function name and path params; got: %s, expected: %s", body, expectedBody)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_Body_Method_Query(t *testing.T) {
|
||||
srcBytes := []byte("hello world")
|
||||
|
||||
reader := bytes.NewReader(srcBytes)
|
||||
request, _ := http.NewRequest(http.MethodPost, "/?code=1", 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()
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("funcName")
|
||||
upstream, err := buildProxyRequest(request, funcURL, "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_NoBody_GetMethod_NoQuery(t *testing.T) {
|
||||
request, _ := http.NewRequest(http.MethodGet, "/", nil)
|
||||
|
||||
funcURL, _ := testResolver("funcName")
|
||||
upstream, err := buildProxyRequest(request, funcURL, "")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if request.Method != upstream.Method {
|
||||
t.Errorf("Method - want: %s, got: %s", request.Method, upstream.Method)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if upstream.Body != nil {
|
||||
t.Errorf("Body - expected nil")
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_HasXForwardedHostHeaderWhenSet(t *testing.T) {
|
||||
srcBytes := []byte("hello world")
|
||||
|
||||
reader := bytes.NewReader(srcBytes)
|
||||
request, err := http.NewRequest(http.MethodPost, "http://gateway/function?code=1", reader)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("funcName")
|
||||
upstream, err := buildProxyRequest(request, funcURL, "/")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if request.Host != upstream.Header.Get("X-Forwarded-Host") {
|
||||
t.Errorf("Host - want: %s, got: %s", request.Host, upstream.Header.Get("X-Forwarded-Host"))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_XForwardedHostHeader_Empty_WhenNotSet(t *testing.T) {
|
||||
srcBytes := []byte("hello world")
|
||||
|
||||
reader := bytes.NewReader(srcBytes)
|
||||
request, err := http.NewRequest(http.MethodPost, "/function", reader)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("funcName")
|
||||
upstream, err := buildProxyRequest(request, funcURL, "/")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if request.Host != upstream.Header.Get("X-Forwarded-Host") {
|
||||
t.Errorf("Host - want: %s, got: %s", request.Host, upstream.Header.Get("X-Forwarded-Host"))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_XForwardedHostHeader_WhenAlreadyPresent(t *testing.T) {
|
||||
srcBytes := []byte("hello world")
|
||||
headerValue := "test.openfaas.com"
|
||||
reader := bytes.NewReader(srcBytes)
|
||||
request, err := http.NewRequest(http.MethodPost, "/function/test", reader)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
request.Header.Set("X-Forwarded-Host", headerValue)
|
||||
funcURL, _ := testResolver("funcName")
|
||||
upstream, err := buildProxyRequest(request, funcURL, "/")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
if upstream.Header.Get("X-Forwarded-Host") != headerValue {
|
||||
t.Errorf("X-Forwarded-Host - want: %s, got: %s", headerValue, upstream.Header.Get("X-Forwarded-Host"))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_buildProxyRequest_WithPathNoQuery(t *testing.T) {
|
||||
srcBytes := []byte("hello world")
|
||||
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()
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("xyz")
|
||||
upstream, err := buildProxyRequest(request, funcURL, functionPath)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
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_buildProxyRequest_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()
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("xyz")
|
||||
upstream, err := buildProxyRequest(request, funcURL, functionPath)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
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_buildProxyRequest_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()
|
||||
}
|
||||
|
||||
funcURL, _ := testResolver("xyz")
|
||||
upstream, err := buildProxyRequest(request, funcURL, functionPath)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user