3
0
Files
corteza/pkg/apigw/processer_test.go
Peter Grlica da9100287c Refactored services, rest and rdbms
Added tests

Added ac to routes and functions

Proxy processer and auth servicer

Added options and extensive logging

Fixed calls to rbac in service, added default http handler on gateway root
2021-08-11 17:25:10 +02:00

196 lines
5.5 KiB
Go

package apigw
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/cortezaproject/corteza-server/pkg/options"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
)
func Test_processerProxy(t *testing.T) {
type (
exp struct {
Status int
Header http.Header
Body *bytes.Buffer
}
tf struct {
name string
err string
params string
exp exp
rq *http.Request
fn func(*require.Assertions) mockRoundTripper
}
)
var (
tcc = []tf{
{
name: "proxy processer with auth headers",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
rs = &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader("default response")),
}
return
}
},
params: `{"location": "/foo", "auth": {"type": "header", "params": {"access-token": "123", "client": "456"}}}`,
exp: exp{
Status: http.StatusOK,
Header: http.Header{"Content-Type": []string{"text/plain; charset=utf-8"}},
Body: bytes.NewBufferString("default response"),
},
},
{
name: "proxy processer with auth query params",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
rs = &http.Response{}
req.Equal("access-param=123%2B456", r.URL.RawQuery)
return
}
},
params: `{"location": "/foo", "auth": {"type": "query", "params": {"access-param": "123+456"}}}`,
exp: exp{
Status: http.StatusOK,
Header: http.Header{"Content-Type": []string{"text/plain; charset=utf-8"}},
Body: bytes.NewBuffer(nil),
},
},
{
name: "proxy processer with auth headers unauthorized",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
rs = &http.Response{
StatusCode: http.StatusUnauthorized,
Body: io.NopCloser(strings.NewReader("unauthorized response")),
}
return
}
},
params: `{"location": "/foo", "auth": {"type": "header", "params": {"access-token": "123", "client": "456"}}}`,
exp: exp{
Status: http.StatusUnauthorized,
Header: http.Header{"Content-Type": []string{"text/plain; charset=utf-8"}},
Body: bytes.NewBufferString("unauthorized response"),
},
},
{
name: "proxy processer params parse error",
params: `{"location": "invalid url", "auth": {"type": "header", "params": {}}}`,
err: `could not parse destination location for proxying: parse "invalid url": invalid URI for request`,
},
{
name: "proxy processer params request error",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
err = fmt.Errorf("error on client.Do")
return
}
},
params: `{"location": "https://example.com", "auth": {"type": "header", "params": {}}}`,
err: `could not proxy request: Post "https://example.com": error on client.Do`,
},
{
name: "proxy processer hop headers removed",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
rs = &http.Response{
Header: http.Header{
"Proxy-Authenticate": []string{`Basic realm="Access to the internal site"`},
"Content-Type": []string{"application/json; charset=utf-8"},
},
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader("default response")),
}
return
}
},
params: `{"location": "https://example.com", "auth": {"type": "header", "params": {}}}`,
exp: exp{
Status: http.StatusUnauthorized,
Header: http.Header{"Content-Type": []string{"application/json; charset=utf-8"}},
Body: bytes.NewBufferString("default response"),
},
},
{
name: "proxy processer query parameters merged",
fn: func(req *require.Assertions) mockRoundTripper {
return func(r *http.Request) (rs *http.Response, err error) {
rs = &http.Response{}
req.Equal("access-param=123%2B456&addedCustomQueryParam=true", r.URL.RawQuery)
return
}
},
params: `{"location": "https://example.com", "auth": {"type": "query", "params": {"access-param": "123+456"}}}`,
exp: exp{
Status: http.StatusUnauthorized,
Header: http.Header{"Content-Type": []string{"text/plain; charset=utf-8"}},
Body: bytes.NewBuffer(nil),
},
rq: &http.Request{
Header: http.Header{},
URL: &url.URL{Path: "/foo", RawQuery: "addedCustomQueryParam=true"},
Body: http.NoBody,
Method: "POST",
},
},
}
)
for _, tc := range tcc {
t.Run(tc.name, func(t *testing.T) {
var (
ctx = context.Background()
req = require.New(t)
c = http.DefaultClient
rq = tc.rq
)
if tc.fn != nil {
c.Transport = mockRoundTripper(tc.fn(req))
}
if rq == nil {
rq, _ = http.NewRequest("POST", "/foo", strings.NewReader(`custom request body`))
}
proxy := NewProcesserProxy(zap.NewNop(), c)
proxy.Merge([]byte(tc.params))
scope := &scp{
"request": rq,
"writer": httptest.NewRecorder(),
"opts": options.Apigw(),
}
err := proxy.Exec(ctx, scope)
if tc.err != "" {
req.EqualError(err, tc.err)
} else {
req.NoError(err)
req.Equal(tc.exp.Header, scope.Writer().(*httptest.ResponseRecorder).Header())
req.Equal(tc.exp.Body, scope.Writer().(*httptest.ResponseRecorder).Body)
}
})
}
}