1
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
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
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
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: "",
95 },
96 {
97 Type: string(v1.ListenerConditionResolvedRefs),
98 Status: metav1.ConditionTrue,
99 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: "",
115 },
116 {
117 Type: string(v1.ListenerConditionResolvedRefs),
118 Status: metav1.ConditionTrue,
119 Reason: "",
120 },
121 },
122 AttachedRoutes: 1,
123 },
124 }
125
126 kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
127
128
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
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
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
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: "",
183 },
184 {
185 Type: string(v1.ListenerConditionResolvedRefs),
186 Status: metav1.ConditionTrue,
187 Reason: "",
188 },
189 },
190 AttachedRoutes: 1,
191 },
192 }
193
194 kubernetes.GatewayStatusMustHaveListeners(t, s.Client, s.TimeoutConfig, gwNN, listeners)
195
196
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