tests

package
v0.6.0-rc2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 16, 2022 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ConformanceTests []suite.ConformanceTest
View Source
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.",
	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 := []v1beta1.ListenerStatus{{
				Name:           v1beta1.SectionName("http"),
				SupportedKinds: []v1beta1.RouteGroupKind{},
				Conditions: []metav1.Condition{{
					Type:   string(v1beta1.ListenerConditionResolvedRefs),
					Status: metav1.ConditionFalse,
					Reason: string(v1beta1.ListenerReasonInvalidRouteKinds),
				}},
			}}

			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 := []v1beta1.ListenerStatus{{
				Name: v1beta1.SectionName("http"),
				SupportedKinds: []v1beta1.RouteGroupKind{{
					Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
					Kind:  v1beta1.Kind("HTTPRoute"),
				}},
				Conditions: []metav1.Condition{{
					Type:   string(v1beta1.ListenerConditionResolvedRefs),
					Status: metav1.ConditionFalse,
					Reason: string(v1beta1.ListenerReasonInvalidRouteKinds),
				}},
			}}

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

		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)
			})
		}
	},
}
View Source
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.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 := []v1beta1.ListenerStatus{{
				Name: v1beta1.SectionName("https"),
				SupportedKinds: []v1beta1.RouteGroupKind{{
					Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
					Kind:  v1beta1.Kind("HTTPRoute"),
				}},
				Conditions: []metav1.Condition{{
					Type:   string(v1beta1.ListenerConditionResolvedRefs),
					Status: metav1.ConditionFalse,
					Reason: string(v1beta1.ListenerReasonRefNotPermitted),
				}},
			}}

			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
		})
	},
}
View Source
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.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 := []v1beta1.ListenerStatus{{
				Name: v1beta1.SectionName("https"),
				SupportedKinds: []v1beta1.RouteGroupKind{{
					Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
					Kind:  v1beta1.Kind("HTTPRoute"),
				}},
				Conditions: []metav1.Condition{{
					Type:   string(v1beta1.ListenerConditionResolvedRefs),
					Status: metav1.ConditionFalse,
					Reason: string(v1beta1.ListenerReasonRefNotPermitted),
				}},
			}}

			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
		})
	},
}
View Source
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.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", Namespace: "gateway-conformance-infra"}

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

			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
		})
	},
}
View Source
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.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", Namespace: "gateway-conformance-infra"}

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

			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
		})
	},
}
View Source
var HTTPExactPathMatching = suite.ConformanceTest{
	ShortName:   "HTTPExactPathMatching",
	Description: "A single HTTPRoute with exact path matching for different backends",
	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)

		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},
			},
		}

		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)
			})
		}
	},
}
View Source
var HTTPRouteCrossNamespace = suite.ConformanceTest{
	ShortName:   "HTTPRouteCrossNamespace",
	Description: "A single HTTPRoute in the gateway-conformance-web-backend namespace should attach to Gateway in another namespace",
	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)

		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",
			})
		})
	},
}
View Source
var HTTPRouteDisallowedKind = suite.ConformanceTest{
	ShortName:   "HTTPRouteDisallowedKind",
	Description: "A single HTTPRoute in the gateway-conformance-infra namespace should fail to attach to a Listener that does not allow the HTTPRoute kind",
	Features:    []suite.SupportedFeature{suite.SupportTLSRoute},
	Manifests:   []string{"tests/httproute-disallowed-kind.yaml"},
	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {

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

		routeName := types.NamespacedName{Name: "disallowed-kind", Namespace: "gateway-conformance-infra"}
		gwName := types.NamespacedName{Name: "tlsroutes-only", Namespace: "gateway-conformance-infra"}

		t.Run("Route should not have Parents set in status", func(t *testing.T) {
			kubernetes.HTTPRouteMustHaveNoAcceptedParents(t, suite.Client, suite.TimeoutConfig, routeName)
		})
		t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
			kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwName)
		})
	},
}
View Source
var HTTPRouteHeaderMatching = suite.ConformanceTest{
	ShortName:   "HTTPRouteHeaderMatching",
	Description: "A single HTTPRoute with header matching for different backends",
	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)

		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)
			})
		}
	},
}
View Source
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",
	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.NamespacesMustBeAccepted(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...)

			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: "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))

			routeName := types.NamespacedName{Namespace: ns, Name: "no-intersecting-hosts"}
			parents := []v1beta1.RouteParentStatus{{
				ParentRef:      parentRefTo(gwNN),
				ControllerName: v1beta1.GatewayController(suite.ControllerName),
				Conditions: []metav1.Condition{
					{
						Type:   string(v1beta1.RouteConditionAccepted),
						Status: metav1.ConditionFalse,
						Reason: string(v1beta1.RouteReasonNoMatchingListenerHostname),
					},
				},
			}}

			kubernetes.HTTPRouteMustHaveParents(t, suite.Client, suite.TimeoutConfig, routeName, 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)
				})
			}
		})
	},
}
View Source
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.",
	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(v1beta1.RouteConditionResolvedRefs),
				Status: metav1.ConditionFalse,
				Reason: string(v1beta1.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},
			})
		})

	},
}
View Source
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.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(v1beta1.RouteConditionResolvedRefs),
				Status: metav1.ConditionFalse,
				Reason: string(v1beta1.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},
			})
		})

	},
}
View Source
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",
	Manifests:   []string{"tests/httproute-invalid-cross-namespace-parent-ref.yaml"},
	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
		routeName := types.NamespacedName{Name: "invalid-cross-namespace-parent-ref", Namespace: "gateway-conformance-web-backend"}
		gwName := types.NamespacedName{Name: "same-namespace", Namespace: "gateway-conformance-infra"}

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

		t.Run("Gateway should have 0 Routes attached", func(t *testing.T) {
			kubernetes.GatewayMustHaveZeroRoutes(t, suite.Client, suite.TimeoutConfig, gwName)
		})
	},
}
View Source
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",
	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(v1beta1.RouteConditionResolvedRefs),
				Status: metav1.ConditionFalse,
				Reason: string(v1beta1.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},
			})
		})

	},
}
View Source
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.SupportRouteDestinationPortMatching},
	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"}

		t.Run("HTTPRoute with no matching port in ParentRef has an Accepted Condition with status False and Reason NoMatchingParent", func(t *testing.T) {
			resolvedRefsCond := metav1.Condition{
				Type:   string(v1beta1.RouteConditionAccepted),
				Status: metav1.ConditionFalse,
				Reason: string(v1beta1.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)
		})
	},
}
View Source
var HTTPRouteListenerHostnameMatching = suite.ConformanceTest{
	ShortName:   "HTTPRouteListenerHostnameMatching",
	Description: "Multiple HTTP listeners with the same port and different hostnames, each with a different HTTPRoute",
	Manifests:   []string{"tests/httproute-listener-hostname-matching.yaml"},
	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
		ns := "gateway-conformance-infra"

		kubernetes.NamespacesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, []string{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"),
			types.NamespacedName{Namespace: ns, Name: "backend-v1"},
		)
		_ = kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN, "listener-2"),
			types.NamespacedName{Namespace: ns, Name: "backend-v2"},
		)
		gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"),
			types.NamespacedName{Namespace: ns, Name: "backend-v3"},
		)

		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)
			})
		}
	},
}
View Source
var HTTPRouteMatching = suite.ConformanceTest{
	ShortName:   "HTTPRouteMatching",
	Description: "A single HTTPRoute with path and header matching for different backends",
	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)

		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,
		}}

		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)
			})
		}
	},
}
View Source
var HTTPRouteMatchingAcrossRoutes = suite.ConformanceTest{
	ShortName:   "HTTPRouteMatchingAcrossRoutes",
	Description: "Two HTTPRoutes with path matching for different backends",
	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)

		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)
			})
		}
	},
}
View Source
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.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)

		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},
			},
		}

		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)
			})
		}
	},
}
View Source
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.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(v1beta1.RouteConditionResolvedRefs),
				Status: metav1.ConditionFalse,
				Reason: string(v1beta1.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",
			})
		})

	},
}
View Source
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.SupportHTTPRouteQueryParamMatching},
	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
		var (
			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)
		)

		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},
		}}

		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)
			})
		}
	},
}
View Source
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.SupportReferenceGrant},
	Manifests:   []string{"tests/httproute-reference-grant.yaml"},
	Test: func(t *testing.T, s *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, s.Client, s.TimeoutConfig, s.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)

		t.Run("Simple HTTP request should reach web-backend", 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:   "web-backend",
				Namespace: "gateway-conformance-web-backend",
			})
		})
	},
}
View Source
var HTTPRouteRequestHeaderModifier = suite.ConformanceTest{
	ShortName:   "HTTPRouteRequestHeaderModifier",
	Description: "An HTTPRoute has request header modifier filters applied correctly",
	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)

		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)
			})
		}
	},
}
View Source
var HTTPRouteRequestRedirect = suite.ConformanceTest{
	ShortName:   "HTTPRouteRequestRedirect",
	Description: "An HTTPRoute with hostname and statusCode redirect filters",
	Manifests:   []string{"tests/httproute-request-redirect.yaml"},
	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
		ns := "gateway-conformance-infra"
		routeNN := types.NamespacedName{Name: "request-redirect", 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:             "/hostname-redirect",
				UnfollowRedirect: true,
			},
			Response: http.Response{
				StatusCode: 302,
			},
			RedirectRequest: &roundtripper.RedirectRequest{
				Hostname: "example.org",
			},
			Backend:   "infra-backend-v1",
			Namespace: ns,
		}, {
			Request: http.Request{
				Path:             "/status-code-301",
				UnfollowRedirect: true,
			},
			Response: http.Response{
				StatusCode: 301,
			},
			Backend:   "infra-backend-v1",
			Namespace: ns,
		}, {
			Request: http.Request{
				Path:             "/host-and-status",
				UnfollowRedirect: true,
			},
			Response: http.Response{
				StatusCode: 301,
			},
			RedirectRequest: &roundtripper.RedirectRequest{
				Hostname: "example.org",
			},
			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)
			})
		}
	},
}
View Source
var HTTPRouteResponseHeaderModifier = suite.ConformanceTest{
	ShortName:   "HTTPRouteResponseHeaderModifier",
	Description: "An HTTPRoute has response header modifier filters applied correctly",
	Features:    []suite.SupportedFeature{suite.SupportHTTPResponseHeaderModification},
	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)

		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,
		}}

		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)
			})
		}
	},
}
View Source
var HTTPRouteSimpleSameNamespace = suite.ConformanceTest{
	ShortName:   "HTTPRouteSimpleSameNamespace",
	Description: "A single HTTPRoute in the gateway-conformance-infra namespace attaches to a Gateway in the same namespace",
	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)

		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",
			})
		})
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL