Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions test/e2e/testdata/btp-timeout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: timeout
namespace: gateway-conformance-infra
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: http-btp-timeout
timeout:
http:
requestTimeout: 2s
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-btp-timeout
namespace: gateway-conformance-infra
spec:
parentRefs:
- name: same-namespace
rules:
- matches:
- path:
type: PathPrefix
value: /btp-timeout
backendRefs:
- name: infra-backend-v1
port: 8080
2 changes: 1 addition & 1 deletion test/e2e/testdata/client-timeout.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ spec:
- matches:
- path:
type: PathPrefix
value: /request-timeout
value: /client-timeout
backendRefs:
- name: infra-backend-v1
port: 8080
42 changes: 42 additions & 0 deletions test/e2e/tests/btp_timeout.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright Envoy Gateway Authors
// SPDX-License-Identifier: Apache-2.0
// The full text of the Apache license is available in the LICENSE file at
// the root of the repo.

//go:build e2e

package tests

import (
"net/http"
"testing"

"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
"sigs.k8s.io/gateway-api/conformance/utils/suite"
)

func init() {
ConformanceTests = append(ConformanceTests, BTPTimeoutTest)
}

var BTPTimeoutTest = suite.ConformanceTest{
ShortName: "BTPTimeout",
Description: "Test BackendTrafficPolicy timeout",
Manifests: []string{"testdata/btp-timeout.yaml"},
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
t.Run("HTTP", func(t *testing.T) {
routeNN := types.NamespacedName{Name: "http-btp-timeout", Namespace: ConformanceInfraNamespace}
gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName,
SameNamespaceGatewayRef, routeNN)

ExpectRequestTimeout(t, suite, gwAddr, "/btp-timeout", "", http.StatusOK)
// Timeout is 2s, so deplay 1s will return 200
ExpectRequestTimeout(t, suite, gwAddr, "/btp-timeout", "delay=1s", http.StatusOK)
// Timeout is 2s, so deplay 4s will return 504
ExpectRequestTimeout(t, suite, gwAddr, "/btp-timeout", "delay=4s", http.StatusGatewayTimeout)
})

// TODO: add test for TCP
},
}
39 changes: 4 additions & 35 deletions test/e2e/tests/client_timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,11 @@ package tests

import (
"net/http"
"net/url"
"testing"
"time"

"k8s.io/apimachinery/pkg/types"
httputils "sigs.k8s.io/gateway-api/conformance/utils/http"
"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
"sigs.k8s.io/gateway-api/conformance/utils/suite"
"sigs.k8s.io/gateway-api/conformance/utils/tlog"
)

func init() {
Expand All @@ -30,38 +26,11 @@ var ClientTimeoutTest = suite.ConformanceTest{
Manifests: []string{"testdata/client-timeout.yaml"},
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
t.Run("http client timeout", func(t *testing.T) {
ns := "gateway-conformance-infra"
routeNN := types.NamespacedName{Name: "http-client-timeout", Namespace: ns}
gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
routeNN := types.NamespacedName{Name: "http-client-timeout", Namespace: ConformanceInfraNamespace}
gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName,
SameNamespaceGatewayRef, routeNN)

// Use raw http request to avoid chunked
req := &http.Request{
Method: "GET",
URL: &url.URL{Scheme: "http", Host: gwAddr, Path: "/request-timeout"},
}

client := &http.Client{}

httputils.AwaitConvergence(t,
suite.TimeoutConfig.RequiredConsecutiveSuccesses,
suite.TimeoutConfig.MaxTimeToConsistency,
func(elapsed time.Duration) bool {
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()

// return 504 instead of 400 when request timeout.
// https://github.com/envoyproxy/envoy/blob/56021dbfb10b53c6d08ed6fc811e1ff4c9ac41fd/source/common/http/utility.cc#L1409
if http.StatusGatewayTimeout == resp.StatusCode {
return true
} else {
tlog.Logf(t, "response status code: %d, (after %v) ", resp.StatusCode, elapsed)
return false
}
})
ExpectRequestTimeout(t, suite, gwAddr, "/client-timeout", "", http.StatusGatewayTimeout)
})
},
}
44 changes: 42 additions & 2 deletions test/e2e/tests/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/conformance/utils/config"
httputils "sigs.k8s.io/gateway-api/conformance/utils/http"
k8sutils "sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
"sigs.k8s.io/gateway-api/conformance/utils/suite"
"sigs.k8s.io/gateway-api/conformance/utils/tlog"

Expand All @@ -49,11 +51,18 @@ import (
var (
IPFamily = os.Getenv("IP_FAMILY")
DeployProfile = os.Getenv("KUBE_DEPLOY_PROFILE")

SameNamespaceGateway = types.NamespacedName{Name: "same-namespace", Namespace: ConformanceInfraNamespace}
SameNamespaceGatewayRef = k8sutils.NewGatewayRef(SameNamespaceGateway)

PodReady = corev1.PodCondition{Type: corev1.PodReady, Status: corev1.ConditionTrue}
)

const defaultServiceStartupTimeout = 5 * time.Minute
const (
ConformanceInfraNamespace = "gateway-conformance-infra"

var PodReady = corev1.PodCondition{Type: corev1.PodReady, Status: corev1.ConditionTrue}
defaultServiceStartupTimeout = 5 * time.Minute
)

// WaitForPods waits for the pods in the given namespace and with the given selector
// to be in the given phase and condition.
Expand Down Expand Up @@ -702,3 +711,34 @@ func GetGatewayResourceNamespace() string {
}
return "envoy-gateway-system"
}

func ExpectRequestTimeout(t *testing.T, suite *suite.ConformanceTestSuite, gwAddr, path, query string, exceptedStatusCode int) {
// Use raw http request to avoid chunked
req := &http.Request{
Method: "GET",
URL: &url.URL{Scheme: "http", Host: gwAddr, Path: path, RawQuery: query},
}

client := &http.Client{
Timeout: 10 * time.Second,
}
httputils.AwaitConvergence(t, suite.TimeoutConfig.RequiredConsecutiveSuccesses, suite.TimeoutConfig.MaxTimeToConsistency,
func(elapsed time.Duration) bool {
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer func() {
_ = resp.Body.Close()
}()

// return 504 instead of 400 when request timeout.
// https://github.com/envoyproxy/envoy/blob/56021dbfb10b53c6d08ed6fc811e1ff4c9ac41fd/source/common/http/utility.cc#L1409
if exceptedStatusCode == resp.StatusCode {
return true
} else {
tlog.Logf(t, "%s%s response status code: %d after %v", gwAddr, path, resp.StatusCode, elapsed)
return false
}
})
}