Skip to content

Commit

Permalink
Merge pull request #188 from devopsfaith/router_integration_tests
Browse files Browse the repository at this point in the history
Extend integration tests
  • Loading branch information
kpacha committed Jan 27, 2019
2 parents 08ea8f0 + 5996da4 commit 9260022
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 74 deletions.
11 changes: 10 additions & 1 deletion router/mux/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"regexp"
"strings"

"github.com/devopsfaith/krakend/config"
Expand Down Expand Up @@ -103,6 +104,7 @@ var NewRequest = NewRequestBuilder(func(_ *http.Request) map[string]string {
// NewRequestBuilder gets a RequestBuilder with the received ParamExtractor as a query param
// extraction mechanism
func NewRequestBuilder(paramExtractor ParamExtractor) RequestBuilder {
var re = regexp.MustCompile(`^\[?([\d.:]+)\]?(:[\d]*)$`)
return func(r *http.Request, queryString, headersToSend []string) *proxy.Request {
params := paramExtractor(r)
headers := make(map[string][]string, 2+len(headersToSend))
Expand All @@ -118,7 +120,14 @@ func NewRequestBuilder(paramExtractor ParamExtractor) RequestBuilder {
headers[k] = h
}
}
headers["X-Forwarded-For"] = []string{r.RemoteAddr}

matches := re.FindAllStringSubmatch(r.RemoteAddr, -1)

if len(matches) > 0 && len(matches[0]) > 1 {
headers["X-Forwarded-For"] = []string{matches[0][1]}
} else {
headers["X-Forwarded-For"] = []string{r.RemoteAddr}
}
headers["User-Agent"] = router.UserAgentHeaderValue

query := make(map[string][]string, len(queryString))
Expand Down
243 changes: 170 additions & 73 deletions test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,63 @@ package test

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math/rand"
"net"
"net/http"
"net/http/httptest"
"strings"
"testing"
"text/template"
"time"

"github.com/urfave/negroni"

"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/logging"
"github.com/devopsfaith/krakend/proxy"
"github.com/devopsfaith/krakend/router/gin"
"github.com/devopsfaith/krakend/router/gorilla"
krakendnegroni "github.com/devopsfaith/krakend/router/negroni"
)

func TestKrakenD(t *testing.T) {
func TestKrakenD_ginRouter(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

testKrakenD(t, func(logger logging.Logger, cfg *config.ServiceConfig) {
gin.DefaultFactory(proxy.DefaultFactory(logger), logger).NewWithContext(ctx).Run(*cfg)
})
}

func TestKrakenD_gorillaRouter(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

config.RoutingPattern = config.BracketsRouterPatternBuilder
testKrakenD(t, func(logger logging.Logger, cfg *config.ServiceConfig) {
gorilla.DefaultFactory(proxy.DefaultFactory(logger), logger).NewWithContext(ctx).Run(*cfg)
})
config.RoutingPattern = config.ColonRouterPatternBuilder
}

func TestKrakenD_negroniRouter(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

config.RoutingPattern = config.BracketsRouterPatternBuilder
testKrakenD(t, func(logger logging.Logger, cfg *config.ServiceConfig) {
factory := krakendnegroni.DefaultFactory(proxy.DefaultFactory(logger), logger, []negroni.Handler{})
factory.NewWithContext(ctx).Run(*cfg)
})
config.RoutingPattern = config.ColonRouterPatternBuilder
}

func testKrakenD(t *testing.T, runRouter func(logging.Logger, *config.ServiceConfig)) {
cfg, err := setupBackend(t)
if err != nil {
t.Error(err)
Expand All @@ -35,9 +74,23 @@ func TestKrakenD(t *testing.T) {
return
}

go func() {
gin.DefaultFactory(proxy.DefaultFactory(logger), logger).New().Run(*cfg)
}()
go runRouter(logger, cfg)

select {
case <-time.After(300 * time.Millisecond):
}

defaultHeaders := map[string]string{
"Content-Type": "application/json",
"X-KrakenD-Completed": "true",
"X-Krakend": "Version undefined",
}

incompleteHeader := map[string]string{
"Content-Type": "application/json",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
}

for _, tc := range []struct {
name string
Expand All @@ -49,15 +102,11 @@ func TestKrakenD(t *testing.T) {
expHeaders map[string]string
}{
{
name: "static",
url: "/static",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
},
expBody: `{"bar":"foobar","foo":42}`,
name: "static",
url: "/static",
headers: map[string]string{},
expHeaders: incompleteHeader,
expBody: `{"bar":"foobar","foo":42}`,
},
{
name: "param_forwarding",
Expand All @@ -68,75 +117,106 @@ func TestKrakenD(t *testing.T) {
"Authorization": "bearer AuthorizationToken",
"X-Y-Z": "x-y-z",
},
body: `{"foo":"bar"}`,
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "true",
"X-Krakend": "Version undefined",
},
expBody: `{"path":"/foo"}`,
body: `{"foo":"bar"}`,
expHeaders: defaultHeaders,
expBody: `{"path":"/foo"}`,
},
{
name: "timeout",
url: "/timeout",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
},
expBody: `{"email":"some@email.com","name":"a"}`,
name: "timeout",
url: "/timeout",
headers: map[string]string{},
expHeaders: incompleteHeader,
expBody: `{"email":"some@email.com","name":"a"}`,
},
{
name: "partial_with_static",
url: "/partial/static",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
},
expBody: `{"bar":"foobar","email":"some@email.com","foo":42,"name":"a"}`,
name: "partial_with_static",
url: "/partial/static",
headers: map[string]string{},
expHeaders: incompleteHeader,
expBody: `{"bar":"foobar","email":"some@email.com","foo":42,"name":"a"}`,
},
{
name: "partial",
url: "/partial",
headers: map[string]string{},
expHeaders: incompleteHeader,
expBody: `{"email":"some@email.com","name":"a"}`,
},
{
name: "combination",
url: "/combination",
headers: map[string]string{},
expHeaders: defaultHeaders,
expBody: `{"name":"a","personal_email":"some@email.com","posts":[{"body":"some content","date":"123456789"},{"body":"some other content","date":"123496789"}]}`,
},
{
name: "detail_error",
url: "/detail_error",
headers: map[string]string{},
expHeaders: incompleteHeader,
expBody: `{"email":"some@email.com","error_backend_a":{"http_status_code":429,"http_body":"sad panda\n"},"name":"a"}`,
},
{
name: "querystring-params-no-params",
url: "/querystring-params-test/no-params?a=1&b=2&c=3",
headers: map[string]string{},
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"]},"path":"/no-params","query":{}}`,
},
{
name: "querystring-params-optional-query-params",
url: "/querystring-params-test/query-params?a=1&b=2&c=3",
headers: map[string]string{},
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"]},"path":"/query-params","query":{"a":["1"],"b":["2"]}}`,
},
{
name: "querystring-params-mandatory-query-params",
url: "/querystring-params-test/url-params/some?a=1&b=2&c=3",
headers: map[string]string{},
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"]},"path":"/url-params","query":{"p":["some"]}}`,
},
{
name: "querystring-params-all",
url: "/querystring-params-test/all-params?a=1&b=2&c=3",
headers: map[string]string{},
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"]},"path":"/all-params","query":{"a":["1"],"b":["2"],"c":["3"]}}`,
},
{
name: "partial",
url: "/partial",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
name: "header-params-none",
url: "/header-params-test/no-params",
headers: map[string]string{
"x-Test-1": "some",
"X-TEST-2": "none",
},
expBody: `{"email":"some@email.com","name":"a"}`,
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"]},"path":"/no-params","query":{}}`,
},
{
name: "combination",
url: "/combination",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "true",
"X-Krakend": "Version undefined",
name: "header-params-filter",
url: "/header-params-test/filter-params",
headers: map[string]string{
"x-tESt-1": "some",
"X-TEST-2": "none",
},
expBody: `{"name":"a","personal_email":"some@email.com","posts":[{"body":"some content","date":"123456789"},{"body":"some other content","date":"123496789"}]}`,
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"],"X-Test-1":["some"]},"path":"/filter-params","query":{}}`,
},
{
name: "detail_error",
url: "/detail_error",
headers: map[string]string{},
expHeaders: map[string]string{
"Content-Type": "application/json; charset=utf-8",
"X-KrakenD-Completed": "false",
"X-Krakend": "Version undefined",
name: "header-params-all",
url: "/header-params-test/all-params",
headers: map[string]string{
"x-Test-1": "some",
"X-TEST-2": "none",
},
expBody: `{"email":"some@email.com","error_backend_a":{"http_status_code":429,"http_body":"sad panda\n"},"name":"a"}`,
expHeaders: defaultHeaders,
expBody: `{"headers":{"Accept-Encoding":["gzip"],"User-Agent":["KrakenD Version undefined"],"X-Test-1":["some"],"X-Test-2":["none"]},"path":"/all-params","query":{}}`,
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
time.Sleep(300 * time.Millisecond)

if tc.method == "" {
tc.method = "GET"
}
Expand All @@ -146,7 +226,9 @@ func TestKrakenD(t *testing.T) {
body = bytes.NewBufferString(tc.body)
}

r, _ := http.NewRequest(tc.method, fmt.Sprintf("http://localhost:%d%s", cfg.Port, tc.url), body)
url := fmt.Sprintf("http://localhost:%d%s", cfg.Port, tc.url)

r, _ := http.NewRequest(tc.method, url, body)
for k, v := range tc.headers {
r.Header.Add(k, v)
}
Expand All @@ -161,21 +243,20 @@ func TestKrakenD(t *testing.T) {
return
}

if resp.StatusCode != http.StatusOK {
t.Errorf("%s: unexpected status code: %d", resp.Request.URL.Path, resp.StatusCode)
}

for k, v := range tc.expHeaders {
if c := resp.Header.Get(k); c != v {
if c := resp.Header.Get(k); !strings.Contains(c, v) {
t.Errorf("%s: unexpected header %s: %s", resp.Request.URL.Path, k, c)
return
}
}
if resp.StatusCode != http.StatusOK {
t.Errorf("%s: unexpected status code: %d", resp.Request.URL.Path, resp.StatusCode)
return
}
b, _ := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if tc.expBody != string(b) {
t.Errorf("%s: unexpected body: %s", resp.Request.URL.Path, string(b))
return
fmt.Println(resp.Request.URL.Path, "was expecting:", tc.expBody)
}
})
}
Expand Down Expand Up @@ -247,6 +328,22 @@ func setupBackend(t *testing.T) (*config.ServiceConfig, error) {
}))
data["b5"] = b5.URL

// querystring-forwarding backend
b6 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add("Content-Type", "application/json")
if ip := net.ParseIP(r.Header.Get("X-Forwarded-For")); ip == nil || !ip.IsLoopback() {
http.Error(rw, "invalid X-Forwarded-For", 400)
return
}
r.Header.Del("X-Forwarded-For")
json.NewEncoder(rw).Encode(map[string]interface{}{
"path": r.URL.Path,
"query": r.URL.Query(),
"headers": r.Header,
})
}))
data["b6"] = b6.URL

c, err := loadConfig(data)
if err != nil {
return nil, err
Expand Down

0 comments on commit 9260022

Please sign in to comment.