mirror of
https://github.com/alibaba/higress.git
synced 2026-06-09 04:37:31 +08:00
refactor: higress test framework (#178)
Signed-off-by: bitliu <bitliu@tencent.com>
This commit is contained in:
@@ -30,42 +30,94 @@ var HTTPRouteHostNameSameNamespace = suite.ConformanceTest{
|
|||||||
Description: "A Ingress in the higress-conformance-infra namespace demonstrates host match ability",
|
Description: "A Ingress in the higress-conformance-infra namespace demonstrates host match ability",
|
||||||
Manifests: []string{"tests/httproute-hostname-same-namespace.yaml"},
|
Manifests: []string{"tests/httproute-hostname-same-namespace.yaml"},
|
||||||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
||||||
|
testcases := []http.Assertion{
|
||||||
|
{
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v1",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/foo",
|
||||||
|
Host: "foo.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v2",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/foo",
|
||||||
|
Host: "bar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v2",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/bar",
|
||||||
|
Host: "foo.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v3",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/bar",
|
||||||
|
Host: "bar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v1",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/any",
|
||||||
|
Host: "any.bar.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) {
|
t.Run("HTTP request should reach infra-backend with different hostname", func(t *testing.T) {
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
for _, testcase := range testcases {
|
||||||
Request: http.Request{Path: "/foo", Host: "foo.com"},
|
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, testcase)
|
||||||
Response: http.Response{StatusCode: 200},
|
}
|
||||||
Backend: "infra-backend-v1",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
|
||||||
|
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
|
||||||
Request: http.Request{Path: "/foo", Host: "bar.com"},
|
|
||||||
Response: http.Response{StatusCode: 200},
|
|
||||||
Backend: "infra-backend-v2",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
|
||||||
|
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
|
||||||
Request: http.Request{Path: "/bar", Host: "foo.com"},
|
|
||||||
Response: http.Response{StatusCode: 200},
|
|
||||||
Backend: "infra-backend-v2",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
|
||||||
|
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
|
||||||
Request: http.Request{Path: "/bar", Host: "bar.com"},
|
|
||||||
Response: http.Response{StatusCode: 200},
|
|
||||||
Backend: "infra-backend-v3",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
|
||||||
|
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
|
||||||
Request: http.Request{Path: "/any", Host: "any.bar.com"},
|
|
||||||
Response: http.Response{StatusCode: 200},
|
|
||||||
Backend: "infra-backend-v1",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,14 +32,24 @@ var HTTPRouteRewritePath = suite.ConformanceTest{
|
|||||||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
||||||
|
|
||||||
t.Run("Rewrite HTTPRoute Path", func(t *testing.T) {
|
t.Run("Rewrite HTTPRoute Path", func(t *testing.T) {
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.Assertion{
|
||||||
Request: http.Request{Path: "/svc/foo"},
|
Request: http.AssertionRequest{
|
||||||
ExpectedRequest: &http.ExpectedRequest{
|
ActualRequest: http.Request{Path: "/svc/foo"},
|
||||||
Request: http.Request{Path: "/foo"},
|
ExpectedRequest: &http.ExpectedRequest{
|
||||||
|
Request: http.Request{Path: "/foo"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Meta: http.AssertionMeta{
|
||||||
|
TargetBackend: "infra-backend-v1",
|
||||||
|
TargetNamespace: "higress-conformance-infra",
|
||||||
},
|
},
|
||||||
Response: http.Response{StatusCode: 200},
|
|
||||||
Backend: "infra-backend-v1",
|
|
||||||
Namespace: "higress-conformance-infra",
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -30,13 +30,22 @@ var HTTPRouteSimpleSameNamespace = suite.ConformanceTest{
|
|||||||
Description: "A single Ingress in the higress-conformance-infra namespace demonstrates basic routing ability",
|
Description: "A single Ingress in the higress-conformance-infra namespace demonstrates basic routing ability",
|
||||||
Manifests: []string{"tests/httproute-simple-same-namespace.yaml"},
|
Manifests: []string{"tests/httproute-simple-same-namespace.yaml"},
|
||||||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
|
||||||
|
|
||||||
t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) {
|
t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) {
|
||||||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.ExpectedResponse{
|
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, suite.GatewayAddress, http.Assertion{
|
||||||
Request: http.Request{Path: "/hello-world"},
|
Meta: http.AssertionMeta{
|
||||||
Response: http.Response{StatusCode: 200},
|
TargetBackend: "infra-backend-v1",
|
||||||
Backend: "infra-backend-v1",
|
TargetNamespace: "higress-conformance-infra",
|
||||||
Namespace: "higress-conformance-infra",
|
},
|
||||||
|
Request: http.AssertionRequest{
|
||||||
|
ActualRequest: http.Request{
|
||||||
|
Path: "/hello-world",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: http.AssertionResponse{
|
||||||
|
ExpectedResponse: http.Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,32 +25,40 @@ import (
|
|||||||
"github.com/alibaba/higress/test/ingress/conformance/utils/roundtripper"
|
"github.com/alibaba/higress/test/ingress/conformance/utils/roundtripper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExpectedResponse defines the response expected for a given request.
|
type Assertion struct {
|
||||||
type ExpectedResponse struct {
|
Meta AssertionMeta
|
||||||
// Request defines the request to make.
|
Request AssertionRequest
|
||||||
Request Request
|
Response AssertionResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssertionMeta struct {
|
||||||
|
// TestCaseName is the User Given TestCase name
|
||||||
|
TestCaseName string
|
||||||
|
// TargetBackend defines the target backend service
|
||||||
|
TargetBackend string
|
||||||
|
// TargetNamespace defines the target backend namespace
|
||||||
|
TargetNamespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AssertionRequest struct {
|
||||||
|
// ActualRequest defines the request to make.
|
||||||
|
ActualRequest Request
|
||||||
|
|
||||||
// ExpectedRequest defines the request that
|
// ExpectedRequest defines the request that
|
||||||
// is expected to arrive at the backend. If
|
// is expected to arrive at the backend. If
|
||||||
// not specified, the backend request will be
|
// not specified, the backend request will be
|
||||||
// expected to match Request.
|
// expected to match Request.
|
||||||
ExpectedRequest *ExpectedRequest
|
ExpectedRequest *ExpectedRequest
|
||||||
|
|
||||||
RedirectRequest *roundtripper.RedirectRequest
|
RedirectRequest *roundtripper.RedirectRequest
|
||||||
|
}
|
||||||
|
|
||||||
// BackendSetResponseHeaders is a set of headers
|
type AssertionResponse struct {
|
||||||
// the echoserver should set in its response.
|
// ExpectedResponse defines what response the test case
|
||||||
BackendSetResponseHeaders map[string]string
|
|
||||||
|
|
||||||
// Response defines what response the test case
|
|
||||||
// should receive.
|
// should receive.
|
||||||
Response Response
|
ExpectedResponse Response
|
||||||
|
// AdditionalResponseHeaders is a set of headers
|
||||||
Backend string
|
// the echoserver should set in its response.
|
||||||
Namespace string
|
AdditionalResponseHeaders map[string]string
|
||||||
|
|
||||||
// User Given TestCase name
|
|
||||||
TestCaseName string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request can be used as both the request to make and a means to verify
|
// Request can be used as both the request to make and a means to verify
|
||||||
@@ -91,38 +99,38 @@ const requiredConsecutiveSuccesses = 3
|
|||||||
//
|
//
|
||||||
// Once the request succeeds consistently with the response having the expected status code, make
|
// Once the request succeeds consistently with the response having the expected status code, make
|
||||||
// additional assertions on the response body using the provided ExpectedResponse.
|
// additional assertions on the response body using the provided ExpectedResponse.
|
||||||
func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, r roundtripper.RoundTripper, timeoutConfig config.TimeoutConfig, gwAddr string, expected ExpectedResponse) {
|
func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, r roundtripper.RoundTripper, timeoutConfig config.TimeoutConfig, gwAddr string, expected Assertion) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
if expected.Request.Method == "" {
|
if expected.Request.ActualRequest.Method == "" {
|
||||||
expected.Request.Method = "GET"
|
expected.Request.ActualRequest.Method = "GET"
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.Response.StatusCode == 0 {
|
if expected.Response.ExpectedResponse.StatusCode == 0 {
|
||||||
expected.Response.StatusCode = 200
|
expected.Response.ExpectedResponse.StatusCode = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("Making %s request to http://%s%s", expected.Request.Method, gwAddr, expected.Request.Path)
|
t.Logf("Making %s request to http://%s%s", expected.Request.ActualRequest.Method, gwAddr, expected.Request.ActualRequest.Path)
|
||||||
|
|
||||||
path, query, _ := strings.Cut(expected.Request.Path, "?")
|
path, query, _ := strings.Cut(expected.Request.ActualRequest.Path, "?")
|
||||||
|
|
||||||
req := roundtripper.Request{
|
req := roundtripper.Request{
|
||||||
Method: expected.Request.Method,
|
Method: expected.Request.ActualRequest.Method,
|
||||||
Host: expected.Request.Host,
|
Host: expected.Request.ActualRequest.Host,
|
||||||
URL: url.URL{Scheme: "http", Host: gwAddr, Path: path, RawQuery: query},
|
URL: url.URL{Scheme: "http", Host: gwAddr, Path: path, RawQuery: query},
|
||||||
Protocol: "HTTP",
|
Protocol: "HTTP",
|
||||||
Headers: map[string][]string{},
|
Headers: map[string][]string{},
|
||||||
UnfollowRedirect: expected.Request.UnfollowRedirect,
|
UnfollowRedirect: expected.Request.ActualRequest.UnfollowRedirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.Request.Headers != nil {
|
if expected.Request.ActualRequest.Headers != nil {
|
||||||
for name, value := range expected.Request.Headers {
|
for name, value := range expected.Request.ActualRequest.Headers {
|
||||||
req.Headers[name] = []string{value}
|
req.Headers[name] = []string{value}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backendSetHeaders := []string{}
|
backendSetHeaders := []string{}
|
||||||
for name, val := range expected.BackendSetResponseHeaders {
|
for name, val := range expected.Response.AdditionalResponseHeaders {
|
||||||
backendSetHeaders = append(backendSetHeaders, name+":"+val)
|
backendSetHeaders = append(backendSetHeaders, name+":"+val)
|
||||||
}
|
}
|
||||||
req.Headers["X-Echo-Set-Header"] = []string{strings.Join(backendSetHeaders, ",")}
|
req.Headers["X-Echo-Set-Header"] = []string{strings.Join(backendSetHeaders, ",")}
|
||||||
@@ -170,7 +178,7 @@ func awaitConvergence(t *testing.T, threshold int, maxTimeToConsistency time.Dur
|
|||||||
// WaitForConsistentResponse repeats the provided request until it completes with a response having
|
// WaitForConsistentResponse repeats the provided request until it completes with a response having
|
||||||
// the expected response consistently. The provided threshold determines how many times in
|
// the expected response consistently. The provided threshold determines how many times in
|
||||||
// a row this must occur to be considered "consistent".
|
// a row this must occur to be considered "consistent".
|
||||||
func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req roundtripper.Request, expected ExpectedResponse, threshold int, maxTimeToConsistency time.Duration) {
|
func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req roundtripper.Request, expected Assertion, threshold int, maxTimeToConsistency time.Duration) {
|
||||||
awaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool {
|
awaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool {
|
||||||
cReq, cRes, err := r.CaptureRoundTrip(req)
|
cReq, cRes, err := r.CaptureRoundTrip(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -188,43 +196,43 @@ func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req ro
|
|||||||
t.Logf("Request passed")
|
t.Logf("Request passed")
|
||||||
}
|
}
|
||||||
|
|
||||||
func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected ExpectedResponse) error {
|
func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected Assertion) error {
|
||||||
if expected.Response.StatusCode != cRes.StatusCode {
|
if expected.Response.ExpectedResponse.StatusCode != cRes.StatusCode {
|
||||||
return fmt.Errorf("expected status code to be %d, got %d", expected.Response.StatusCode, cRes.StatusCode)
|
return fmt.Errorf("expected status code to be %d, got %d", expected.Response.ExpectedResponse.StatusCode, cRes.StatusCode)
|
||||||
}
|
}
|
||||||
if cRes.StatusCode == 200 {
|
if cRes.StatusCode == 200 {
|
||||||
// The request expected to arrive at the backend is
|
// The request expected to arrive at the backend is
|
||||||
// the same as the request made, unless otherwise
|
// the same as the request made, unless otherwise
|
||||||
// specified.
|
// specified.
|
||||||
if expected.ExpectedRequest == nil {
|
if expected.Request.ExpectedRequest == nil {
|
||||||
expected.ExpectedRequest = &ExpectedRequest{Request: expected.Request}
|
expected.Request.ExpectedRequest = &ExpectedRequest{Request: expected.Request.ActualRequest}
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.ExpectedRequest.Method == "" {
|
if expected.Request.ExpectedRequest.Method == "" {
|
||||||
expected.ExpectedRequest.Method = "GET"
|
expected.Request.ExpectedRequest.Method = "GET"
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.ExpectedRequest.Host != "" && expected.ExpectedRequest.Host != cReq.Host {
|
if expected.Request.ExpectedRequest.Host != "" && expected.Request.ExpectedRequest.Host != cReq.Host {
|
||||||
return fmt.Errorf("expected host to be %s, got %s", expected.ExpectedRequest.Host, cReq.Host)
|
return fmt.Errorf("expected host to be %s, got %s", expected.Request.ExpectedRequest.Host, cReq.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.ExpectedRequest.Path != cReq.Path {
|
if expected.Request.ExpectedRequest.Path != cReq.Path {
|
||||||
return fmt.Errorf("expected path to be %s, got %s", expected.ExpectedRequest.Path, cReq.Path)
|
return fmt.Errorf("expected path to be %s, got %s", expected.Request.ExpectedRequest.Path, cReq.Path)
|
||||||
}
|
}
|
||||||
if expected.ExpectedRequest.Method != cReq.Method {
|
if expected.Request.ExpectedRequest.Method != cReq.Method {
|
||||||
return fmt.Errorf("expected method to be %s, got %s", expected.ExpectedRequest.Method, cReq.Method)
|
return fmt.Errorf("expected method to be %s, got %s", expected.Request.ExpectedRequest.Method, cReq.Method)
|
||||||
}
|
}
|
||||||
if expected.Namespace != cReq.Namespace {
|
if expected.Meta.TargetNamespace != cReq.Namespace {
|
||||||
return fmt.Errorf("expected namespace to be %s, got %s", expected.Namespace, cReq.Namespace)
|
return fmt.Errorf("expected namespace to be %s, got %s", expected.Meta.TargetNamespace, cReq.Namespace)
|
||||||
}
|
}
|
||||||
if expected.ExpectedRequest.Headers != nil {
|
if expected.Request.ExpectedRequest.Headers != nil {
|
||||||
if cReq.Headers == nil {
|
if cReq.Headers == nil {
|
||||||
return fmt.Errorf("no headers captured, expected %v", len(expected.ExpectedRequest.Headers))
|
return fmt.Errorf("no headers captured, expected %v", len(expected.Request.ExpectedRequest.Headers))
|
||||||
}
|
}
|
||||||
for name, val := range cReq.Headers {
|
for name, val := range cReq.Headers {
|
||||||
cReq.Headers[strings.ToLower(name)] = val
|
cReq.Headers[strings.ToLower(name)] = val
|
||||||
}
|
}
|
||||||
for name, expectedVal := range expected.ExpectedRequest.Headers {
|
for name, expectedVal := range expected.Request.ExpectedRequest.Headers {
|
||||||
actualVal, ok := cReq.Headers[strings.ToLower(name)]
|
actualVal, ok := cReq.Headers[strings.ToLower(name)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cReq.Headers)
|
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cReq.Headers)
|
||||||
@@ -235,15 +243,15 @@ func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedReques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.Response.Headers != nil {
|
if expected.Response.ExpectedResponse.Headers != nil {
|
||||||
if cRes.Headers == nil {
|
if cRes.Headers == nil {
|
||||||
return fmt.Errorf("no headers captured, expected %v", len(expected.ExpectedRequest.Headers))
|
return fmt.Errorf("no headers captured, expected %v", len(expected.Request.ExpectedRequest.Headers))
|
||||||
}
|
}
|
||||||
for name, val := range cRes.Headers {
|
for name, val := range cRes.Headers {
|
||||||
cRes.Headers[strings.ToLower(name)] = val
|
cRes.Headers[strings.ToLower(name)] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, expectedVal := range expected.Response.Headers {
|
for name, expectedVal := range expected.Response.ExpectedResponse.Headers {
|
||||||
actualVal, ok := cRes.Headers[strings.ToLower(name)]
|
actualVal, ok := cRes.Headers[strings.ToLower(name)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cRes.Headers)
|
return fmt.Errorf("expected %s header to be set, actual headers: %v", name, cRes.Headers)
|
||||||
@@ -253,12 +261,12 @@ func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedReques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(expected.Response.AbsentHeaders) > 0 {
|
if len(expected.Response.ExpectedResponse.AbsentHeaders) > 0 {
|
||||||
for name, val := range cRes.Headers {
|
for name, val := range cRes.Headers {
|
||||||
cRes.Headers[strings.ToLower(name)] = val
|
cRes.Headers[strings.ToLower(name)] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range expected.Response.AbsentHeaders {
|
for _, name := range expected.Response.ExpectedResponse.AbsentHeaders {
|
||||||
val, ok := cRes.Headers[strings.ToLower(name)]
|
val, ok := cRes.Headers[strings.ToLower(name)]
|
||||||
if ok {
|
if ok {
|
||||||
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
|
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
|
||||||
@@ -268,12 +276,12 @@ func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedReques
|
|||||||
|
|
||||||
// Verify that headers expected *not* to be present on the
|
// Verify that headers expected *not* to be present on the
|
||||||
// request are actually not present.
|
// request are actually not present.
|
||||||
if len(expected.ExpectedRequest.AbsentHeaders) > 0 {
|
if len(expected.Request.ExpectedRequest.AbsentHeaders) > 0 {
|
||||||
for name, val := range cReq.Headers {
|
for name, val := range cReq.Headers {
|
||||||
cReq.Headers[strings.ToLower(name)] = val
|
cReq.Headers[strings.ToLower(name)] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range expected.ExpectedRequest.AbsentHeaders {
|
for _, name := range expected.Request.ExpectedRequest.AbsentHeaders {
|
||||||
val, ok := cReq.Headers[strings.ToLower(name)]
|
val, ok := cReq.Headers[strings.ToLower(name)]
|
||||||
if ok {
|
if ok {
|
||||||
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
|
return fmt.Errorf("expected %s header to not be set, got %s", name, val)
|
||||||
@@ -281,74 +289,74 @@ func CompareRequest(req *roundtripper.Request, cReq *roundtripper.CapturedReques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(cReq.Pod, expected.Backend) {
|
if !strings.HasPrefix(cReq.Pod, expected.Meta.TargetBackend) {
|
||||||
return fmt.Errorf("expected pod name to start with %s, got %s", expected.Backend, cReq.Pod)
|
return fmt.Errorf("expected pod name to start with %s, got %s", expected.Meta.TargetBackend, cReq.Pod)
|
||||||
}
|
}
|
||||||
} else if roundtripper.IsRedirect(cRes.StatusCode) {
|
} else if roundtripper.IsRedirect(cRes.StatusCode) {
|
||||||
if expected.RedirectRequest == nil {
|
if expected.Request.RedirectRequest == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
setRedirectRequestDefaults(req, cRes, &expected)
|
setRedirectRequestDefaults(req, cRes, &expected)
|
||||||
|
|
||||||
if expected.RedirectRequest.Host != cRes.RedirectRequest.Host {
|
if expected.Request.RedirectRequest.Host != cRes.RedirectRequest.Host {
|
||||||
return fmt.Errorf("expected redirected hostname to be %s, got %s", expected.RedirectRequest.Host, cRes.RedirectRequest.Host)
|
return fmt.Errorf("expected redirected hostname to be %s, got %s", expected.Request.RedirectRequest.Host, cRes.RedirectRequest.Host)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Port != cRes.RedirectRequest.Port {
|
if expected.Request.RedirectRequest.Port != cRes.RedirectRequest.Port {
|
||||||
return fmt.Errorf("expected redirected port to be %s, got %s", expected.RedirectRequest.Port, cRes.RedirectRequest.Port)
|
return fmt.Errorf("expected redirected port to be %s, got %s", expected.Request.RedirectRequest.Port, cRes.RedirectRequest.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Scheme != cRes.RedirectRequest.Scheme {
|
if expected.Request.RedirectRequest.Scheme != cRes.RedirectRequest.Scheme {
|
||||||
return fmt.Errorf("expected redirected scheme to be %s, got %s", expected.RedirectRequest.Scheme, cRes.RedirectRequest.Scheme)
|
return fmt.Errorf("expected redirected scheme to be %s, got %s", expected.Request.RedirectRequest.Scheme, cRes.RedirectRequest.Scheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Path != cRes.RedirectRequest.Path {
|
if expected.Request.RedirectRequest.Path != cRes.RedirectRequest.Path {
|
||||||
return fmt.Errorf("expected redirected path to be %s, got %s", expected.RedirectRequest.Path, cRes.RedirectRequest.Path)
|
return fmt.Errorf("expected redirected path to be %s, got %s", expected.Request.RedirectRequest.Path, cRes.RedirectRequest.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get User-defined test case name or generate from expected response to a given request.
|
// Get User-defined test case name or generate from expected response to a given request.
|
||||||
func (er *ExpectedResponse) GetTestCaseName(i int) string {
|
func (er *Assertion) GetTestCaseName(i int) string {
|
||||||
|
|
||||||
// If TestCase name is provided then use that or else generate one.
|
// If TestCase name is provided then use that or else generate one.
|
||||||
if er.TestCaseName != "" {
|
if er.Meta.TestCaseName != "" {
|
||||||
return er.TestCaseName
|
return er.Meta.TestCaseName
|
||||||
}
|
}
|
||||||
|
|
||||||
headerStr := ""
|
headerStr := ""
|
||||||
reqStr := ""
|
reqStr := ""
|
||||||
|
|
||||||
if er.Request.Headers != nil {
|
if er.Request.ActualRequest.Headers != nil {
|
||||||
headerStr = " with headers"
|
headerStr = " with headers"
|
||||||
}
|
}
|
||||||
|
|
||||||
reqStr = fmt.Sprintf("%d request to '%s%s'%s", i, er.Request.Host, er.Request.Path, headerStr)
|
reqStr = fmt.Sprintf("%d request to '%s%s'%s", i, er.Request.ActualRequest.Host, er.Request.ActualRequest.Path, headerStr)
|
||||||
|
|
||||||
if er.Backend != "" {
|
if er.Meta.TargetBackend != "" {
|
||||||
return fmt.Sprintf("%s should go to %s", reqStr, er.Backend)
|
return fmt.Sprintf("%s should go to %s", reqStr, er.Meta.TargetBackend)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s should receive a %d", reqStr, er.Response.StatusCode)
|
return fmt.Sprintf("%s should receive a %d", reqStr, er.Response.ExpectedResponse.StatusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.CapturedResponse, expected *ExpectedResponse) {
|
func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.CapturedResponse, expected *Assertion) {
|
||||||
// If the expected host is nil it means we do not test host redirect.
|
// If the expected host is nil it means we do not test host redirect.
|
||||||
// In that case we are setting it to the one we got from the response because we do not know the ip/host of the gateway.
|
// In that case we are setting it to the one we got from the response because we do not know the ip/host of the gateway.
|
||||||
if expected.RedirectRequest.Host == "" {
|
if expected.Request.RedirectRequest.Host == "" {
|
||||||
expected.RedirectRequest.Host = cRes.RedirectRequest.Host
|
expected.Request.RedirectRequest.Host = cRes.RedirectRequest.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Port == "" {
|
if expected.Request.RedirectRequest.Port == "" {
|
||||||
expected.RedirectRequest.Port = req.URL.Port()
|
expected.Request.RedirectRequest.Port = req.URL.Port()
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Scheme == "" {
|
if expected.Request.RedirectRequest.Scheme == "" {
|
||||||
expected.RedirectRequest.Scheme = req.URL.Scheme
|
expected.Request.RedirectRequest.Scheme = req.URL.Scheme
|
||||||
}
|
}
|
||||||
|
|
||||||
if expected.RedirectRequest.Path == "" {
|
if expected.Request.RedirectRequest.Path == "" {
|
||||||
expected.RedirectRequest.Path = req.URL.Path
|
expected.Request.RedirectRequest.Path = req.URL.Path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user