diff --git a/test/e2e/gateway/tcproute_test.go b/test/e2e/gateway/tcproute_test.go index 4e3d4ea05f9..033928d0501 100644 --- a/test/e2e/gateway/tcproute_test.go +++ b/test/e2e/gateway/tcproute_test.go @@ -16,6 +16,8 @@ package gateway import ( + "context" + . "github.com/onsi/ginkgo/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,7 +35,7 @@ func testTCPRoute(namespace string, gateway types.NamespacedName) { Specify("A TCPRoute does L4 TCP proxying of traffic for its Listener port", func() { t := f.T() - f.Fixtures.Echo.Deploy(namespace, "echo") + f.Fixtures.Echo.Deploy(namespace, "echo-tcproute-backend") route := &gatewayapi_v1alpha2.TCPRoute{ ObjectMeta: meta_v1.ObjectMeta{ @@ -51,7 +53,7 @@ func testTCPRoute(namespace string, gateway types.NamespacedName) { }, Rules: []gatewayapi_v1alpha2.TCPRouteRule{ { - BackendRefs: gatewayapi.TLSRouteBackendRef("echo", 80, ptr.To(int32(1))), + BackendRefs: gatewayapi.TLSRouteBackendRef("echo-tcproute-backend", 80, ptr.To(int32(1))), }, }, }, @@ -64,12 +66,25 @@ func testTCPRoute(namespace string, gateway types.NamespacedName) { Condition: e2e.HasStatusCode(200), }) assert.Truef(t, ok, "expected 200 response code, got %d", res.StatusCode) - assert.Equal(t, "echo", f.GetEchoResponseBody(res.Body).Service) + assert.Equal(t, "echo-tcproute-backend", f.GetEchoResponseBody(res.Body).Service) // Envoy is expected to add the "server: envoy" and // "x-envoy-upstream-service-time" HTTP headers when // proxying HTTP; this ensures we are proxying TCP only. assert.Equal(t, "", res.Headers.Get("server")) assert.Equal(t, "", res.Headers.Get("x-envoy-upstream-service-time")) + + // Delete route and wait for config to no longer be present so this + // test doesn't pollute others. This route effectively matches all + // hostnames so it can affect other tests. + require.NoError(t, f.Client.Delete(context.Background(), route)) + require.Eventually(t, func() bool { + _, err := f.HTTP.Request(&e2e.HTTPRequestOpts{}) + return err != nil + }, f.RetryTimeout, f.RetryInterval, "expected request to eventually fail") + require.Never(t, func() bool { + _, err := f.HTTP.Request(&e2e.HTTPRequestOpts{}) + return err == nil + }, f.RetryTimeout, f.RetryInterval, "expected request to never succeed after failing") }) } diff --git a/test/e2e/http.go b/test/e2e/http.go index 520c16cccf9..c5b35d11a0a 100644 --- a/test/e2e/http.go +++ b/test/e2e/http.go @@ -134,6 +134,40 @@ func (h *HTTP) RequestUntil(opts *HTTPRequestOpts) (*HTTPResponse, bool) { return h.requestUntil(makeRequest, opts.Condition) } +// Request makes a single HTTP request with the provided parameters +// and returns the HTTP response or an error. Note that opts.Condition is +// ignored by this method. +// +// In general, E2E's should use RequestUntil instead of this method since +// RequestUntil will retry requests to account for eventual consistency and +// other ephemeral issues. +func (h *HTTP) Request(opts *HTTPRequestOpts) (*HTTPResponse, error) { + req, err := http.NewRequest(http.MethodGet, opts.requestURLBase(h.HTTPURLBase)+opts.Path, nil) + require.NoError(h.t, err, "error creating HTTP request") + + req.Host = opts.Host + for _, opt := range opts.RequestOpts { + opt(req) + } + + client := httpClient(opts.ClientOpts...) + + r, err := client.Do(req) + if err != nil { + return nil, err + } + defer r.Body.Close() + + bodyBytes, err := io.ReadAll(r.Body) + require.NoError(h.t, err) + + return &HTTPResponse{ + StatusCode: r.StatusCode, + Headers: r.Header, + Body: bodyBytes, + }, nil +} + func OptDontFollowRedirects(c *http.Client) { // Per CheckRedirect godoc: "As a special case, if // CheckRedirect returns ErrUseLastResponse, then