88package tests
99
1010import (
11+ "context"
1112 "testing"
13+ "time"
1214
15+ "github.com/stretchr/testify/require"
1316 "k8s.io/apimachinery/pkg/types"
17+ "k8s.io/apimachinery/pkg/util/wait"
1418 gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
1519 "sigs.k8s.io/gateway-api/conformance/utils/http"
1620 "sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
1721 "sigs.k8s.io/gateway-api/conformance/utils/suite"
22+ "sigs.k8s.io/gateway-api/conformance/utils/tlog"
23+
24+ "github.com/envoyproxy/gateway/test/utils/prometheus"
1825)
1926
2027func init () {
@@ -23,7 +30,7 @@ func init() {
2330
2431var CircuitBreakerTest = suite.ConformanceTest {
2532 ShortName : "CircuitBreaker" ,
26- Description : "Deny All Requests " ,
33+ Description : "Test circuit breaker functionality " ,
2734 Manifests : []string {"testdata/circuitbreaker.yaml" },
2835 Test : func (t * testing.T , suite * suite.ConformanceTestSuite ) {
2936 t .Run ("Deny All Requests" , func (t * testing.T ) {
@@ -47,5 +54,58 @@ var CircuitBreakerTest = suite.ConformanceTest{
4754
4855 http .MakeRequestAndExpectEventuallyConsistentResponse (t , suite .RoundTripper , suite .TimeoutConfig , gwAddr , expectedResponse )
4956 })
57+
58+ t .Run ("Retry budget worked" , func (t * testing.T ) {
59+ ns := "gateway-conformance-infra"
60+ routeNN := types.NamespacedName {Name : "http-with-retry-budget" , Namespace : ns }
61+ gwNN := types.NamespacedName {Name : "same-namespace" , Namespace : ns }
62+ gwAddr := kubernetes .GatewayAndRoutesMustBeAccepted (t , suite .Client , suite .TimeoutConfig , suite .ControllerName , kubernetes .NewGatewayRef (gwNN ), & gwapiv1.HTTPRoute {}, false , routeNN )
63+
64+ // make sure that the backend is healthy.
65+ http .MakeRequestAndExpectEventuallyConsistentResponse (t , suite .RoundTripper , suite .TimeoutConfig , gwAddr , http.ExpectedResponse {
66+ Request : http.Request {
67+ Path : "/retry-budget" ,
68+ },
69+ Response : http.Response {
70+ StatusCodes : []int {200 },
71+ },
72+ Namespace : ns ,
73+ })
74+
75+ promClient , err := prometheus .NewClient (suite .Client ,
76+ types.NamespacedName {Name : "prometheus" , Namespace : "monitoring" },
77+ )
78+ require .NoError (t , err )
79+
80+ promQL := `envoy_cluster_upstream_rq_retry_overflow{app_kubernetes_io_name="envoy",app_kubernetes_io_managed_by="envoy-gateway"}`
81+
82+ // expect 503 since the policy applies a retry budget with 0% success rate
83+ http .MakeRequestAndExpectEventuallyConsistentResponse (t , suite .RoundTripper , suite .TimeoutConfig , gwAddr , http.ExpectedResponse {
84+ Request : http.Request {
85+ Path : "/status/503" ,
86+ },
87+ Response : http.Response {
88+ StatusCodes : []int {503 },
89+ },
90+ Namespace : ns ,
91+ })
92+
93+ err = wait .PollUntilContextTimeout (t .Context (), time .Second , time .Minute , true , func (ctx context.Context ) (bool , error ) {
94+ v , err := promClient .QuerySum (ctx , promQL )
95+ if err != nil {
96+ tlog .Logf (t , "failed to query prometheus: %v" , err )
97+ return false , nil
98+ }
99+
100+ if v > 0 {
101+ tlog .Logf (t , "got expected retry overflow metric: %v" , v )
102+ return true , nil
103+ }
104+
105+ tlog .Logf (t , "retry overflow metric not updated yet: %v" , v )
106+ return false , nil
107+ })
108+ require .NoError (t , err )
109+ })
50110 },
51111}
0 commit comments