...

Source file src/sigs.k8s.io/gateway-api/conformance/tests/httproute-hostname-intersection.go

Documentation: sigs.k8s.io/gateway-api/conformance/tests

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tests
    18  
    19  import (
    20  	"testing"
    21  
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	"k8s.io/apimachinery/pkg/types"
    24  
    25  	v1 "sigs.k8s.io/gateway-api/apis/v1"
    26  	"sigs.k8s.io/gateway-api/conformance/utils/http"
    27  	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
    28  	"sigs.k8s.io/gateway-api/conformance/utils/suite"
    29  )
    30  
    31  func init() {
    32  	ConformanceTests = append(ConformanceTests, HTTPRouteHostnameIntersection)
    33  }
    34  
    35  var HTTPRouteHostnameIntersection = suite.ConformanceTest{
    36  	ShortName:   "HTTPRouteHostnameIntersection",
    37  	Description: "HTTPRoutes should attach to listeners only if they have intersecting hostnames, and should accept requests only for the intersecting hostnames",
    38  	Features: []suite.SupportedFeature{
    39  		suite.SupportGateway,
    40  		suite.SupportHTTPRoute,
    41  	},
    42  	Manifests: []string{"tests/httproute-hostname-intersection.yaml"},
    43  	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
    44  		ns := "gateway-conformance-infra"
    45  		gwNN := types.NamespacedName{Name: "httproute-hostname-intersection", Namespace: ns}
    46  
    47  		// This test creates an additional Gateway in the gateway-conformance-infra
    48  		// namespace so we have to wait for it to be ready.
    49  		kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})
    50  
    51  		t.Run("HTTPRoutes that do intersect with listener hostnames", func(t *testing.T) {
    52  			routes := []types.NamespacedName{
    53  				{Namespace: ns, Name: "specific-host-matches-listener-specific-host"},
    54  				{Namespace: ns, Name: "specific-host-matches-listener-wildcard-host"},
    55  				{Namespace: ns, Name: "wildcard-host-matches-listener-specific-host"},
    56  				{Namespace: ns, Name: "wildcard-host-matches-listener-wildcard-host"},
    57  			}
    58  			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routes...)
    59  			for _, routeNN := range routes {
    60  				kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)
    61  			}
    62  
    63  			var testCases []http.ExpectedResponse
    64  
    65  			// Test cases for HTTPRoute "specific-host-matches-listener-specific-host".
    66  			testCases = append(testCases,
    67  				http.ExpectedResponse{
    68  					Request:   http.Request{Host: "very.specific.com", Path: "/s1"},
    69  					Backend:   "infra-backend-v1",
    70  					Namespace: ns,
    71  				},
    72  				// Port value within the Host header MUST not be considered while
    73  				// performing match against hostname.
    74  				http.ExpectedResponse{
    75  					Request:   http.Request{Host: "very.specific.com:1234", Path: "/s1"},
    76  					Backend:   "infra-backend-v1",
    77  					Namespace: ns,
    78  				},
    79  				http.ExpectedResponse{
    80  					Request:  http.Request{Host: "non.matching.com", Path: "/s1"},
    81  					Response: http.Response{StatusCode: 404},
    82  				},
    83  				http.ExpectedResponse{
    84  					Request:  http.Request{Host: "foo.nonmatchingwildcard.io", Path: "/s1"},
    85  					Response: http.Response{StatusCode: 404},
    86  				},
    87  				http.ExpectedResponse{
    88  					Request:  http.Request{Host: "foo.wildcard.io", Path: "/s1"},
    89  					Response: http.Response{StatusCode: 404},
    90  				},
    91  				http.ExpectedResponse{
    92  					Request:  http.Request{Host: "very.specific.com", Path: "/non-matching-prefix"},
    93  					Response: http.Response{StatusCode: 404},
    94  				},
    95  			)
    96  
    97  			//  Test cases for HTTPRoute "specific-host-matches-listener-wildcard-host".
    98  			testCases = append(testCases,
    99  				http.ExpectedResponse{
   100  					Request:   http.Request{Host: "foo.wildcard.io", Path: "/s2"},
   101  					Backend:   "infra-backend-v2",
   102  					Namespace: ns,
   103  				},
   104  				http.ExpectedResponse{
   105  					Request:   http.Request{Host: "bar.wildcard.io", Path: "/s2"},
   106  					Backend:   "infra-backend-v2",
   107  					Namespace: ns,
   108  				},
   109  				http.ExpectedResponse{
   110  					Request:   http.Request{Host: "foo.bar.wildcard.io", Path: "/s2"},
   111  					Backend:   "infra-backend-v2",
   112  					Namespace: ns,
   113  				},
   114  				http.ExpectedResponse{
   115  					Request:  http.Request{Host: "non.matching.com", Path: "/s2"},
   116  					Response: http.Response{StatusCode: 404},
   117  				},
   118  				http.ExpectedResponse{
   119  					Request:  http.Request{Host: "wildcard.io", Path: "/s2"},
   120  					Response: http.Response{StatusCode: 404},
   121  				},
   122  
   123  				http.ExpectedResponse{
   124  					Request:  http.Request{Host: "very.specific.com", Path: "/s2"},
   125  					Response: http.Response{StatusCode: 404},
   126  				},
   127  				http.ExpectedResponse{
   128  					Request:  http.Request{Host: "foo.wildcard.io", Path: "/non-matching-prefix"},
   129  					Response: http.Response{StatusCode: 404},
   130  				},
   131  			)
   132  
   133  			//  Test cases for HTTPRoute "wildcard-host-matches-listener-specific-host".
   134  			testCases = append(testCases,
   135  				http.ExpectedResponse{
   136  					Request:   http.Request{Host: "very.specific.com", Path: "/s3"},
   137  					Backend:   "infra-backend-v3",
   138  					Namespace: ns,
   139  				},
   140  				http.ExpectedResponse{
   141  					Request:  http.Request{Host: "non.matching.com", Path: "/s3"},
   142  					Response: http.Response{StatusCode: 404},
   143  				},
   144  				http.ExpectedResponse{
   145  					Request:  http.Request{Host: "foo.specific.com", Path: "/s3"},
   146  					Response: http.Response{StatusCode: 404},
   147  				},
   148  				http.ExpectedResponse{
   149  					Request:  http.Request{Host: "foo.wildcard.io", Path: "/s3"},
   150  					Response: http.Response{StatusCode: 404},
   151  				},
   152  				http.ExpectedResponse{
   153  					Request:  http.Request{Host: "very.specific.com", Path: "/non-matching-prefix"},
   154  					Response: http.Response{StatusCode: 404},
   155  				},
   156  			)
   157  
   158  			//  Test cases for HTTPRoute "wildcard-host-matches-listener-wildcard-host".
   159  			testCases = append(testCases,
   160  				http.ExpectedResponse{
   161  					Request:   http.Request{Host: "foo.anotherwildcard.io", Path: "/s4"},
   162  					Backend:   "infra-backend-v1",
   163  					Namespace: ns,
   164  				},
   165  				http.ExpectedResponse{
   166  					Request:   http.Request{Host: "bar.anotherwildcard.io", Path: "/s4"},
   167  					Backend:   "infra-backend-v1",
   168  					Namespace: ns,
   169  				},
   170  				http.ExpectedResponse{
   171  					Request:   http.Request{Host: "foo.bar.anotherwildcard.io", Path: "/s4"},
   172  					Backend:   "infra-backend-v1",
   173  					Namespace: ns,
   174  				},
   175  				http.ExpectedResponse{
   176  					Request:  http.Request{Host: "anotherwildcard.io", Path: "/s4"},
   177  					Response: http.Response{StatusCode: 404},
   178  				},
   179  
   180  				http.ExpectedResponse{
   181  					Request:  http.Request{Host: "foo.wildcard.io", Path: "/s4"},
   182  					Response: http.Response{StatusCode: 404},
   183  				},
   184  				http.ExpectedResponse{
   185  					Request:  http.Request{Host: "very.specific.com", Path: "/s4"},
   186  					Response: http.Response{StatusCode: 404},
   187  				},
   188  				http.ExpectedResponse{
   189  					Request:  http.Request{Host: "foo.anotherwildcard.io", Path: "/non-matching-prefix"},
   190  					Response: http.Response{StatusCode: 404},
   191  				},
   192  			)
   193  
   194  			for i := range testCases {
   195  				// Declare tc here to avoid loop variable
   196  				// reuse issues across parallel tests.
   197  				tc := testCases[i]
   198  				t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
   199  					t.Parallel()
   200  					http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
   201  				})
   202  			}
   203  		})
   204  
   205  		t.Run("HTTPRoutes that do not intersect with listener hostnames", func(t *testing.T) {
   206  			gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN))
   207  			routeNN := types.NamespacedName{Namespace: ns, Name: "no-intersecting-hosts"}
   208  
   209  			parents := []v1.RouteParentStatus{{
   210  				ParentRef:      parentRefTo(gwNN),
   211  				ControllerName: v1.GatewayController(suite.ControllerName),
   212  				Conditions: []metav1.Condition{
   213  					{
   214  						Type:   string(v1.RouteConditionAccepted),
   215  						Status: metav1.ConditionFalse,
   216  						Reason: string(v1.RouteReasonNoMatchingListenerHostname),
   217  					},
   218  				},
   219  			}}
   220  
   221  			kubernetes.HTTPRouteMustHaveParents(t, suite.Client, suite.TimeoutConfig, routeNN, parents, true)
   222  
   223  			testCases := []http.ExpectedResponse{
   224  				{
   225  					Request:  http.Request{Host: "specific.but.wrong.com", Path: "/s5"},
   226  					Response: http.Response{StatusCode: 404},
   227  				},
   228  				{
   229  					Request:  http.Request{Host: "wildcard.io", Path: "/s5"},
   230  					Response: http.Response{StatusCode: 404},
   231  				},
   232  			}
   233  
   234  			for i := range testCases {
   235  				// Declare tc here to avoid loop variable
   236  				// reuse issues across parallel tests.
   237  				tc := testCases[i]
   238  				t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
   239  					t.Parallel()
   240  					http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
   241  				})
   242  			}
   243  		})
   244  	},
   245  }
   246  
   247  func parentRefTo(gateway types.NamespacedName) v1.ParentReference {
   248  	var (
   249  		group     = v1.Group(v1.GroupName)
   250  		kind      = v1.Kind("Gateway")
   251  		namespace = v1.Namespace(gateway.Namespace)
   252  		name      = v1.ObjectName(gateway.Name)
   253  	)
   254  
   255  	return v1.ParentReference{
   256  		Group:     &group,
   257  		Kind:      &kind,
   258  		Namespace: &namespace,
   259  		Name:      name,
   260  	}
   261  }
   262  

View as plain text