diff --git a/conformance/tests/httproute-request-mirror-backend.yaml b/conformance/tests/httproute-request-mirror-backend.yaml new file mode 100644 index 0000000000..5ab311a640 --- /dev/null +++ b/conformance/tests/httproute-request-mirror-backend.yaml @@ -0,0 +1,20 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: request-mirror + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - backendRefs: + - name: infra-backend-v1 + namespace: gateway-conformance-infra + port: 8080 + filters: + - type: RequestMirror + requestMirror: + backendRef: + name: infra-backend-v2 + namespace: gateway-conformance-infra + port: 8080 diff --git a/conformance/tests/httproute-request-mirror.go b/conformance/tests/httproute-request-mirror.go index fa4c36b44b..bdd6eaad93 100644 --- a/conformance/tests/httproute-request-mirror.go +++ b/conformance/tests/httproute-request-mirror.go @@ -28,7 +28,24 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, HTTPRouteRequestMirror) + ConformanceTests = append(ConformanceTests, + HTTPRouteRequestMirror, + HTTPRouteBackendRequestMirror, + ) +} + +var HTTPRouteBackendRequestMirror = suite.ConformanceTest{ + ShortName: "HTTPRouteBackendRequestMirror", + Description: "An HTTPRoute backendRef with request mirror filter", + Manifests: []string{"tests/httproute-request-mirror-backend.yaml"}, + Features: []features.SupportedFeature{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportHTTPRouteBackendRequestMirror, + }, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + RunHTTPRouteRequestMirrorTest(t, suite, HTTPRouteRequestMirrorTestCases) + }, } var HTTPRouteRequestMirror = suite.ConformanceTest{ @@ -41,64 +58,69 @@ var HTTPRouteRequestMirror = suite.ConformanceTest{ features.SupportHTTPRouteRequestMirror, }, Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { - ns := "gateway-conformance-infra" - routeNN := types.NamespacedName{Name: "request-mirror", Namespace: ns} - gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} - gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + RunHTTPRouteRequestMirrorTest(t, suite, HTTPRouteRequestMirrorTestCases) + RunHTTPRouteRequestMirrorTest(t, suite, HTTPRouteRequestMirrorAndModifyRequestHeaderTestCases) + }, +} - testCases := []http.ExpectedResponse{ - { - Request: http.Request{ - Path: "/mirror", - }, - ExpectedRequest: &http.ExpectedRequest{ - Request: http.Request{ - Path: "/mirror", - }, - }, - Backend: "infra-backend-v1", - MirroredTo: []http.BackendRef{{ - Name: "infra-backend-v2", - Namespace: ns, - }}, - Namespace: ns, - }, - { - Request: http.Request{ - Path: "/mirror-and-modify-headers", - Headers: map[string]string{ - "X-Header-Remove": "remove-val", - "X-Header-Add-Append": "append-val-1", - }, - }, - ExpectedRequest: &http.ExpectedRequest{ - Request: http.Request{ - Path: "/mirror-and-modify-headers", - Headers: map[string]string{ - "X-Header-Add": "header-val-1", - "X-Header-Add-Append": "append-val-1,header-val-2", - "X-Header-Set": "set-overwrites-values", - }, - }, - AbsentHeaders: []string{"X-Header-Remove"}, - }, - Namespace: ns, - Backend: "infra-backend-v1", - MirroredTo: []http.BackendRef{{ - Name: "infra-backend-v2", - Namespace: ns, - }}, +func RunHTTPRouteRequestMirrorTest(t *testing.T, suite *suite.ConformanceTestSuite, testCases []http.ExpectedResponse) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "request-mirror", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) + http.ExpectMirroredRequest(t, suite.Client, suite.Clientset, tc.MirroredTo, tc.Request.Path) + }) + } +} + +var HTTPRouteRequestMirrorTestCases = []http.ExpectedResponse{{ + Request: http.Request{ + Path: "/mirror", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/mirror", + }, + }, + Backend: "infra-backend-v1", + MirroredTo: []http.BackendRef{{ + Name: "infra-backend-v2", + Namespace: "gateway-conformance-infra", + }}, + Namespace: "gateway-conformance-infra", +}} + +var HTTPRouteRequestMirrorAndModifyRequestHeaderTestCases = []http.ExpectedResponse{{ + Request: http.Request{ + Path: "/mirror-and-modify-headers", + Headers: map[string]string{ + "X-Header-Remove": "remove-val", + "X-Header-Add-Append": "append-val-1", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/mirror-and-modify-headers", + Headers: map[string]string{ + "X-Header-Add": "header-val-1", + "X-Header-Add-Append": "append-val-1,header-val-2", + "X-Header-Set": "set-overwrites-values", }, - } - for i := range testCases { - // Declare tc here to avoid loop variable - // reuse issues across parallel tests. - tc := testCases[i] - t.Run(tc.GetTestCaseName(i), func(t *testing.T) { - t.Parallel() - http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) - http.ExpectMirroredRequest(t, suite.Client, suite.Clientset, tc.MirroredTo, tc.Request.Path) - }) - } + }, + AbsentHeaders: []string{"X-Header-Remove"}, }, -} + Namespace: "gateway-conformance-infra", + Backend: "infra-backend-v1", + MirroredTo: []http.BackendRef{{ + Name: "infra-backend-v2", + Namespace: "gateway-conformance-infra", + }}, +}} diff --git a/pkg/features/features.go b/pkg/features/features.go index fcb6d28019..aa26fae374 100644 --- a/pkg/features/features.go +++ b/pkg/features/features.go @@ -128,6 +128,9 @@ const ( // This option indicates support for HTTPRoute request mirror (extended conformance). SupportHTTPRouteRequestMirror SupportedFeature = "HTTPRouteRequestMirror" + // This option indicates support for HTTPRoute backend request mirror (extended conformance). + SupportHTTPRouteBackendRequestMirror SupportedFeature = "HTTPRouteBackendRequestMirror" + // This option indicates support for multiple RequestMirror filters within the same HTTPRoute rule (extended conformance). SupportHTTPRouteRequestMultipleMirrors SupportedFeature = "HTTPRouteRequestMultipleMirrors" @@ -154,6 +157,7 @@ var HTTPRouteExtendedFeatures = sets.New( SupportHTTPRouteHostRewrite, SupportHTTPRoutePathRewrite, SupportHTTPRouteRequestMirror, + SupportHTTPRouteBackendRequestMirror, SupportHTTPRouteRequestMultipleMirrors, SupportHTTPRouteRequestTimeout, SupportHTTPRouteBackendTimeout,