...

Source file src/sigs.k8s.io/gateway-api/conformance/tests/gateway-modify-listeners.go

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

     1  /*
     2  Copyright 2023 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  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/stretchr/testify/require"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/types"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  
    29  	v1 "sigs.k8s.io/gateway-api/apis/v1"
    30  	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
    31  	"sigs.k8s.io/gateway-api/conformance/utils/suite"
    32  )
    33  
    34  func init() {
    35  	ConformanceTests = append(ConformanceTests, GatewayModifyListeners)
    36  }
    37  
    38  var GatewayModifyListeners = suite.ConformanceTest{
    39  	ShortName:   "GatewayModifyListeners",
    40  	Description: "A Gateway in the gateway-conformance-infra namespace should handle adding and removing listeners.",
    41  	Features: []suite.SupportedFeature{
    42  		suite.SupportGateway,
    43  	},
    44  	Manifests: []string{"tests/gateway-modify-listeners.yaml"},
    45  	Test: func(t *testing.T, s *suite.ConformanceTestSuite) {
    46  		t.Run("should be able to add a listener that then becomes available for routing traffic", func(t *testing.T) {
    47  			gwNN := types.NamespacedName{Name: "gateway-add-listener", Namespace: "gateway-conformance-infra"}
    48  			ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    49  			defer cancel()
    50  
    51  			namespaces := []string{"gateway-conformance-infra"}
    52  			kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)
    53  
    54  			// verify that the implementation is tracking the most recent resource changes
    55  			kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)
    56  
    57  			original := &v1.Gateway{}
    58  			err := s.Client.Get(ctx, gwNN, original)
    59  			require.NoErrorf(t, err, "error getting Gateway: %v", err)
    60  
    61  			all := v1.NamespacesFromAll
    62  
    63  			mutate := original.DeepCopy()
    64  
    65  			// add a new listener to the Gateway spec
    66  			hostname := v1.Hostname("data.test.com")
    67  			mutate.Spec.Listeners = append(mutate.Spec.Listeners, v1.Listener{
    68  				Name:     "http",
    69  				Port:     80,
    70  				Protocol: v1.HTTPProtocolType,
    71  				Hostname: &hostname,
    72  				AllowedRoutes: &v1.AllowedRoutes{
    73  					Namespaces: &v1.RouteNamespaces{From: &all},
    74  				},
    75  			})
    76  
    77  			err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
    78  			require.NoErrorf(t, err, "error patching the Gateway: %v", err)
    79  
    80  			// Ensure the generation and observedGeneration sync up
    81  			kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)
    82  
    83  			listeners := []v1.ListenerStatus{
    84  				{
    85  					Name: v1.SectionName("https"),
    86  					SupportedKinds: []v1.RouteGroupKind{{
    87  						Group: (*v1.Group)(&v1.GroupVersion.Group),
    88  						Kind:  v1.Kind("HTTPRoute"),
    89  					}},
    90  					Conditions: []metav1.Condition{
    91  						{
    92  							Type:   string(v1.ListenerConditionAccepted),
    93  							Status: metav1.ConditionTrue,
    94  							Reason: "", // any reason
    95  						},
    96  						{
    97  							Type:   string(v1.ListenerConditionResolvedRefs),
    98  							Status: metav1.ConditionTrue,
    99  							Reason: "", // any reason
   100  						},
   101  					},
   102  					AttachedRoutes: 1,
   103  				},
   104  				{
   105  					Name: v1.SectionName("http"),
   106  					SupportedKinds: []v1.RouteGroupKind{{
   107  						Group: (*v1.Group)(&v1.GroupVersion.Group),
   108  						Kind:  v1.Kind("HTTPRoute"),
   109  					}},
   110  					Conditions: []metav1.Condition{
   111  						{
   112  							Type:   string(v1.ListenerConditionAccepted),
   113  							Status: metav1.ConditionTrue,
   114  							Reason: "", // any reason
   115  						},
   116  						{
   117  							Type:   string(v1.ListenerConditionResolvedRefs),
   118  							Status: metav1.ConditionTrue,
   119  							Reason: "", // any reason
   120  						},
   121  					},
   122  					AttachedRoutes: 1,
   123  				},
   124  			}
   125  
   126  			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
   127  
   128  			// verify that the implementation continues to keep up to date with the resource changes we've been making
   129  			kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)
   130  
   131  			updated := &v1.Gateway{}
   132  			err = s.Client.Get(ctx, gwNN, updated)
   133  			require.NoErrorf(t, err, "error getting Gateway: %v", err)
   134  
   135  			require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
   136  		})
   137  
   138  		t.Run("should be able to remove listeners, which would then stop routing the relevant traffic", func(t *testing.T) {
   139  			gwNN := types.NamespacedName{Name: "gateway-remove-listener", Namespace: "gateway-conformance-infra"}
   140  			ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
   141  			defer cancel()
   142  
   143  			namespaces := []string{"gateway-conformance-infra"}
   144  			kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)
   145  
   146  			// verify that the implementation is tracking the most recent resource changes
   147  			kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)
   148  
   149  			original := &v1.Gateway{}
   150  			err := s.Client.Get(ctx, gwNN, original)
   151  			require.NoErrorf(t, err, "error getting Gateway: %v", err)
   152  
   153  			mutate := original.DeepCopy()
   154  			require.Equalf(t, 2, len(mutate.Spec.Listeners), "the gateway must have 2 listeners")
   155  
   156  			// remove the "https" Gateway listener, leaving only the "http" listener
   157  			var newListeners []v1.Listener
   158  			for _, listener := range mutate.Spec.Listeners {
   159  				if listener.Name == "http" {
   160  					newListeners = append(newListeners, listener)
   161  				}
   162  			}
   163  			mutate.Spec.Listeners = newListeners
   164  
   165  			err = s.Client.Patch(ctx, mutate, client.MergeFrom(original))
   166  			require.NoErrorf(t, err, "error patching the Gateway: %v", err)
   167  
   168  			// Ensure the generation and observedGeneration sync up
   169  			kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, namespaces)
   170  
   171  			listeners := []v1.ListenerStatus{
   172  				{
   173  					Name: v1.SectionName("http"),
   174  					SupportedKinds: []v1.RouteGroupKind{{
   175  						Group: (*v1.Group)(&v1.GroupVersion.Group),
   176  						Kind:  v1.Kind("HTTPRoute"),
   177  					}},
   178  					Conditions: []metav1.Condition{
   179  						{
   180  							Type:   string(v1.ListenerConditionAccepted),
   181  							Status: metav1.ConditionTrue,
   182  							Reason: "", // any reason
   183  						},
   184  						{
   185  							Type:   string(v1.ListenerConditionResolvedRefs),
   186  							Status: metav1.ConditionTrue,
   187  							Reason: "", // any reason
   188  						},
   189  					},
   190  					AttachedRoutes: 1,
   191  				},
   192  			}
   193  
   194  			kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
   195  
   196  			// verify that the implementation continues to keep up to date with the resource changes we've been making
   197  			kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN)
   198  
   199  			updated := &v1.Gateway{}
   200  			err = s.Client.Get(ctx, gwNN, updated)
   201  			require.NoErrorf(t, err, "error getting Gateway: %v", err)
   202  
   203  			require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update")
   204  		})
   205  	},
   206  }
   207  

View as plain text