Skip to content

Commit

Permalink
Implement proxying test cases (#14831)
Browse files Browse the repository at this point in the history
* Implement simple proxy cases

They test response codes and bodies

* Add timeout endpoint

* Add timeout test case

* Cleanup test placement

* Return response body

Now it's possible to log response bodies AND verify the content.
It's also possible to inspect whole responses in tests.

* Move timeout to negative authorisation

* Remove status verification from body tests

* Separate edge-cases

* Bump images

* Merge test files
  • Loading branch information
VOID404 authored Jul 21, 2022
1 parent caa027a commit df311bc
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ func SetupRoutes(logOut io.Writer, basicAuthCredentials BasicAuthCredentials, oA
r := api.PathPrefix("/unsecure").Subrouter()
r.HandleFunc("/ok", alwaysOk).Methods(http.MethodGet)
r.HandleFunc("/echo", echo)
r.HandleFunc("/code/{code:[0-9]+}", resCode)
r.HandleFunc("/timeout", timeout)
}
{
r := api.PathPrefix("/basic").Subrouter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import (
"io/ioutil"
"log"
"net/http"
"strconv"
"time"

"github.com/gorilla/mux"
)

func alwaysOk(w http.ResponseWriter, _ *http.Request) {
Expand Down Expand Up @@ -39,3 +43,27 @@ func echo(w http.ResponseWriter, r *http.Request) {
log.Println("Couldn't encode the response body to JSON:", r.URL)
}
}

// resCode should only be used in paths with `code`
// parameter, that is a valid int
func resCode(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
codeStr := vars["code"] // must exist, because path has a pattern
code, _ := strconv.Atoi(codeStr) // can't error, because path has a pattern
w.WriteHeader(code)
w.Write([]byte(codeStr))
}

func timeout(w http.ResponseWriter, r *http.Request) {
c := r.Context().Done()
if c == nil {
log.Println("Context has no timeout, sleeping for 2 minutes")
time.Sleep(2 * time.Minute)
return
}
log.Println("Context timeout, waiting until done")

_ = <-c

alwaysOk(w, r)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apiVersion: applicationconnector.kyma-project.io/v1alpha1
kind: Application
metadata:
name: proxy-errors
namespace: "{{ .Values.namespace }}"
spec:
description: Proxying edge cases
skipVerify: true
labels:
app: proxy-errors
services:
- displayName: code 123
name: code 123
providerDisplayName: code 123
description: Should return 503, receiving unknown informational codes
id: "{{ uuidv4 }}"
entries:
- type: API
targetUrl: "http://{{ .Values.mockServiceName }}.{{ .Values.namespace }}.svc.cluster.local:8080/v1/api/unsecure/code/123"
centralGatewayUrl: "http://central-application-gateway.kyma-system:8080/proxy-errors/code-123"
- displayName: timeout
name: timeout
providerDisplayName: timeout
description: Should return 503 when target times out
id: "{{ uuidv4 }}"
entries:
- type: API
targetUrl: "http://{{ .Values.mockServiceName }}.{{ .Values.namespace }}.svc.cluster.local:8080/v1/api/unsecure/timeout"
centralGatewayUrl: "http://central-application-gateway.kyma-system:8080/proxy-errors/timeout"
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: applicationconnector.kyma-project.io/v1alpha1
kind: Application
metadata:
name: proxy-cases
namespace: "{{ .Values.namespace }}"
spec:
description: Proxying
skipVerify: true
labels:
app: proxy-cases
services:
- displayName: code 451
name: code 451
providerDisplayName: code 451
description: Should return 451 forwarded from target endpoint
id: "{{ uuidv4 }}"
entries:
- type: API
targetUrl: "http://{{ .Values.mockServiceName }}.{{ .Values.namespace }}.svc.cluster.local:8080/v1/api/unsecure/code/451"
centralGatewayUrl: "http://central-application-gateway.kyma-system:8080/proxy-cases/code-451"
- displayName: code 307
name: code 307
providerDisplayName: code 307
description: Should return 307 forwarded from target endpoint
id: "{{ uuidv4 }}"
entries:
- type: API
targetUrl: "http://{{ .Values.mockServiceName }}.{{ .Values.namespace }}.svc.cluster.local:8080/v1/api/unsecure/code/307"
centralGatewayUrl: "http://central-application-gateway.kyma-system:8080/proxy-cases/code-307"
- displayName: code 203
name: code 203
providerDisplayName: code 203
description: Should return 203 forwarded from target endpoint
id: "{{ uuidv4 }}"
entries:
- type: API
targetUrl: "http://{{ .Values.mockServiceName }}.{{ .Values.namespace }}.svc.cluster.local:8080/v1/api/unsecure/code/203"
centralGatewayUrl: "http://central-application-gateway.kyma-system:8080/proxy-cases/code-203"
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ containerRegistry:
images:
gatewayTest:
name: "gateway-test"
version: "PR-14845"
version: "PR-14831"

mockApplication:
name: "mock-app"
version: "PR-14845"
version: "PR-14831"
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package application_gateway

import (
"net/http"
"time"
)

func (gs *GatewaySuite) TestComplex() {
gs.Run("OAuth token renewal", func() {
http := NewHttpCli(gs.T())

url := gatewayURL("complex-cases", "oauth-expired-token-renewal")
gs.T().Log("Url:", url)

// Authorize, then call endpoint
res, err := http.Get(url)
logBody(gs.T(), res.Body)
res, _, err := http.Get(url)
gs.Nil(err, "First request failed")
gs.Equal(200, res.StatusCode, "First request failed")

time.Sleep(10 * time.Second) // wait for token to expire

// Call endpoint, requiring token renewall
res, err = http.Get(url)
logBody(gs.T(), res.Body)
res, _, err = http.Get(url)
gs.Nil(err, "Second request failed")
gs.Equal(200, res.StatusCode, "Second request failed")
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,50 @@ package application_gateway

import (
"io"
"io/ioutil"
"net/http"
"regexp"
"strconv"
"testing"

"github.com/kyma-project/kyma/components/application-operator/pkg/apis/applicationconnector/v1alpha1"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)

func logBody(t *testing.T, body io.Reader) {
t.Helper()
type LogHttp struct {
t *testing.T
httpCli *http.Client
}

func NewHttpCli(t *testing.T) LogHttp {
return LogHttp{t: t, httpCli: &http.Client{}}
}

buf, err := ioutil.ReadAll(body)
if err == nil && len(buf) > 0 {
t.Log("Body:", string(buf))
func (c LogHttp) Get(url string) (resp *http.Response, body []byte, err error) {
c.t.Helper()
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return
}

return c.Do(req)

}

func executeGetRequest(t *testing.T, entry v1alpha1.Entry) int {
t.Helper()
func (c LogHttp) Do(req *http.Request) (res *http.Response, body []byte, err error) {
c.t.Helper()
c.t.Logf("%s %s", req.Method, req.URL)

t.Log("Calling", entry.CentralGatewayUrl)
res, err := http.Get(entry.CentralGatewayUrl)
res, err = c.httpCli.Do(req)
if err != nil {
return
}

if err == nil {
logBody(t, res.Body)
body, err = io.ReadAll(res.Body)
if err == nil && len(body) > 0 {
c.t.Logf("Body: %s", body)
}
assert.Nil(t, err)
return res.StatusCode

return
}

func getExpectedHTTPCode(service v1alpha1.Service) (int, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package application_gateway

import (
"context"
"strconv"

v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var applications = []string{"positive-authorisation", "negative-authorisation", "path-related-error-handling", "missing-resources-error-handling"}
var applications = []string{"positive-authorisation", "negative-authorisation", "path-related-error-handling", "missing-resources-error-handling", "proxy-cases", "proxy-errors"}

func (gs *GatewaySuite) TestGetRequest() {

Expand All @@ -16,6 +18,8 @@ func (gs *GatewaySuite) TestGetRequest() {
gs.Run(app.Spec.Description, func() {
for _, service := range app.Spec.Services {
gs.Run(service.Description, func() {
http := NewHttpCli(gs.T())

for _, entry := range service.Entries {
if entry.Type != "API" {
gs.T().Log("Skipping event entry")
Expand All @@ -28,12 +32,42 @@ func (gs *GatewaySuite) TestGetRequest() {
gs.T().Fail()
}

actualCode := executeGetRequest(gs.T(), entry)

gs.Equal(expectedCode, actualCode)
res, _, err := http.Get(entry.CentralGatewayUrl)
gs.Nil(err, "Request failed")
gs.Equal(expectedCode, res.StatusCode, "Incorrect response code")
}
})
}
})
}
}

func (gs *GatewaySuite) TestResponseBody() {
app, err := gs.cli.ApplicationconnectorV1alpha1().Applications().Get(context.Background(), "proxy-cases", v1.GetOptions{})
gs.Nil(err)
for _, service := range app.Spec.Services {
gs.Run(service.Description, func() {
http := NewHttpCli(gs.T())

for _, entry := range service.Entries {
if entry.Type != "API" {
gs.T().Log("Skipping event entry")
continue
}

expectedCode, err := getExpectedHTTPCode(service)
if err != nil {
gs.T().Log("Error during getting the error code from description -> applicationCRD")
gs.T().Fail()
}

_, body, err := http.Get(entry.CentralGatewayUrl)
gs.Nil(err, "Request failed")

codeStr := strconv.Itoa(expectedCode)

gs.Equal(codeStr, string(body), "Incorrect body")
}
})
}
}

0 comments on commit df311bc

Please sign in to comment.