diff --git a/conformance/tests/httproute-method-matching.go b/conformance/tests/httproute-method-matching.go index b1f226a1c0..704c6528fd 100644 --- a/conformance/tests/httproute-method-matching.go +++ b/conformance/tests/httproute-method-matching.go @@ -61,6 +61,68 @@ var HTTPRouteMethodMatching = suite.ConformanceTest{ }, } + // Combinations of method matching with other core matches. + 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, + }, + }...) + + // Ensure that combinations of matches which are OR'd together match + // even if only one of them is used in the request. + 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, + }, + }...) + + // Ensure that combinations of match types which are ANDed together do not match + // when only a subset of match types is used in the request. + 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}, + }, + }...) + + // For requests that satisfy multiple matches, ensure precedence order + // defined by the Gateway API spec is maintained. + 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-v3", + Namespace: ns, + }, + }...) + for i := range testCases { // Declare tc here to avoid loop variable // reuse issues across parallel tests. diff --git a/conformance/tests/httproute-method-matching.yaml b/conformance/tests/httproute-method-matching.yaml index b75d60439e..5396f084ee 100644 --- a/conformance/tests/httproute-method-matching.yaml +++ b/conformance/tests/httproute-method-matching.yaml @@ -17,3 +17,70 @@ spec: backendRefs: - name: infra-backend-v2 port: 8080 + + # Combinations with core match types. + - matches: + - path: + type: PathPrefix + value: /path1 + method: GET + backendRefs: + - name: infra-backend-v1 + port: 8080 + - matches: + - headers: + - name: version + value: one + method: PUT + backendRefs: + - name: infra-backend-v2 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /path2 + headers: + - name: version + value: two + method: POST + backendRefs: + - name: infra-backend-v3 + port: 8080 + + # Match of the form (cond1 AND cond2) OR (cond3 AND cond4 AND cond5) + - matches: + - path: + type: PathPrefix + value: /path3 + method: PATCH + - path: + type: PathPrefix + value: /path4 + headers: + - name: version + value: three + method: DELETE + backendRefs: + - name: infra-backend-v1 + port: 8080 + + # Matches for checking precedence. + - matches: + - path: + type: PathPrefix + value: /path5 + backendRefs: + - name: infra-backend-v1 + port: 8080 + - matches: + - method: PATCH + backendRefs: + - name: infra-backend-v2 + port: 8080 + - matches: + - headers: + - name: version + value: four + backendRefs: + - name: infra-backend-v3 + port: 8080 diff --git a/conformance/tests/httproute-query-param-matching.go b/conformance/tests/httproute-query-param-matching.go index 22f6bb5759..79c76f7aad 100644 --- a/conformance/tests/httproute-query-param-matching.go +++ b/conformance/tests/httproute-query-param-matching.go @@ -84,6 +84,68 @@ var HTTPRouteQueryParamMatching = suite.ConformanceTest{ Response: http.Response{StatusCode: 404}, }} + // Combinations of query param matching with other core matches. + 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, + }, + }...) + + // Ensure that combinations of matches which are OR'd together match + // even if only one of them is used in the request. + 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, + }, + }...) + + // Ensure that combinations of match types which are ANDed together do not match + // when only a subset of match types is used in the request. + 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}, + }, + }...) + + // For requests that satisfy multiple matches, ensure precedence order + // defined by the Gateway API spec is maintained. + 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) { diff --git a/conformance/tests/httproute-query-param-matching.yaml b/conformance/tests/httproute-query-param-matching.yaml index c4ddfe206c..2b9db8141c 100644 --- a/conformance/tests/httproute-query-param-matching.yaml +++ b/conformance/tests/httproute-query-param-matching.yaml @@ -33,3 +33,82 @@ spec: backendRefs: - name: infra-backend-v3 port: 8080 + + # Combinations with core match types. + - matches: + - path: + type: PathPrefix + value: /path1 + queryParams: + - name: animal + value: whale + backendRefs: + - name: infra-backend-v1 + port: 8080 + - matches: + - headers: + - name: version + value: one + queryParams: + - name: animal + value: whale + backendRefs: + - name: infra-backend-v2 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /path2 + headers: + - name: version + value: two + queryParams: + - name: animal + value: whale + backendRefs: + - name: infra-backend-v3 + port: 8080 + + # Match of the form (cond1 AND cond2) OR (cond3 AND cond4 AND cond5) + - matches: + - path: + type: PathPrefix + value: /path3 + queryParams: + - name: animal + value: shark + - path: + type: PathPrefix + value: /path4 + headers: + - name: version + value: three + queryParams: + - name: animal + value: kraken + backendRefs: + - name: infra-backend-v1 + port: 8080 + + # Matches for checking precedence. + - matches: + - path: + type: PathPrefix + value: /path5 + backendRefs: + - name: infra-backend-v1 + port: 8080 + - matches: + - queryParams: + - name: animal + value: hydra + backendRefs: + - name: infra-backend-v2 + port: 8080 + - matches: + - headers: + - name: version + value: four + backendRefs: + - name: infra-backend-v3 + port: 8080 diff --git a/hack/verify-yamllint.sh b/hack/verify-yamllint.sh old mode 100644 new mode 100755