...

Package tests

import "sigs.k8s.io/gateway-api/conformance/tests"
Overview
Index

Overview ▾

Index ▾

Package files

gateway-invalid-route-kind.go gateway-invalid-tls-certificateref.go gateway-modify-listeners.go gateway-observed-generation-bump.go gateway-secret-invalid-reference-grant.go gateway-secret-missing-reference-grant.go gateway-secret-reference-grant-all-in-namespace.go gateway-secret-reference-grant-specific.go gateway-static-addresses.go gateway-with-attached-routes.go gatewayclass-observed-generation-bump.go httproute-backend-protocol-h2c.go httproute-backend-protocol-ws.go httproute-cross-namespace.go httproute-disallowed-kind.go httproute-exact-path-matching.go httproute-header-matching.go httproute-hostname-intersection.go httproute-invalid-backendref-nonexistent.go httproute-invalid-backendref-unknown-kind.go httproute-invalid-cross-namespace-backend-ref.go httproute-invalid-cross-namespace-parent-ref.go httproute-invalid-parentref-not-matching-listener-port.go httproute-invalid-parentref-not-matching-section-name.go httproute-invalid-reference-grant.go httproute-listener-hostname-matching.go httproute-matching-across-routes.go httproute-matching.go httproute-method-matching.go httproute-observed-generation-bump.go httproute-partially-invalid-via-reference-grant.go httproute-path-match-order.go httproute-query-param-matching.go httproute-redirect-host-and-status.go httproute-redirect-path.go httproute-redirect-port-and-scheme.go httproute-redirect-port.go httproute-redirect-scheme.go httproute-reference-grant.go httproute-request-header-modifier.go httproute-request-mirror.go httproute-request-multiple-mirrors.go httproute-response-header-modifier.go httproute-rewrite-host.go httproute-rewrite-path.go httproute-simple-same-namespace.go httproute-timeout-backend-request.go httproute-timeout-request.go main.go mesh-basic.go mesh-consumer-route.go mesh-frontend-hostname.go mesh-frontend.go mesh-ports.go mesh-split.go tlsroute-invalid-reference-grant.go tlsroute-simple-same-namespace.go

Variables

var ConformanceTests []suite.ConformanceTest
var GatewayClassObservedGenerationBump = suite.ConformanceTest{
    ShortName: "GatewayClassObservedGenerationBump",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
    },
    Description: "A GatewayClass should update the observedGeneration in all of it's Status.Conditions after an update to the spec",
    Manifests:   []string{"tests/gatewayclass-observed-generation-bump.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwc := types.NamespacedName{Name: "gatewayclass-observed-generation-bump"}

        t.Run("observedGeneration should increment", func(t *testing.T) {
            ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
            defer cancel()

            kubernetes.GWCMustHaveAcceptedConditionAny(t, s.Client, s.TimeoutConfig, gwc.Name)

            original := &v1.GatewayClass{}
            err := s.Client.Get(ctx, gwc, original)
            require.NoErrorf(t, err, "error getting GatewayClass: %v", err)

            kubernetes.GatewayClassMustHaveLatestConditions(t, original)

            mutate := original.DeepCopy()
            desc := "new"
            mutate.Spec.Description = &desc

            err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
            require.NoErrorf(t, err, "error patching the GatewayClass: %v", err)

            kubernetes.GWCMustHaveAcceptedConditionAny(t, s.Client, s.TimeoutConfig, gwc.Name)

            updated := &v1.GatewayClass{}
            err = s.Client.Get(ctx, gwc, updated)
            require.NoErrorf(t, err, "error getting GatewayClass: %v", err)

            kubernetes.GatewayClassMustHaveLatestConditions(t, updated)

            require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
        })
    },
}
var GatewayInvalidRouteKind = suite.ConformanceTest{
    ShortName:   "GatewayInvalidRouteKind",
    Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready an invalid Route kind is specified.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
    },
    Manifests: []string{"tests/gateway-invalid-route-kind.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        t.Run("Gateway listener should have a false ResolvedRefs condition with reason InvalidRouteKinds and no supportedKinds", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-only-invalid-route-kind", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{{
                Name:           v1.SectionName("http"),
                SupportedKinds: []v1.RouteGroupKind{},
                Conditions: []metav1.Condition{{
                    Type:   string(v1.ListenerConditionResolvedRefs),
                    Status: metav1.ConditionFalse,
                    Reason: string(v1.ListenerReasonInvalidRouteKinds),
                }},
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })

        t.Run("Gateway listener should have a false ResolvedRefs condition with reason InvalidRouteKinds and HTTPRoute must be put in the supportedKinds", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-supported-and-invalid-route-kind", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("http"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{{
                    Type:   string(v1.ListenerConditionResolvedRefs),
                    Status: metav1.ConditionFalse,
                    Reason: string(v1.ListenerReasonInvalidRouteKinds),
                }},
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}
var GatewayInvalidTLSConfiguration = suite.ConformanceTest{
    ShortName:   "GatewayInvalidTLSConfiguration",
    Description: "A Gateway should fail to become ready if the Gateway has an invalid TLS configuration",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
    },
    Manifests: []string{"tests/gateway-invalid-tls-certificateref.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        listeners := []v1.ListenerStatus{{
            Name: v1.SectionName("https"),
            SupportedKinds: []v1.RouteGroupKind{{
                Group: (*v1.Group)(&v1.GroupVersion.Group),
                Kind:  v1.Kind("HTTPRoute"),
            }},
            Conditions: []metav1.Condition{{
                Type:   string(v1.ListenerConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.ListenerReasonInvalidCertificateRef),
            }},
            AttachedRoutes: 0,
        }}

        testCases := []struct {
            name                  string
            gatewayNamespacedName types.NamespacedName
        }{
            {
                name:                  "Nonexistent secret referenced as CertificateRef in a Gateway listener",
                gatewayNamespacedName: types.NamespacedName{Name: "gateway-certificate-nonexistent-secret", Namespace: "gateway-conformance-infra"},
            },
            {
                name:                  "Unsupported group resource referenced as CertificateRef in a Gateway listener",
                gatewayNamespacedName: types.NamespacedName{Name: "gateway-certificate-unsupported-group", Namespace: "gateway-conformance-infra"},
            },
            {
                name:                  "Unsupported kind resource referenced as CertificateRef in a Gateway listener",
                gatewayNamespacedName: types.NamespacedName{Name: "gateway-certificate-unsupported-kind", Namespace: "gateway-conformance-infra"},
            },
            {
                name:                  "Malformed secret referenced as CertificateRef in a Gateway listener",
                gatewayNamespacedName: types.NamespacedName{Name: "gateway-certificate-malformed-secret", Namespace: "gateway-conformance-infra"},
            },
        }

        for _, tc := range testCases {
            tc := tc
            t.Run(tc.name, func(t *testing.T) {
                t.Parallel()
                kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, tc.gatewayNamespacedName, listeners)
            })
        }
    },
}
var GatewayModifyListeners = suite.ConformanceTest{
    ShortName:   "GatewayModifyListeners",
    Description: "A Gateway in the gateway-conformance-infra namespace should handle adding and removing listeners.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
    },
    Manifests: []string{"tests/gateway-modify-listeners.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        t.Run("should be able to add a listener that then becomes available for routing traffic", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-add-listener", Namespace: "gateway-conformance-infra"}
            ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
            defer cancel()

            namespaces := []string{"gateway-conformance-infra"}
            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            original := &v1.Gateway{}
            err := s.Client.Get(ctx, gwNN, original)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            all := v1.NamespacesFromAll

            mutate := original.DeepCopy()

            hostname := v1.Hostname("data.test.com")
            mutate.Spec.Listeners = append(mutate.Spec.Listeners, v1.Listener{
                Name:     "http",
                Port:     80,
                Protocol: v1.HTTPProtocolType,
                Hostname: &hostname,
                AllowedRoutes: &v1.AllowedRoutes{
                    Namespaces: &v1.RouteNamespaces{From: &all},
                },
            })

            err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
            require.NoErrorf(t, err, "error patching the Gateway: %v", err)

            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            listeners := []v1.ListenerStatus{
                {
                    Name: v1.SectionName("https"),
                    SupportedKinds: []v1.RouteGroupKind{{
                        Group: (*v1.Group)(&v1.GroupVersion.Group),
                        Kind:  v1.Kind("HTTPRoute"),
                    }},
                    Conditions: []metav1.Condition{
                        {
                            Type:   string(v1.ListenerConditionAccepted),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                        {
                            Type:   string(v1.ListenerConditionResolvedRefs),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                    },
                    AttachedRoutes: 1,
                },
                {
                    Name: v1.SectionName("http"),
                    SupportedKinds: []v1.RouteGroupKind{{
                        Group: (*v1.Group)(&v1.GroupVersion.Group),
                        Kind:  v1.Kind("HTTPRoute"),
                    }},
                    Conditions: []metav1.Condition{
                        {
                            Type:   string(v1.ListenerConditionAccepted),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                        {
                            Type:   string(v1.ListenerConditionResolvedRefs),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                    },
                    AttachedRoutes: 1,
                },
            }

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            updated := &v1.Gateway{}
            err = s.Client.Get(ctx, gwNN, updated)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
        })

        t.Run("should be able to remove listeners, which would then stop routing the relevant traffic", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-remove-listener", Namespace: "gateway-conformance-infra"}
            ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
            defer cancel()

            namespaces := []string{"gateway-conformance-infra"}
            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            original := &v1.Gateway{}
            err := s.Client.Get(ctx, gwNN, original)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            mutate := original.DeepCopy()
            require.Equalf(t, 2, len(mutate.Spec.Listeners), "the gateway must have 2 listeners")

            // remove the "https" Gateway listener, leaving only the "http" listener
            var newListeners []v1.Listener
            for _, listener := range mutate.Spec.Listeners {
                if listener.Name == "http" {
                    newListeners = append(newListeners, listener)
                }
            }
            mutate.Spec.Listeners = newListeners

            err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
            require.NoErrorf(t, err, "error patching the Gateway: %v", err)

            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            listeners := []v1.ListenerStatus{
                {
                    Name: v1.SectionName("http"),
                    SupportedKinds: []v1.RouteGroupKind{{
                        Group: (*v1.Group)(&v1.GroupVersion.Group),
                        Kind:  v1.Kind("HTTPRoute"),
                    }},
                    Conditions: []metav1.Condition{
                        {
                            Type:   string(v1.ListenerConditionAccepted),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                        {
                            Type:   string(v1.ListenerConditionResolvedRefs),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                    },
                    AttachedRoutes: 1,
                },
            }

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            updated := &v1.Gateway{}
            err = s.Client.Get(ctx, gwNN, updated)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
        })
    },
}
var GatewayObservedGenerationBump = suite.ConformanceTest{
    ShortName:   "GatewayObservedGenerationBump",
    Description: "A Gateway in the gateway-conformance-infra namespace should update the observedGeneration in all of its Status.Conditions after an update to the spec",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportGatewayPort8080,
    },
    Manifests: []string{"tests/gateway-observed-generation-bump.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "gateway-observed-generation-bump", Namespace: "gateway-conformance-infra"}

        t.Run("observedGeneration should increment", func(t *testing.T) {
            ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
            defer cancel()

            namespaces := []string{"gateway-conformance-infra"}
            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            original := &v1.Gateway{}
            err := s.Client.Get(ctx, gwNN, original)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            all := v1.NamespacesFromAll

            mutate := original.DeepCopy()

            mutate.Spec.Listeners = append(mutate.Spec.Listeners, v1.Listener{
                Name:     "alternate",
                Port:     8080,
                Protocol: v1.HTTPProtocolType,
                AllowedRoutes: &v1.AllowedRoutes{
                    Namespaces: &v1.RouteNamespaces{From: &all},
                },
            })

            err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
            require.NoErrorf(t, err, "error patching the Gateway: %v", err)

            kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)

            kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

            updated := &v1.Gateway{}
            err = s.Client.Get(ctx, gwNN, updated)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
        })
    },
}
var GatewaySecretInvalidReferenceGrant = suite.ConformanceTest{
    ShortName:   "GatewaySecretInvalidReferenceGrant",
    Description: "A Gateway in the gateway-conformance-infra namespace should fail to become ready if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant exists but does not grant permission to that specific Secret",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/gateway-secret-invalid-reference-grant.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "gateway-secret-invalid-reference-grant", Namespace: "gateway-conformance-infra"}

        t.Run("Gateway listener should have a false ResolvedRefs condition with reason RefNotPermitted", func(t *testing.T) {
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("https"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{{
                    Type:   string(v1.ListenerConditionResolvedRefs),
                    Status: metav1.ConditionFalse,
                    Reason: string(v1.ListenerReasonRefNotPermitted),
                }},
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}
var GatewaySecretMissingReferenceGrant = suite.ConformanceTest{
    ShortName:   "GatewaySecretMissingReferenceGrant",
    Description: "A Gateway in the gateway-conformance-infra namespace should fail to become programmed if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to the Secret does not exist",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/gateway-secret-missing-reference-grant.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "gateway-secret-missing-reference-grant", Namespace: "gateway-conformance-infra"}

        t.Run("Gateway listener should have a false ResolvedRefs condition with reason RefNotPermitted", func(t *testing.T) {
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("https"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{{
                    Type:   string(v1.ListenerConditionResolvedRefs),
                    Status: metav1.ConditionFalse,
                    Reason: string(v1.ListenerReasonRefNotPermitted),
                }},
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}
var GatewaySecretReferenceGrantAllInNamespace = suite.ConformanceTest{
    ShortName:   "GatewaySecretReferenceGrantAllInNamespace",
    Description: "A Gateway in the gateway-conformance-infra namespace should become programmed if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to all Secrets in the namespace exists",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/gateway-secret-reference-grant-all-in-namespace.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "gateway-secret-reference-grant-all-in-namespace", Namespace: "gateway-conformance-infra"}

        t.Run("Gateway listener should have a true ResolvedRefs condition and a true Programmed condition", func(t *testing.T) {
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("https"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.ListenerConditionProgrammed),
                        Status: metav1.ConditionTrue,
                        Reason: string(v1.ListenerReasonProgrammed),
                    },
                    {
                        Type:   string(v1.ListenerConditionResolvedRefs),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                },
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}
var GatewaySecretReferenceGrantSpecific = suite.ConformanceTest{
    ShortName:   "GatewaySecretReferenceGrantSpecific",
    Description: "A Gateway in the gateway-conformance-infra namespace should become programmed if the Gateway has a certificateRef for a Secret in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to the specific Secret exists",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/gateway-secret-reference-grant-specific.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "gateway-secret-reference-grant-specific", Namespace: "gateway-conformance-infra"}

        t.Run("Gateway listener should have a true ResolvedRefs condition and a true Programmed condition", func(t *testing.T) {
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("https"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.ListenerConditionProgrammed),
                        Status: metav1.ConditionTrue,
                        Reason: string(v1.ListenerReasonProgrammed),
                    },
                    {
                        Type:   string(v1.ListenerConditionResolvedRefs),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                },
                AttachedRoutes: 0,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}

GatewayStaticAddresses tests the implementation's support of deploying Gateway resources with static addresses, or in other words addresses provided via the specification rather than relying on the underlying implementation/network to dynamically assign the Gateway an address.

Running this test against your own implementation is currently a little bit messy, as at the time of writing we didn't have great ways to provide the test suite with things like known good, or known bad addresses to run the test with (as we obviously can't determine that for the implementation).

As such, if you're trying to enable this test for yourself and you're getting confused about how to provide addresses, you'll actually do that in the conformance test suite BEFORE you even set up and run your tests. Make sure you populate the following test suite fields:

With appropriate network addresses for your network environment.

var GatewayStaticAddresses = suite.ConformanceTest{
    ShortName:   "GatewayStaticAddresses",
    Description: "A Gateway in the gateway-conformance-infra namespace should be able to use previously determined addresses.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportGatewayStaticAddresses,
    },
    Manifests: []string{
        "tests/gateway-static-addresses.yaml",
    },
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{
            Name:      "gateway-static-addresses",
            Namespace: "gateway-conformance-infra",
        }
        ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
        defer cancel()

        t.Logf("waiting for namespace %s and Gateway %s to be ready for testing", gwNN.Namespace, gwNN.Name)
        kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

        t.Logf("retrieving Gateway %s/%s and noting the provided addresses", gwNN.Namespace, gwNN.Name)
        currentGW := &v1.Gateway{}
        err := s.Client.Get(ctx, gwNN, currentGW)
        require.NoError(t, err, "error getting Gateway: %v", err)
        require.Len(t, currentGW.Spec.Addresses, 3, "expected 3 addresses on the Gateway, one invalid, one usable and one unusable. somehow got %d", len(currentGW.Spec.Addresses))
        invalidAddress := currentGW.Spec.Addresses[0]
        unusableAddress := currentGW.Spec.Addresses[1]
        usableAddress := currentGW.Spec.Addresses[2]

        t.Logf("verifying that the Gateway %s/%s is NOT accepted due to an address type that the implementation doesn't support", gwNN.Namespace, gwNN.Name)
        kubernetes.GatewayMustHaveCondition(t, s.Client, s.TimeoutConfig, gwNN, metav1.Condition{
            Type:   string(v1.GatewayConditionAccepted),
            Status: metav1.ConditionFalse,
            Reason: string(v1.GatewayReasonUnsupportedAddress),
        })

        t.Logf("patching Gateway %s/%s to remove the invalid address %s", gwNN.Namespace, gwNN.Name, invalidAddress.Value)
        updatedGW := currentGW.DeepCopy()
        updatedGW.Spec.Addresses = filterAddr(currentGW.Spec.Addresses, invalidAddress)
        err = s.Client.Patch(ctx, updatedGW, client.MergeFrom(currentGW))
        require.NoError(t, err, "failed to patch Gateway: %v", err)
        kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

        t.Logf("verifying that the Gateway %s/%s is now accepted, but is not programmed due to an address that can't be used", gwNN.Namespace, gwNN.Name)
        err = s.Client.Get(ctx, gwNN, currentGW)
        require.NoError(t, err, "error getting Gateway: %v", err)
        kubernetes.GatewayMustHaveCondition(t, s.Client, s.TimeoutConfig, gwNN, metav1.Condition{
            Type:   string(v1.GatewayConditionAccepted),
            Status: metav1.ConditionTrue,
            Reason: string(v1.GatewayReasonAccepted),
        })
        kubernetes.GatewayMustHaveCondition(t, s.Client, s.TimeoutConfig, gwNN, metav1.Condition{
            Type:   string(v1.GatewayConditionProgrammed),
            Status: metav1.ConditionFalse,
            Reason: string(v1.GatewayReasonAddressNotUsable),
        })

        t.Logf("patching Gateway %s/%s to remove the unusable address %s", gwNN.Namespace, gwNN.Name, unusableAddress.Value)
        updatedGW = currentGW.DeepCopy()
        updatedGW.Spec.Addresses = filterAddr(currentGW.Spec.Addresses, unusableAddress)
        err = s.Client.Patch(ctx, updatedGW, client.MergeFrom(currentGW))
        require.NoError(t, err, "failed to patch Gateway: %v", err)
        kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)

        t.Logf("verifying that the Gateway %s/%s is accepted and programmed with the usable static address %s assigned", gwNN.Namespace, gwNN.Name, usableAddress.Value)
        err = s.Client.Get(ctx, gwNN, currentGW)
        require.NoError(t, err, "error getting Gateway: %v", err)
        kubernetes.GatewayMustHaveCondition(t, s.Client, s.TimeoutConfig, gwNN, metav1.Condition{
            Type:   string(v1.GatewayConditionAccepted),
            Status: metav1.ConditionTrue,
            Reason: string(v1.GatewayReasonAccepted),
        })
        kubernetes.GatewayMustHaveCondition(t, s.Client, s.TimeoutConfig, gwNN, metav1.Condition{
            Type:   string(v1.GatewayConditionProgrammed),
            Status: metav1.ConditionTrue,
            Reason: string(v1.GatewayReasonProgrammed),
        })
        kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, finalExpectedListenerState)
        require.Len(t, currentGW.Spec.Addresses, 1, "expected only 1 address left specified on Gateway")
        require.Len(t, currentGW.Status.Addresses, 1, "one usable address was provided, so it should be the one reflected in status")
        require.Equal(t, usableAddress.Type, currentGW.Status.Addresses[0].Type, "expected address type to match the usable address")
        require.Equal(t, usableAddress.Value, currentGW.Status.Addresses[0].Value, "expected usable address to be assigned")
    },
}
var GatewayWithAttachedRoutes = suite.ConformanceTest{
    ShortName:   "GatewayWithAttachedRoutes",
    Description: "A Gateway in the gateway-conformance-infra namespace should be attached to routes.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/gateway-with-attached-routes.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        t.Run("Gateway listener should have one valid http routes attached", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-with-one-attached-route", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("http"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.ListenerConditionAccepted),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                    {
                        Type:   string(v1.ListenerConditionResolvedRefs),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                },
                AttachedRoutes: 1,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })

        t.Run("Gateway listener should have two valid http routes attached", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-with-two-attached-routes", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("http"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.ListenerConditionAccepted),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                    {
                        Type:   string(v1.ListenerConditionResolvedRefs),
                        Status: metav1.ConditionTrue,
                        Reason: "",
                    },
                },
                AttachedRoutes: 2,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })

        t.Run("Gateway listener should have AttachedRoutes set even when Gateway has unresolved refs", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "unresolved-gateway-with-one-attached-unresolved-route", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{{
                Name: v1.SectionName("tls"),
                SupportedKinds: []v1.RouteGroupKind{{
                    Group: (*v1.Group)(&v1.GroupVersion.Group),
                    Kind:  v1.Kind("HTTPRoute"),
                }},
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.ListenerConditionProgrammed),
                        Status: metav1.ConditionFalse,
                        Reason: "",
                    },
                    {
                        Type:   string(v1.ListenerConditionResolvedRefs),
                        Status: metav1.ConditionFalse,
                        Reason: "",
                    },
                },
                AttachedRoutes: 1,
            }}

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)

            hrouteNN := types.NamespacedName{Name: "http-route-4", Namespace: "gateway-conformance-infra"}
            notAccepted := metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionFalse,
                Reason: "",
            }
            unresolved := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: "",
            }

            kubernetes.HTTPRouteMustHaveCondition(t, s.Client, s.TimeoutConfig, hrouteNN, gwNN, notAccepted)
            kubernetes.HTTPRouteMustHaveCondition(t, s.Client, s.TimeoutConfig, hrouteNN, gwNN, unresolved)
        })
    },
}
var GatewayWithAttachedRoutesWithPort8080 = suite.ConformanceTest{
    ShortName:   "GatewayWithAttachedRoutesWithPort8080",
    Description: "A Gateway in the gateway-conformance-infra namespace should be attached to routes.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportGatewayPort8080,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/gateway-with-attached-routes-with-port-8080.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        t.Run("Gateway listener should have attached route by specifying the sectionName", func(t *testing.T) {
            gwNN := types.NamespacedName{Name: "gateway-with-two-listeners-and-one-attached-route", Namespace: "gateway-conformance-infra"}
            listeners := []v1.ListenerStatus{
                {
                    Name: v1.SectionName("http-unattached"),
                    SupportedKinds: []v1.RouteGroupKind{{
                        Group: (*v1.Group)(&v1.GroupVersion.Group),
                        Kind:  v1.Kind("HTTPRoute"),
                    }},
                    Conditions: []metav1.Condition{
                        {
                            Type:   string(v1.ListenerConditionAccepted),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                        {
                            Type:   string(v1.ListenerConditionResolvedRefs),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                    },
                    AttachedRoutes: 0,
                },
                {
                    Name: v1.SectionName("http"),
                    SupportedKinds: []v1.RouteGroupKind{{
                        Group: (*v1.Group)(&v1.GroupVersion.Group),
                        Kind:  v1.Kind("HTTPRoute"),
                    }},
                    Conditions: []metav1.Condition{
                        {
                            Type:   string(v1.ListenerConditionAccepted),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                        {
                            Type:   string(v1.ListenerConditionResolvedRefs),
                            Status: metav1.ConditionTrue,
                            Reason: "",
                        },
                    },
                    AttachedRoutes: 1,
                },
            }

            kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
        })
    },
}
var HTTPExactPathMatching = suite.ConformanceTest{
    ShortName:   "HTTPExactPathMatching",
    Description: "A single HTTPRoute with exact path matching for different backends",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-exact-path-matching.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "exact-matching", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/one"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/two"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            }, {
                Request:  http.Request{Path: "/"},
                Response: http.Response{StatusCode: 404},
            }, {
                Request:  http.Request{Path: "/one/example"},
                Response: http.Response{StatusCode: 404},
            }, {
                Request:  http.Request{Path: "/two/"},
                Response: http.Response{StatusCode: 404},
            }, {
                Request:  http.Request{Path: "/Two"},
                Response: http.Response{StatusCode: 404},
            },
        }

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteBackendProtocolH2C = suite.ConformanceTest{
    ShortName:   "HTTPRouteBackendProtocolH2C",
    Description: "A HTTPRoute with a BackendRef that has an appProtocol kubernetes.io/h2c should be functional",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteBackendProtocolH2C,
    },
    Manifests: []string{
        "tests/httproute-backend-protocol-h2c.yaml",
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "backend-protocol-h2c", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("http2 prior knowledge request should reach backend", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Path:     "/",
                    Protocol: roundtripper.H2CPriorKnowledgeProtocol,
                },
                Response:  http.Response{StatusCode: 200},
                Backend:   "infra-backend-v1",
                Namespace: "gateway-conformance-infra",
            })
        })
    },
}
var HTTPRouteBackendProtocolWebSocket = suite.ConformanceTest{
    ShortName:   "HTTPRouteBackendProtocolWebSocket",
    Description: "A HTTPRoute with a BackendRef that has an appProtocol kubernetes.io/ws should be functional",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteBackendProtocolWebSocket,
    },
    Manifests: []string{
        "tests/httproute-backend-protocol-ws.yaml",
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "backend-protocol-ws", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        threshold := suite.TimeoutConfig.RequiredConsecutiveSuccesses
        maxTimeToConsistency := suite.TimeoutConfig.MaxTimeToConsistency

        t.Run("websocket connection should reach backend", func(t *testing.T) {
            http.AwaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool {
                origin := fmt.Sprintf("ws://gateway/%s", t.Name())
                remote := fmt.Sprintf("ws://%s/ws", gwAddr)

                ws, err := websocket.Dial(remote, "", origin)
                if err != nil {
                    t.Log("failed to dial", err)
                    return false
                }
                defer ws.Close()

                // Send text frame
                var (
                    textMessage = "Websocket Support!"
                    textReply   string
                )
                if err := websocket.Message.Send(ws, textMessage); err != nil {
                    t.Log("failed to send text frame", err)
                    return false
                }
                if err := websocket.Message.Receive(ws, &textReply); err != nil {
                    t.Log("failed to receive text frame", err)
                    return false
                }
                if textMessage != textReply {
                    t.Logf("unexpected reply - want: %s got: %s", textMessage, textReply)
                    return false
                }

                // Send byte frame
                var (
                    binaryMessage = []byte{1, 2, 3, 4, 5, 6, 7}
                    binaryReply   []byte
                )
                if err := websocket.Message.Send(ws, binaryMessage); err != nil {
                    t.Log("failed to send binary frame", err)
                    return false
                }
                if err := websocket.Message.Receive(ws, &binaryReply); err != nil {
                    t.Log("failed to receive binary frame", err)
                }
                if !bytes.Equal(binaryMessage, binaryReply) {
                    t.Logf("unexpected reply - want: %#v got: %#v", binaryMessage, binaryReply)
                    return false
                }
                return true
            })
        })
    },
}
var HTTPRouteCrossNamespace = suite.ConformanceTest{
    ShortName:   "HTTPRouteCrossNamespace",
    Description: "A single HTTPRoute in the gateway-conformance-web-backend namespace should attach to Gateway in another namespace",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-cross-namespace.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "cross-namespace", Namespace: "gateway-conformance-web-backend"}
        gwNN := types.NamespacedName{Name: "backend-namespaces", Namespace: "gateway-conformance-infra"}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("Simple HTTP request should reach web-backend", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request:   http.Request{Path: "/"},
                Response:  http.Response{StatusCode: 200},
                Backend:   "web-backend",
                Namespace: "gateway-conformance-web-backend",
            })
        })
    },
}
var HTTPRouteDisallowedKind = suite.ConformanceTest{
    ShortName:   "HTTPRouteDisallowedKind",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should fail to attach to a Gateway with no listeners that allow the HTTPRoute kind",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportTLSRoute,
    },
    Manifests: []string{"tests/httproute-disallowed-kind.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {

        kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{"gateway-conformance-infra"})

        routeNN := types.NamespacedName{Name: "disallowed-kind", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "tlsroutes-only", Namespace: "gateway-conformance-infra"}
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("Route should not have been accepted with reason NotAllowedByListeners", func(t *testing.T) {
            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonNotAllowedByListeners),
            })
        })
        t.Run("Route should not have Parents set in status", func(t *testing.T) {
            kubernetes.HTTPRouteMustHaveNoAcceptedParents(t, suite.Client, suite.TimeoutConfig, routeNN)
        })
        t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
            kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwNN)
        })
    },
}
var HTTPRouteHeaderMatching = suite.ConformanceTest{
    ShortName:   "HTTPRouteHeaderMatching",
    Description: "A single HTTPRoute with header matching for different backends",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-header-matching.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "header-matching", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{{
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "one"}},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "two"}},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "two", "Color": "orange"}},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "two", "Color": "blue"}},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:  http.Request{Path: "/", Headers: map[string]string{"Color": "orange"}},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:  http.Request{Path: "/", Headers: map[string]string{"Some-Other-Header": "one"}},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Color": "blue"}},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Color": "green"}},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Color": "red"}},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Color": "yellow"}},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:  http.Request{Path: "/", Headers: map[string]string{"Color": "purple"}},
            Response: http.Response{StatusCode: 404},
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteHostnameIntersection = suite.ConformanceTest{
    ShortName:   "HTTPRouteHostnameIntersection",
    Description: "HTTPRoutes should attach to listeners only if they have intersecting hostnames, and should accept requests only for the intersecting hostnames",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-hostname-intersection.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        gwNN := types.NamespacedName{Name: "httproute-hostname-intersection", Namespace: ns}

        kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})

        t.Run("HTTPRoutes that do intersect with listener hostnames", func(t *testing.T) {
            routes := []types.NamespacedName{
                {Namespace: ns, Name: "specific-host-matches-listener-specific-host"},
                {Namespace: ns, Name: "specific-host-matches-listener-wildcard-host"},
                {Namespace: ns, Name: "wildcard-host-matches-listener-specific-host"},
                {Namespace: ns, Name: "wildcard-host-matches-listener-wildcard-host"},
            }
            gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routes...)
            for _, routeNN := range routes {
                kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)
            }

            var testCases []http.ExpectedResponse

            testCases = append(testCases,
                http.ExpectedResponse{
                    Request:   http.Request{Host: "very.specific.com", Path: "/s1"},
                    Backend:   "infra-backend-v1",
                    Namespace: ns,
                },

                http.ExpectedResponse{
                    Request:   http.Request{Host: "very.specific.com:1234", Path: "/s1"},
                    Backend:   "infra-backend-v1",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "non.matching.com", Path: "/s1"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.nonmatchingwildcard.io", Path: "/s1"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.wildcard.io", Path: "/s1"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "very.specific.com", Path: "/non-matching-prefix"},
                    Response: http.Response{StatusCode: 404},
                },
            )

            testCases = append(testCases,
                http.ExpectedResponse{
                    Request:   http.Request{Host: "foo.wildcard.io", Path: "/s2"},
                    Backend:   "infra-backend-v2",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:   http.Request{Host: "bar.wildcard.io", Path: "/s2"},
                    Backend:   "infra-backend-v2",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:   http.Request{Host: "foo.bar.wildcard.io", Path: "/s2"},
                    Backend:   "infra-backend-v2",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "non.matching.com", Path: "/s2"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "wildcard.io", Path: "/s2"},
                    Response: http.Response{StatusCode: 404},
                },

                http.ExpectedResponse{
                    Request:  http.Request{Host: "very.specific.com", Path: "/s2"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.wildcard.io", Path: "/non-matching-prefix"},
                    Response: http.Response{StatusCode: 404},
                },
            )

            testCases = append(testCases,
                http.ExpectedResponse{
                    Request:   http.Request{Host: "very.specific.com", Path: "/s3"},
                    Backend:   "infra-backend-v3",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "non.matching.com", Path: "/s3"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.specific.com", Path: "/s3"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.wildcard.io", Path: "/s3"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "very.specific.com", Path: "/non-matching-prefix"},
                    Response: http.Response{StatusCode: 404},
                },
            )

            testCases = append(testCases,
                http.ExpectedResponse{
                    Request:   http.Request{Host: "foo.anotherwildcard.io", Path: "/s4"},
                    Backend:   "infra-backend-v1",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:   http.Request{Host: "bar.anotherwildcard.io", Path: "/s4"},
                    Backend:   "infra-backend-v1",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:   http.Request{Host: "foo.bar.anotherwildcard.io", Path: "/s4"},
                    Backend:   "infra-backend-v1",
                    Namespace: ns,
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "anotherwildcard.io", Path: "/s4"},
                    Response: http.Response{StatusCode: 404},
                },

                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.wildcard.io", Path: "/s4"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "very.specific.com", Path: "/s4"},
                    Response: http.Response{StatusCode: 404},
                },
                http.ExpectedResponse{
                    Request:  http.Request{Host: "foo.anotherwildcard.io", Path: "/non-matching-prefix"},
                    Response: http.Response{StatusCode: 404},
                },
            )

            for i := range testCases {

                tc := testCases[i]
                t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                    t.Parallel()
                    http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
                })
            }
        })

        t.Run("HTTPRoutes that do not intersect with listener hostnames", func(t *testing.T) {
            gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN))
            routeNN := types.NamespacedName{Namespace: ns, Name: "no-intersecting-hosts"}

            parents := []v1.RouteParentStatus{{
                ParentRef:      parentRefTo(gwNN),
                ControllerName: v1.GatewayController(suite.ControllerName),
                Conditions: []metav1.Condition{
                    {
                        Type:   string(v1.RouteConditionAccepted),
                        Status: metav1.ConditionFalse,
                        Reason: string(v1.RouteReasonNoMatchingListenerHostname),
                    },
                },
            }}

            kubernetes.HTTPRouteMustHaveParents(t, suite.Client, suite.TimeoutConfig, routeNN, parents, true)

            testCases := []http.ExpectedResponse{
                {
                    Request:  http.Request{Host: "specific.but.wrong.com", Path: "/s5"},
                    Response: http.Response{StatusCode: 404},
                },
                {
                    Request:  http.Request{Host: "wildcard.io", Path: "/s5"},
                    Response: http.Response{StatusCode: 404},
                },
            }

            for i := range testCases {

                tc := testCases[i]
                t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                    t.Parallel()
                    http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
                })
            }
        })
    },
}
var HTTPRouteInvalidBackendRefUnknownKind = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidBackendRefUnknownKind",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set a ResolvedRefs status False with reason InvalidKind when attempting to bind to a Gateway in the same namespace if the route has a BackendRef that points to an unknown Kind.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-invalid-backendref-unknown-kind.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "invalid-backend-ref-unknown-kind", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("HTTPRoute with Invalid Kind has a ResolvedRefs Condition with status False and Reason InvalidKind", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonInvalidKind),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("HTTP Request to invalid backend with invalid Kind receives a 500", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/v2",
                },
                Response: http.Response{StatusCode: 500},
            })
        })
    },
}
var HTTPRouteInvalidCrossNamespaceBackendRef = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidCrossNamespaceBackendRef",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set a ResolvedRefs status False with reason RefNotPermitted when attempting to bind to a Gateway in the same namespace if the route has a BackendRef Service in the gateway-conformance-web-backend namespace and a ReferenceGrant granting permission to route to that Service does not exist",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/httproute-invalid-cross-namespace-backend-ref.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "invalid-cross-namespace-backend-ref", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("HTTPRoute with a cross-namespace BackendRef and no ReferenceGrant has a ResolvedRefs Condition with status False and Reason RefNotPermitted", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonRefNotPermitted),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("HTTP Request to invalid cross-namespace backend must receive a 500", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response: http.Response{StatusCode: 500},
            })
        })
    },
}
var HTTPRouteInvalidCrossNamespaceParentRef = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidCrossNamespaceParentRef",
    Description: "A single HTTPRoute in the gateway-conformance-web-backend namespace should fail to attach to a Gateway in another namespace that it is not allowed to",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-invalid-cross-namespace-parent-ref.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}
        routeNN := types.NamespacedName{Name: "invalid-cross-namespace-parent-ref", Namespace: "gateway-conformance-web-backend"}
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("HTTPRoute should have an Accepted: false condition with reason NotAllowedByListeners", func(t *testing.T) {
            acceptedCond := metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonNotAllowedByListeners),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, acceptedCond)
        })

        t.Run("Route should not have Parents set in status", func(t *testing.T) {
            kubernetes.HTTPRouteMustHaveNoAcceptedParents(t, suite.Client, suite.TimeoutConfig, routeNN)
        })

        t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
            kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwNN)
        })
    },
}
var HTTPRouteInvalidNonExistentBackendRef = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidNonExistentBackendRef",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set a ResolvedRefs status False with reason BackendNotFound and return 500 when binding to a Gateway in the same namespace if the route has a BackendRef Service that does not exist",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-invalid-backendref-nonexistent.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "invalid-nonexistent-backend-ref", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("HTTPRoute with only a nonexistent BackendRef has a ResolvedRefs Condition with status False and Reason BackendNotFound", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonBackendNotFound),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("HTTP Request to invalid nonexistent backend receive a 500", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response: http.Response{StatusCode: 500},
            })
        })
    },
}
var HTTPRouteInvalidParentRefNotMatchingListenerPort = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidParentRefNotMatchingListenerPort",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set the Accepted status to False with reason NoMatchingParent when attempting to bind to a Gateway that does not have a matching ListenerPort.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteDestinationPortMatching,
    },
    Manifests: []string{"tests/httproute-invalid-parentref-not-matching-listener-port.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "httproute-listener-not-matching-route-port", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("HTTPRoute with no matching port in ParentRef has an Accepted Condition with status False and Reason NoMatchingParent", func(t *testing.T) {
            acceptedCond := metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonNoMatchingParent),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, acceptedCond)
        })

        t.Run("Route should not have Parents accepted in status", func(t *testing.T) {
            kubernetes.HTTPRouteMustHaveNoAcceptedParents(t, suite.Client, suite.TimeoutConfig, routeNN)
        })

        t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
            kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwNN)
        })
    },
}
var HTTPRouteInvalidParentRefNotMatchingSectionName = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidParentRefNotMatchingSectionName",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should set the Accepted status to False with reason NoMatchingParent when attempting to bind to a Gateway that does not have a matching SectionName.",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-invalid-parentref-not-matching-section-name.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "httproute-listener-not-matching-section-name", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        t.Run("HTTPRoute with no matching sectionName in ParentRef has an Accepted Condition with status False and Reason NoMatchingParent", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonNoMatchingParent),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("Route should not have Parents accepted in status", func(t *testing.T) {
            kubernetes.HTTPRouteMustHaveNoAcceptedParents(t, suite.Client, suite.TimeoutConfig, routeNN)
        })

        t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
            kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwNN)
        })
    },
}
var HTTPRouteInvalidReferenceGrant = suite.ConformanceTest{
    ShortName:   "HTTPRouteInvalidReferenceGrant",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace, with a backendRef in another namespace without valid ReferenceGrant, should have the ResolvedRefs condition set to False and not forward HTTP requests to any backend",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/httproute-invalid-reference-grant.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "reference-grant", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("HTTPRoute with BackendRef in another namespace and no ReferenceGrant covering the Service has a ResolvedRefs Condition with status False and Reason RefNotPermitted", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonRefNotPermitted),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("Simple HTTP request not should reach web-backend", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response:  http.Response{StatusCode: 500},
                Backend:   "web-backend",
                Namespace: "gateway-conformance-web-backend",
            })
        })
    },
}
var HTTPRouteListenerHostnameMatching = suite.ConformanceTest{
    ShortName:   "HTTPRouteListenerHostnameMatching",
    Description: "Multiple HTTP listeners with the same port and different hostnames, each with a different HTTPRoute",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-listener-hostname-matching.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"

        kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})

        routeNN1 := types.NamespacedName{Name: "backend-v1", Namespace: ns}
        routeNN2 := types.NamespacedName{Name: "backend-v2", Namespace: ns}
        routeNN3 := types.NamespacedName{Name: "backend-v3", Namespace: ns}
        gwNN := types.NamespacedName{Name: "httproute-listener-hostname-matching", Namespace: ns}

        kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN, "listener-1"), routeNN1)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN1, gwNN)

        kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN, "listener-2"), routeNN2)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN2, gwNN)

        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"), routeNN3)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN3, gwNN)

        testCases := []http.ExpectedResponse{{
            Request:   http.Request{Host: "bar.com", Path: "/"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Host: "foo.bar.com", Path: "/"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Host: "baz.bar.com", Path: "/"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:   http.Request{Host: "boo.bar.com", Path: "/"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:   http.Request{Host: "multiple.prefixes.bar.com", Path: "/"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:   http.Request{Host: "multiple.prefixes.foo.com", Path: "/"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:  http.Request{Host: "foo.com", Path: "/"},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:  http.Request{Host: "no.matching.host", Path: "/"},
            Response: http.Response{StatusCode: 404},
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteMatching = suite.ConformanceTest{
    ShortName:   "HTTPRouteMatching",
    Description: "A single HTTPRoute with path and header matching for different backends",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-matching.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "matching", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{{
            Request:   http.Request{Path: "/"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/example"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "one"}},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/v2"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/v2/example"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/", Headers: map[string]string{"Version": "two"}},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/v2/"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {

            Request:   http.Request{Path: "/v2example"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/foo/v2/example"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteMatchingAcrossRoutes = suite.ConformanceTest{
    ShortName:   "HTTPRouteMatchingAcrossRoutes",
    Description: "Two HTTPRoutes with path matching for different backends",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-matching-across-routes.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN1 := types.NamespacedName{Name: "matching-part1", Namespace: ns}
        routeNN2 := types.NamespacedName{Name: "matching-part2", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN1, routeNN2)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN1, gwNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN2, gwNN)

        testCases := []http.ExpectedResponse{{
            Request: http.Request{
                Host: "example.com",
                Path: "/",
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host: "example.com",
                Path: "/example",
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host: "example.net",
                Path: "/example",
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host:    "example.com",
                Path:    "/example",
                Headers: map[string]string{"Version": "one"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host: "example.com",
                Path: "/v2",
            },
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request: http.Request{

                Host: "example.net",
                Path: "/v2",
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host: "example.com",
                Path: "/v2/example",
            },
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request: http.Request{
                Host:    "example.com",
                Path:    "/",
                Headers: map[string]string{"Version": "two"},
            },
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteMethodMatching = suite.ConformanceTest{
    ShortName:   "HTTPRouteMethodMatching",
    Description: "A single HTTPRoute with method matching for different backends",
    Manifests:   []string{"tests/httproute-method-matching.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteMethodMatching,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "method-matching", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request:   http.Request{Method: "POST", Path: "/"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            }, {
                Request:   http.Request{Method: "GET", Path: "/"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            }, {
                Request:  http.Request{Method: "HEAD", Path: "/"},
                Response: http.Response{StatusCode: 404},
            },
        }

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path1", Method: "GET"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "one"}, Path: "/", Method: "PUT"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "two"}, Path: "/path2", Method: "POST"},
                Backend:   "infra-backend-v3",
                Namespace: ns,
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path3", Method: "PATCH"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "three"}, Path: "/path4", Method: "DELETE"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:  http.Request{Path: "/", Method: "PUT"},
                Response: http.Response{StatusCode: 404},
            },
            {
                Request:  http.Request{Path: "/path4", Method: "DELETE"},
                Response: http.Response{StatusCode: 404},
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path5", Method: "PATCH"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "four"}, Path: "/", Method: "PATCH"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            },
        }...)

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteObservedGenerationBump = suite.ConformanceTest{
    ShortName:   "HTTPRouteObservedGenerationBump",
    Description: "A HTTPRoute in the gateway-conformance-infra namespace should update the observedGeneration in all of it's Status.Conditions after an update to the spec",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-observed-generation-bump.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "observed-generation-bump", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        t.Run("observedGeneration should increment", func(t *testing.T) {
            ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
            defer cancel()

            namespaces := []string{"gateway-conformance-infra"}
            kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, namespaces)

            original := &v1.HTTPRoute{}
            err := suite.Client.Get(ctx, routeNN, original)
            require.NoErrorf(t, err, "error getting HTTPRoute: %v", err)

            kubernetes.HTTPRouteMustHaveLatestConditions(t, original)

            mutate := original.DeepCopy()
            mutate.Spec.Rules[0].BackendRefs[0].Name = "infra-backend-v2"
            err = suite.Client.Patch(ctx, mutate, client.MergeFrom(original))
            require.NoErrorf(t, err, "error patching the HTTPRoute: %v", err)

            kubernetes.HTTPRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, metav1.Condition{
                Type:   string(v1.RouteConditionAccepted),
                Status: metav1.ConditionTrue,
                Reason: "",
            })
            kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

            updated := &v1.HTTPRoute{}
            err = suite.Client.Get(ctx, routeNN, updated)
            require.NoErrorf(t, err, "error getting Gateway: %v", err)

            kubernetes.HTTPRouteMustHaveLatestConditions(t, updated)

            require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
        })
    },
}
var HTTPRoutePartiallyInvalidViaInvalidReferenceGrant = suite.ConformanceTest{
    ShortName:   "HTTPRoutePartiallyInvalidViaInvalidReferenceGrant",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace should attach to a Gateway in the same namespace if the route has a backendRef Service in the gateway-conformance-app-backend namespace and a ReferenceGrant exists but does not grant permission to route to that specific Service",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/httproute-partially-invalid-via-reference-grant.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "invalid-reference-grant", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, s.Client, s.TimeoutConfig, s.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("HTTPRoute with BackendRef in another namespace and no ReferenceGrant covering the Service has a ResolvedRefs Condition with status False and Reason RefNotPermitted", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1.RouteReasonRefNotPermitted),
            }

            kubernetes.HTTPRouteMustHaveCondition(t, s.Client, s.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })

        t.Run("HTTP Request to invalid backend with missing referenceGrant should receive a 500", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, s.RoundTripper, s.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/v2",
                },
                Response: http.Response{StatusCode: 500},
            })
        })

        t.Run("HTTP Request to valid sibling backend should succeed", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, s.RoundTripper, s.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response:  http.Response{StatusCode: 200},
                Backend:   "app-backend-v1",
                Namespace: "gateway-conformance-app-backend",
            })
        })
    },
}
var HTTPRoutePathMatchOrder = suite.ConformanceTest{
    ShortName:   "HTTPRoutePathMatchOrder",
    Description: "An HTTPRoute where there are multiple matches routing to any given backend follows match order precedence",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-path-match-order.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Namespace: ns, Name: "path-matching-order"}
        gwNN := types.NamespacedName{Namespace: ns, Name: "same-namespace"}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/match/exact/one"},
                Backend:   "infra-backend-v3",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/match/exact"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/match"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/match/prefix/one/any"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/match/prefix/any"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/match/any"},
                Backend:   "infra-backend-v3",
                Namespace: ns,
            },
        }

        for i := range testCases {
            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteQueryParamMatching = suite.ConformanceTest{
    ShortName:   "HTTPRouteQueryParamMatching",
    Description: "A single HTTPRoute with query param matching for different backends",
    Manifests:   []string{"tests/httproute-query-param-matching.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteQueryParamMatching,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Namespace: ns, Name: "query-param-matching"}
        gwNN := types.NamespacedName{Namespace: ns, Name: "same-namespace"}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{{
            Request:   http.Request{Path: "/?animal=whale"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/?animal=dolphin"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/?animal=dolphin&color=blue"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/?ANIMAL=Whale"},
            Backend:   "infra-backend-v3",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/?animal=whale&otherparam=irrelevant"},
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request:   http.Request{Path: "/?animal=dolphin&color=yellow"},
            Backend:   "infra-backend-v2",
            Namespace: ns,
        }, {
            Request:  http.Request{Path: "/?color=blue"},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:  http.Request{Path: "/?animal=dog"},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:  http.Request{Path: "/?animal=whaledolphin"},
            Response: http.Response{StatusCode: 404},
        }, {
            Request:  http.Request{Path: "/"},
            Response: http.Response{StatusCode: 404},
        }}

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path1?animal=whale"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "one"}, Path: "/?animal=whale"},
                Backend:   "infra-backend-v2",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "two"}, Path: "/path2?animal=whale"},
                Backend:   "infra-backend-v3",
                Namespace: ns,
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path3?animal=shark"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "three"}, Path: "/path4?animal=kraken"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:  http.Request{Path: "/?animal=shark"},
                Response: http.Response{StatusCode: 404},
            },
            {
                Request:  http.Request{Path: "/path4?animal=kraken"},
                Response: http.Response{StatusCode: 404},
            },
        }...)

        testCases = append(testCases, []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/path5?animal=hydra"},
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request:   http.Request{Headers: map[string]string{"version": "four"}, Path: "/?animal=hydra"},
                Backend:   "infra-backend-v3",
                Namespace: ns,
            },
        }...)

        for i := range testCases {
            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRedirectHostAndStatus = suite.ConformanceTest{
    ShortName:   "HTTPRouteRedirectHostAndStatus",
    Description: "An HTTPRoute with hostname and statusCode redirect filters",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-redirect-host-and-status.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "redirect-host-and-status", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/hostname-redirect",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host: "example.org",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/host-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 301,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host: "example.org",
                },
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRedirectPath = suite.ConformanceTest{
    ShortName:   "HTTPRouteRedirectPath",
    Description: "An HTTPRoute with scheme redirect filter",
    Manifests:   []string{"tests/httproute-redirect-path.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRoutePathRedirect,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "redirect-path", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/original-prefix/lemon",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Path: "/replacement-prefix/lemon",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/full/path/original",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Path: "/full-path-replacement",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/path-and-host",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host: "example.org",
                    Path: "/replacement-prefix",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/path-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 301,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Path: "/replacement-prefix",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/full-path-and-host",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host: "example.org",
                    Path: "/replacement-full",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/full-path-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 301,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Path: "/replacement-full",
                },
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRedirectPort = suite.ConformanceTest{
    ShortName:   "HTTPRouteRedirectPort",
    Description: "An HTTPRoute with a port redirect filter",
    Manifests:   []string{"tests/httproute-redirect-port.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRoutePortRedirect,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "redirect-port", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/port",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Port: "8083",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/port-and-host",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host: "example.org",
                    Port: "8083",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/port-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 301,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Port: "8083",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/port-and-host-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Port: "8083",
                    Host: "example.org",
                },
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRedirectPortAndScheme = suite.ConformanceTest{
    ShortName:   "HTTPRouteRedirectPortAndScheme",
    Description: "An HTTPRoute with port and scheme redirect filter",
    Manifests:   []string{"tests/httproute-redirect-port-and-scheme.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRoutePortRedirect,
        suite.SupportGatewayPort8080,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"

        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        routeNN := types.NamespacedName{Name: "http-route-for-listener-on-port-80", Namespace: ns}
        gwAddr80 := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        gwNN = types.NamespacedName{Name: "same-namespace-with-http-listener-on-8080", Namespace: ns}
        routeNN = types.NamespacedName{Name: "http-route-for-listener-on-port-8080", Namespace: ns}
        gwAddr8080 := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        gwNN = types.NamespacedName{Name: "same-namespace-with-https-listener", Namespace: ns}
        routeNN = types.NamespacedName{Name: "http-route-for-listener-on-port-443", Namespace: ns}
        gwAddr443 := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        certNN := types.NamespacedName{Name: "tls-validity-checks-certificate", Namespace: ns}
        cPem, keyPem, err := GetTLSSecret(suite.Client, certNN)
        if err != nil {
            t.Fatalf("unexpected error finding TLS secret: %v", err)
        }

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/scheme-nil-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-nil-and-port-80",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-nil-and-port-8080",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Port:   "8080",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-https-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-https-and-port-443",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-https-and-port-8443",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Port:   "8443",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
        }

        for i := range testCases {
            tc := testCases[i]
            t.Run("http-listener-on-80/"+tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr80, tc)
            })
        }

        testCases = []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/scheme-nil-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Port:   "8080",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-nil-and-port-80",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path:             "/scheme-https-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
        }

        for i := range testCases {
            tc := testCases[i]
            t.Run("http-listener-on-8080/"+tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr8080, tc)
            })
        }

        testCases = []http.ExpectedResponse{
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-nil-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-nil-and-port-443",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-nil-and-port-8443",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Port:   "8443",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-http-and-port-nil",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-http-and-port-80",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Host:             "example.org",
                    Path:             "/scheme-http-and-port-8080",
                    UnfollowRedirect: true,
                },
                Response: http.Response{StatusCode: 302},
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "http",
                    Port:   "8080",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
        }

        for i := range testCases {
            tc := testCases[i]
            t.Run("https-listener-on-443/"+tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr443, cPem, keyPem, "example.org", tc)
            })
        }
    },
}
var HTTPRouteRedirectScheme = suite.ConformanceTest{
    ShortName:   "HTTPRouteRedirectScheme",
    Description: "An HTTPRoute with a scheme redirect filter",
    Manifests:   []string{"tests/httproute-redirect-scheme.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteSchemeRedirect,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "redirect-scheme", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path:             "/scheme",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/scheme-and-host",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Host:   "example.org",
                    Scheme: "https",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/scheme-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 301,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path:             "/scheme-and-host-and-status",
                    UnfollowRedirect: true,
                },
                Response: http.Response{
                    StatusCode: 302,
                },
                RedirectRequest: &roundtripper.RedirectRequest{
                    Scheme: "https",
                    Host:   "example.org",
                },
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteReferenceGrant = suite.ConformanceTest{
    ShortName:   "HTTPRouteReferenceGrant",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace, with a backendRef in the gateway-conformance-web-backend namespace, should attach to Gateway in the gateway-conformance-infra namespace",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/httproute-reference-grant.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "reference-grant", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("Simple HTTP request should reach web-backend", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response:  http.Response{StatusCode: 200},
                Backend:   "web-backend",
                Namespace: "gateway-conformance-web-backend",
            })
        })

        ctx, cancel := context.WithTimeout(context.Background(), suite.TimeoutConfig.DeleteTimeout)
        defer cancel()
        rg := v1beta1.ReferenceGrant{
            ObjectMeta: metav1.ObjectMeta{
                Name:      "reference-grant",
                Namespace: "gateway-conformance-web-backend",
            },
        }
        require.NoError(t, suite.Client.Delete(ctx, &rg))

        t.Run("Simple HTTP request should return 500 after deleting the relevant reference grant", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request: http.Request{
                    Method: "GET",
                    Path:   "/",
                },
                Response: http.Response{StatusCode: 500},
            })
        })
    },
}
var HTTPRouteRequestHeaderModifier = suite.ConformanceTest{
    ShortName:   "HTTPRouteRequestHeaderModifier",
    Description: "An HTTPRoute has request header modifier filters applied correctly",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-request-header-modifier.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "request-header-modifier", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{{
            Request: http.Request{
                Path: "/set",
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/set",
                    Headers: map[string]string{
                        "Some-Other-Header": "val",
                        "X-Header-Set":      "set-overwrites-values",
                    },
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/set",
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Set":      "some-other-value",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/set",
                    Headers: map[string]string{
                        "Some-Other-Header": "val",
                        "X-Header-Set":      "set-overwrites-values",
                    },
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/add",
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/add",
                    Headers: map[string]string{
                        "Some-Other-Header": "val",
                        "X-Header-Add":      "add-appends-values",
                    },
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/add",
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Add":      "some-other-value",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/add",
                    Headers: map[string]string{
                        "Some-Other-Header": "val",
                        "X-Header-Add":      "some-other-value,add-appends-values",
                    },
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/remove",
                Headers: map[string]string{
                    "X-Header-Remove": "val",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/remove",
                },
                AbsentHeaders: []string{"X-Header-Remove"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/multiple",
                Headers: map[string]string{
                    "X-Header-Set-2":    "set-val-2",
                    "X-Header-Add-2":    "add-val-2",
                    "X-Header-Remove-2": "remove-val-2",
                    "Another-Header":    "another-header-val",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/multiple",
                    Headers: map[string]string{
                        "X-Header-Set-1": "header-set-1",
                        "X-Header-Set-2": "header-set-2",
                        "X-Header-Add-1": "header-add-1",
                        "X-Header-Add-2": "add-val-2,header-add-2",
                        "X-Header-Add-3": "header-add-3",
                        "Another-Header": "another-header-val",
                    },
                },
                AbsentHeaders: []string{"X-Header-Remove-1", "X-Header-Remove-2"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/case-insensitivity",

                Headers: map[string]string{
                    "x-header-set":    "original-val-set",
                    "x-header-add":    "original-val-add",
                    "x-header-remove": "original-val-remove",
                    "Another-Header":  "another-header-val",
                },
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/case-insensitivity",
                    Headers: map[string]string{
                        "X-Header-Set":   "header-set",
                        "X-Header-Add":   "original-val-add,header-add",
                        "Another-Header": "another-header-val",
                    },
                },
                AbsentHeaders: []string{"x-header-remove", "X-Header-Remove"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRequestMirror = suite.ConformanceTest{
    ShortName:   "HTTPRouteRequestMirror",
    Description: "An HTTPRoute with request mirror filter",
    Manifests:   []string{"tests/httproute-request-mirror.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.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)

        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,
                }},
            },
        }
        for i := range testCases {

            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 HTTPRouteRequestMultipleMirrors = suite.ConformanceTest{
    ShortName:   "HTTPRouteRequestMultipleMirrors",
    Description: "An HTTPRoute with multiple request mirror filters",
    Manifests:   []string{"tests/httproute-request-multiple-mirrors.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteRequestMirror,
        suite.SupportHTTPRouteRequestMultipleMirrors,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "request-multiple-mirrors", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path: "/multi-mirror",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/multi-mirror",
                    },
                },
                Backend: "infra-backend-v1",
                MirroredTo: []http.BackendRef{
                    {
                        Name:      "infra-backend-v2",
                        Namespace: ns,
                    },
                    {
                        Name:      "infra-backend-v3",
                        Namespace: ns,
                    },
                },
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path: "/multi-mirror-and-modify-request-headers",
                    Headers: map[string]string{
                        "X-Header-Remove":     "remove-val",
                        "X-Header-Add-Append": "append-val-1",
                    },
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/multi-mirror-and-modify-request-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,
                    },
                    {
                        Name:      "infra-backend-v3",
                        Namespace: ns,
                    },
                },
            },
        }
        for i := range testCases {

            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 HTTPRouteResponseHeaderModifier = suite.ConformanceTest{
    ShortName:   "HTTPRouteResponseHeaderModifier",
    Description: "An HTTPRoute has response header modifier filters applied correctly",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteResponseHeaderModification,
    },
    Manifests: []string{"tests/httproute-response-header-modifier.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "response-header-modifier", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{{
            Request: http.Request{
                Path: "/set",
            },
            BackendSetResponseHeaders: map[string]string{
                "Some-Other-Header": "val",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Set":      "set-overwrites-values",
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/set",
            },
            BackendSetResponseHeaders: map[string]string{
                "Some-Other-Header": "val",
                "X-Header-Set":      "some-other-value",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Set":      "set-overwrites-values",
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/add",
            },
            BackendSetResponseHeaders: map[string]string{
                "Some-Other-Header": "val",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Add":      "add-appends-values",
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/add",
            },
            BackendSetResponseHeaders: map[string]string{
                "Some-Other-Header": "val",
                "X-Header-Add":      "some-other-value",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "Some-Other-Header": "val",
                    "X-Header-Add":      "some-other-value,add-appends-values",
                },
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/remove",
            },
            BackendSetResponseHeaders: map[string]string{
                "X-Header-Remove": "val",
            },
            Response: http.Response{
                AbsentHeaders: []string{"X-Header-Remove"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/multiple",
            },
            BackendSetResponseHeaders: map[string]string{
                "X-Header-Set-2":    "set-val-2",
                "X-Header-Add-2":    "add-val-2",
                "X-Header-Remove-2": "remove-val-2",
                "Another-Header":    "another-header-val",
                "X-Header-Remove-1": "val",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "X-Header-Set-1": "header-set-1",
                    "X-Header-Set-2": "header-set-2",
                    "X-Header-Add-1": "header-add-1",
                    "X-Header-Add-2": "add-val-2,header-add-2",
                    "X-Header-Add-3": "header-add-3",
                    "Another-Header": "another-header-val",
                },
                AbsentHeaders: []string{"X-Header-Remove-1", "X-Header-Remove-2"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/case-insensitivity",
            },
            BackendSetResponseHeaders: map[string]string{
                "x-header-set":    "original-val-set",
                "x-header-add":    "original-val-add",
                "x-header-remove": "original-val-remove",
                "Another-Header":  "another-header-val",
            },
            Response: http.Response{
                Headers: map[string]string{
                    "X-Header-Set":      "header-set",
                    "X-Header-Add":      "original-val-add,header-add",
                    "X-Lowercase-Add":   "lowercase-add",
                    "X-Mixedcase-Add-1": "mixedcase-add-1",
                    "X-Mixedcase-Add-2": "mixedcase-add-2",
                    "X-Uppercase-Add":   "uppercase-add",
                    "Another-Header":    "another-header-val",
                },
                AbsentHeaders: []string{"x-header-remove", "X-Header-Remove"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }, {
            Request: http.Request{
                Path: "/response-and-request-header-modifiers",
                Headers: map[string]string{
                    "X-Header-Remove":     "remove-val",
                    "X-Header-Add-Append": "append-val-1",
                    "X-Header-Echo":       "echo",
                },
            },
            BackendSetResponseHeaders: map[string]string{
                "X-Header-Set-2":    "set-val-2",
                "X-Header-Add-2":    "add-val-2",
                "X-Header-Remove-2": "remove-val-2",
                "Another-Header":    "another-header-val",
                "X-Header-Remove-1": "remove-val-1",
                "X-Header-Echo":     "echo",
            },
            ExpectedRequest: &http.ExpectedRequest{
                Request: http.Request{
                    Path: "/response-and-request-header-modifiers",
                    Headers: map[string]string{
                        "X-Header-Add":        "header-val-1",
                        "X-Header-Set":        "set-overwrites-values",
                        "X-Header-Add-Append": "append-val-1,header-val-2",
                        "X-Header-Echo":       "echo",
                    },
                },
                AbsentHeaders: []string{"X-Header-Remove"},
            },
            Response: http.Response{
                Headers: map[string]string{
                    "X-Header-Set-1": "header-set-1",
                    "X-Header-Set-2": "header-set-2",
                    "X-Header-Add-1": "header-add-1",
                    "X-Header-Add-2": "add-val-2,header-add-2",
                    "Another-Header": "another-header-val",
                    "X-Header-Echo":  "echo",
                },
                AbsentHeaders: []string{"X-Header-Remove-1", "X-Header-Remove-2"},
            },
            Backend:   "infra-backend-v1",
            Namespace: ns,
        }}

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRewriteHost = suite.ConformanceTest{
    ShortName:   "HTTPRouteRewriteHost",
    Description: "An HTTPRoute with hostname rewrite filter",
    Manifests:   []string{"tests/httproute-rewrite-host.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteHostRewrite,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "rewrite-host", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path: "/one",
                    Host: "rewrite.example",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/one",
                        Host: "one.example.org",
                    },
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path: "/two",
                    Host: "rewrite.example",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/two",
                        Host: "example.org",
                    },
                },
                Backend:   "infra-backend-v2",
                Namespace: ns,
            }, {
                Request: http.Request{
                    Path: "/rewrite-host-and-modify-headers",
                    Host: "rewrite.example",
                    Headers: map[string]string{
                        "X-Header-Remove":     "remove-val",
                        "X-Header-Add-Append": "append-val-1",
                    },
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/rewrite-host-and-modify-headers",
                        Host: "test.example.org",
                        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"},
                },
                Backend:   "infra-backend-v2",
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteRewritePath = suite.ConformanceTest{
    ShortName:   "HTTPRouteRewritePath",
    Description: "An HTTPRoute with path rewrite filter",
    Manifests:   []string{"tests/httproute-rewrite-path.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRoutePathRewrite,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "rewrite-path", Namespace: ns}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Path: "/prefix/one/two",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/one/two",
                    },
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path: "/strip-prefix/three",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/three",
                    },
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path: "/strip-prefix",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/",
                    },
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path: "/full/one/two",
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/one",
                    },
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path: "/full/rewrite-path-and-modify-headers/test",
                    Headers: map[string]string{
                        "X-Header-Remove":     "remove-val",
                        "X-Header-Add-Append": "append-val-1",
                        "X-Header-Set":        "set-val",
                    },
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/test",
                        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"},
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
            {
                Request: http.Request{
                    Path: "/prefix/rewrite-path-and-modify-headers/one",
                    Headers: map[string]string{
                        "X-Header-Remove":     "remove-val",
                        "X-Header-Add-Append": "append-val-1",
                        "X-Header-Set":        "set-val",
                    },
                },
                ExpectedRequest: &http.ExpectedRequest{
                    Request: http.Request{
                        Path: "/prefix/one",
                        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"},
                },
                Backend:   "infra-backend-v1",
                Namespace: ns,
            },
        }
        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteSimpleSameNamespace = suite.ConformanceTest{
    ShortName:   "HTTPRouteSimpleSameNamespace",
    Description: "A single HTTPRoute in the gateway-conformance-infra namespace attaches to a Gateway in the same namespace",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
    },
    Manifests: []string{"tests/httproute-simple-same-namespace.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := v1beta1.Namespace("gateway-conformance-infra")
        routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: string(ns)}
        gwNN := types.NamespacedName{Name: "same-namespace", Namespace: string(ns)}
        gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) {
            http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, http.ExpectedResponse{
                Request:   http.Request{Path: "/"},
                Response:  http.Response{StatusCode: 200},
                Backend:   "infra-backend-v1",
                Namespace: "gateway-conformance-infra",
            })
        })
    },
}
var HTTPRouteTimeoutBackendRequest = suite.ConformanceTest{
    ShortName:   "HTTPRouteTimeoutBackendRequest",
    Description: "An HTTPRoute with backend request timeout",
    Manifests:   []string{"tests/httproute-timeout-backend-request.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteBackendTimeout,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "backend-request-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)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/backend-timeout"},
                Response:  http.Response{StatusCode: 200},
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/backend-timeout?delay=1s"},
                Response:  http.Response{StatusCode: 504},
                Namespace: ns,
            },
        }

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var HTTPRouteTimeoutRequest = suite.ConformanceTest{
    ShortName:   "HTTPRouteTimeoutRequest",
    Description: "An HTTPRoute with request timeout",
    Manifests:   []string{"tests/httproute-timeout-request.yaml"},
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteRequestTimeout,
    },
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "request-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)
        kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)

        testCases := []http.ExpectedResponse{
            {
                Request:   http.Request{Path: "/request-timeout"},
                Response:  http.Response{StatusCode: 200},
                Namespace: ns,
            }, {
                Request:   http.Request{Path: "/request-timeout?delay=1s"},
                Response:  http.Response{StatusCode: 504},
                Namespace: ns,
            },
        }

        for i := range testCases {

            tc := testCases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                t.Parallel()
                http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
            })
        }
    },
}
var MeshBasic = suite.ConformanceTest{
    ShortName:   "MeshBasic",
    Description: "A mesh client can communicate with a mesh server. This tests basic reachability with no configuration applied.",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
    },
    Manifests: []string{},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
        cases := []http.ExpectedResponse{{
            Request: http.Request{
                Host:   "echo",
                Method: "GET",
            },
            Response: http.Response{
                StatusCode: 200,
            },
        }}
        for i := range cases {

            tc := cases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var MeshConsumerRoute = suite.ConformanceTest{
    ShortName:   "MeshConsumerRoute",
    Description: "An HTTPRoute in a namespace other than its parentRef's namespace only affects requests from the route's namespace",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteResponseHeaderModification,
    },
    Manifests: []string{"tests/mesh-consumer-route.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        consumerClient := echo.ConnectToAppInNamespace(t, s, echo.MeshAppEchoV1, "gateway-conformance-mesh-consumer")
        consumerCases := []http.ExpectedResponse{
            {
                TestCaseName: "request from consumer route's namespace modified by HTTPRoute",
                Request: http.Request{
                    Host:   "echo-v1.gateway-conformance-mesh",
                    Method: "GET",
                    Path:   "/",
                },
                Response: http.Response{
                    StatusCode: 200,
                    Headers: map[string]string{
                        "X-Header-Set": "set",
                    },
                },
                Backend: "echo-v1",
            },
        }
        producerClient := echo.ConnectToAppInNamespace(t, s, echo.MeshAppEchoV1, "gateway-conformance-mesh")
        producerCases := []http.ExpectedResponse{
            {
                TestCaseName: "request not from consumer route's namespace not modified by HTTPRoute",
                Request: http.Request{
                    Host:   "echo-v1.gateway-conformance-mesh",
                    Method: "GET",
                    Path:   "/",
                },
                Response: http.Response{
                    StatusCode:    200,
                    AbsentHeaders: []string{"X-Header-Set"},
                },
                Backend: "echo-v1",
            },
        }
        for i, tc := range consumerCases {
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                consumerClient.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
        for i, tc := range producerCases {
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                producerClient.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var MeshFrontend = suite.ConformanceTest{
    ShortName:   "MeshFrontend",
    Description: "Mesh rules should only apply to the associated frontend",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteResponseHeaderModification,
    },
    Manifests: []string{"tests/mesh-frontend.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
        v2 := echo.ConnectToApp(t, s, echo.MeshAppEchoV2)
        cases := []http.ExpectedResponse{
            {
                TestCaseName: "Send to service",
                Request: http.Request{
                    Host:   "echo-v2",
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,

                    Headers: map[string]string{
                        "X-Header-Set": "set",
                    },
                },
                Backend: "echo-v2",
            },
            {
                TestCaseName: "Send to pod IP",
                Request: http.Request{
                    Host:   v2.Address,
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode:    200,
                    AbsentHeaders: []string{"X-Header-Set"},
                },
                Backend: "echo-v2",
            },
        }
        for i := range cases {

            tc := cases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var MeshFrontendHostname = suite.ConformanceTest{
    ShortName:   "MeshFrontendHostname",
    Description: "Mesh parentRef matches Service IP (not Host)",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
        suite.SupportHTTPRouteResponseHeaderModification,
    },
    Manifests: []string{"tests/mesh-frontend.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
        cases := []http.ExpectedResponse{
            {
                TestCaseName: "Send to service with wrong hostname",
                Request: http.Request{
                    Host: "echo-v2",
                    Headers: map[string]string{
                        "Host": "echo-v1",
                    },
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,

                    Headers: map[string]string{
                        "X-Header-Set": "set",
                    },
                },
                Backend: "echo-v2",
            },
            {
                TestCaseName: "Send to other service with matching hostname",
                Request: http.Request{
                    Host: "echo-v1",
                    Headers: map[string]string{
                        "Host": "echo-v2",
                    },
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode:    200,
                    AbsentHeaders: []string{"X-Header-Set"},
                },
                Backend: "echo-v1",
            },
        }
        for i := range cases {

            tc := cases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var MeshPorts = suite.ConformanceTest{
    ShortName:   "MeshPorts",
    Description: "A mesh route can optionally configure 'port' in parentRef",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
        suite.SupportHTTPRoute,
        suite.SupportHTTPRouteResponseHeaderModification,
    },
    Manifests: []string{"tests/mesh-ports.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
        cases := []http.ExpectedResponse{
            {
                TestCaseName: "Explicit port set, send to that port",
                Request: http.Request{
                    Host:   "echo-v1",
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,

                    Headers: map[string]string{
                        "X-Header-Set": "v1",
                    },
                },
                Backend: "echo-v1",
            },
            {
                TestCaseName: "Explicit port, send to an excluded port",
                Request: http.Request{
                    Host:   "echo-v1:8080",
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,

                    AbsentHeaders: []string{"X-Header-Set"},
                },
                Backend: "echo-v1",
            },
            {
                TestCaseName: "No port set",
                Request: http.Request{
                    Host:   "echo-v2",
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,
                    Headers: map[string]string{
                        "X-Header-Set": "v2",
                    },
                },
                Backend: "echo-v2",
            },
            {
                TestCaseName: "No port set",
                Request: http.Request{
                    Host:   "echo-v2:8080",
                    Method: "GET",
                },
                Response: http.Response{
                    StatusCode: 200,
                    Headers: map[string]string{
                        "X-Header-Set": "v2",
                    },
                },
                Backend: "echo-v2",
            },
        }
        for i := range cases {

            tc := cases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var MeshTrafficSplit = suite.ConformanceTest{
    ShortName:   "MeshTrafficSplit",
    Description: "A mesh client can send traffic to a Service which is split between two versions",
    Features: []suite.SupportedFeature{
        suite.SupportMesh,
    },
    Manifests: []string{"tests/mesh-split.yaml"},
    Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
        client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1)
        cases := []http.ExpectedResponse{
            {
                Request: http.Request{
                    Host:   "echo",
                    Method: "GET",
                    Path:   "/v1",
                },
                Response: http.Response{
                    StatusCode: 200,
                },
                Backend: "echo-v1",
            },
            {
                Request: http.Request{
                    Host:   "echo",
                    Method: "GET",
                    Path:   "/v2",
                },
                Response: http.Response{
                    StatusCode: 200,
                },
                Backend: "echo-v2",
            },
        }
        for i := range cases {

            tc := cases[i]
            t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
                client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig)
            })
        }
    },
}
var TLSRouteInvalidReferenceGrant = suite.ConformanceTest{
    ShortName:   "TLSRouteInvalidReferenceGrant",
    Description: "A single TLSRoute in the gateway-conformance-infra namespace, with a backendRef in another namespace without valid ReferenceGrant, should have the ResolvedRefs condition set to False",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportTLSRoute,
        suite.SupportReferenceGrant,
    },
    Manifests: []string{"tests/tlsroute-invalid-reference-grant.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: "gateway-conformance-infra"}
        gwNN := types.NamespacedName{Name: "gateway-tlsroute-referencegrant", Namespace: "gateway-conformance-infra"}

        kubernetes.GatewayAndTLSRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

        t.Run("TLSRoute with BackendRef in another namespace and no ReferenceGrant covering the Service has a ResolvedRefs Condition with status False and Reason RefNotPermitted", func(t *testing.T) {
            resolvedRefsCond := metav1.Condition{
                Type:   string(v1beta1.RouteConditionResolvedRefs),
                Status: metav1.ConditionFalse,
                Reason: string(v1beta1.RouteReasonRefNotPermitted),
            }

            kubernetes.TLSRouteMustHaveCondition(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN, resolvedRefsCond)
        })
    },
}
var TLSRouteSimpleSameNamespace = suite.ConformanceTest{
    ShortName:   "TLSRouteSimpleSameNamespace",
    Description: "A single TLSRoute in the gateway-conformance-infra namespace attaches to a Gateway in the same namespace",
    Features: []suite.SupportedFeature{
        suite.SupportGateway,
        suite.SupportTLSRoute,
    },
    Manifests: []string{"tests/tlsroute-simple-same-namespace.yaml"},
    Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
        ns := "gateway-conformance-infra"
        routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: ns}
        gwNN := types.NamespacedName{Name: "gateway-tlsroute", Namespace: ns}
        certNN := types.NamespacedName{Name: "tls-passthrough-checks-certificate", Namespace: ns}

        kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})

        gwAddr, hostnames := kubernetes.GatewayAndTLSRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
        if len(hostnames) != 1 {
            t.Fatalf("unexpected error in test configuration, found %d hostnames", len(hostnames))
        }
        serverStr := string(hostnames[0])

        cPem, keyPem, err := GetTLSSecret(suite.Client, certNN)
        if err != nil {
            t.Fatalf("unexpected error finding TLS secret: %v", err)
        }
        t.Run("Simple TLS request matching TLSRoute should reach infra-backend", func(t *testing.T) {
            tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, serverStr,
                http.ExpectedResponse{
                    Request:   http.Request{Host: serverStr, Path: "/"},
                    Backend:   "tls-backend",
                    Namespace: "gateway-conformance-infra",
                })
        })
    },
}

func GetTLSSecret

func GetTLSSecret(client client.Client, secretName types.NamespacedName) ([]byte, []byte, error)

GetTLSSecret fetches the named Secret and converts both cert and key to []byte