1
16
17 package kubernetes
18
19 import (
20 "fmt"
21 "testing"
22
23 "github.com/stretchr/testify/assert"
24 "github.com/stretchr/testify/require"
25 corev1 "k8s.io/api/core/v1"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/types"
28 "k8s.io/utils/ptr"
29
30 "sigs.k8s.io/gateway-api/apis/v1alpha2"
31 "sigs.k8s.io/gateway-api/apis/v1beta1"
32 )
33
34
35
36
37
38 func TestNewGatewayRef(t *testing.T) {
39 tests := []struct {
40 name string
41 nsn types.NamespacedName
42 listenerNames []string
43 }{
44 {
45 name: "verifying the contents of a GatewayRef with no provided listeners",
46 nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"},
47 },
48 {
49 name: "verifying the contents of a GatewayRef listeners with one listener provided",
50 nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"},
51 listenerNames: []string{"fake-listener-1"},
52 },
53 {
54 name: "verifying the contents of a GatewayRef listeners with multiple listeners provided",
55 nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"},
56 listenerNames: []string{
57 "fake-listener-1",
58 "fake-listener-2",
59 "fake-listener-3",
60 },
61 },
62 }
63
64 for i := 0; i < len(tests); i++ {
65 test := tests[i]
66 t.Run(test.name, func(t *testing.T) {
67 ref := NewGatewayRef(test.nsn, test.listenerNames...)
68 require.IsType(t, GatewayRef{}, ref)
69 if test.listenerNames == nil {
70 require.Len(t, ref.listenerNames, 1)
71 assert.Equal(t, "", string(*ref.listenerNames[0]))
72 } else {
73 require.Len(t, ref.listenerNames, len(test.listenerNames))
74 for i := 0; i < len(ref.listenerNames); i++ {
75 assert.Equal(t, test.listenerNames[i], string(*ref.listenerNames[i]))
76 }
77 }
78 assert.Equal(t, test.nsn, ref.NamespacedName)
79 })
80 }
81 }
82
83 func TestVerifyConditionsMatchGeneration(t *testing.T) {
84 tests := []struct {
85 name string
86 obj metav1.Object
87 conditions []metav1.Condition
88 expected error
89 }{
90 {},
91 {
92 name: "if no conditions are provided this technically passes verification",
93 },
94 {
95 name: "conditions where all match the generation pass verification",
96 obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}},
97 conditions: []metav1.Condition{
98 {Type: "FakeCondition1", ObservedGeneration: 20},
99 {Type: "FakeCondition2", ObservedGeneration: 20},
100 {Type: "FakeCondition3", ObservedGeneration: 20},
101 },
102 },
103 {
104 name: "conditions where one does not match the generation fail verification",
105 obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}},
106 conditions: []metav1.Condition{
107 {Type: "FakeCondition1", ObservedGeneration: 20},
108 {Type: "FakeCondition2", ObservedGeneration: 19},
109 {Type: "FakeCondition3", ObservedGeneration: 20},
110 },
111 expected: fmt.Errorf("expected observedGeneration to be updated to 20 for all conditions, only 2/3 were updated. stale conditions are: FakeCondition2 (generation 19)"),
112 },
113 {
114 name: "conditions where most do not match the generation fail verification",
115 obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}},
116 conditions: []metav1.Condition{
117 {Type: "FakeCondition1", ObservedGeneration: 18},
118 {Type: "FakeCondition2", ObservedGeneration: 18},
119 {Type: "FakeCondition3", ObservedGeneration: 14},
120 {Type: "FakeCondition4", ObservedGeneration: 20},
121 {Type: "FakeCondition5", ObservedGeneration: 16},
122 {Type: "FakeCondition6", ObservedGeneration: 15},
123 },
124 expected: fmt.Errorf("expected observedGeneration to be updated to 20 for all conditions, only 1/6 were updated. stale conditions are: FakeCondition1 (generation 18), FakeCondition2 (generation 18), FakeCondition3 (generation 14), FakeCondition5 (generation 16), FakeCondition6 (generation 15)"),
125 },
126 }
127
128 for i := 0; i < len(tests); i++ {
129 test := tests[i]
130 t.Run(test.name, func(t *testing.T) {
131 err := ConditionsHaveLatestObservedGeneration(test.obj, test.conditions)
132 assert.Equal(t, test.expected, err)
133 })
134 }
135 }
136
137
138
139
140
141 func Test_listenersMatch(t *testing.T) {
142 tests := []struct {
143 name string
144 expected []v1beta1.ListenerStatus
145 actual []v1beta1.ListenerStatus
146 want bool
147 }{
148 {
149 name: "listeners do not match if a different number of actual and expected listeners are provided",
150 expected: []v1beta1.ListenerStatus{
151 {
152 SupportedKinds: []v1beta1.RouteGroupKind{
153 {
154 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
155 Kind: v1beta1.Kind("HTTPRoute"),
156 },
157 },
158 },
159 {
160 SupportedKinds: []v1beta1.RouteGroupKind{
161 {
162 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
163 Kind: v1beta1.Kind("GRPCRoute"),
164 },
165 },
166 },
167 },
168 actual: []v1beta1.ListenerStatus{
169 {
170 SupportedKinds: []v1beta1.RouteGroupKind{
171 {
172 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
173 Kind: v1beta1.Kind("HTTPRoute"),
174 },
175 },
176 },
177 },
178 want: false,
179 },
180 {
181 name: "SupportedKinds: expected empty and actual is non empty",
182 expected: []v1beta1.ListenerStatus{
183 {
184 SupportedKinds: []v1beta1.RouteGroupKind{},
185 },
186 },
187 actual: []v1beta1.ListenerStatus{
188 {
189 SupportedKinds: []v1beta1.RouteGroupKind{
190 {
191 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
192 Kind: v1beta1.Kind("HTTPRoute"),
193 },
194 },
195 },
196 },
197 want: false,
198 },
199 {
200 name: "SupportedKinds: expected and actual are equal",
201 expected: []v1beta1.ListenerStatus{
202 {
203 SupportedKinds: []v1beta1.RouteGroupKind{
204 {
205 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
206 Kind: v1beta1.Kind("HTTPRoute"),
207 },
208 },
209 },
210 },
211 actual: []v1beta1.ListenerStatus{
212 {
213 SupportedKinds: []v1beta1.RouteGroupKind{
214 {
215 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
216 Kind: v1beta1.Kind("HTTPRoute"),
217 },
218 },
219 },
220 },
221 want: true,
222 },
223 {
224 name: "SupportedKinds: expected and actual are equal values, Group pointers are different",
225 expected: []v1beta1.ListenerStatus{
226 {
227 SupportedKinds: []v1beta1.RouteGroupKind{
228 {
229 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
230 Kind: v1beta1.Kind("HTTPRoute"),
231 },
232 },
233 },
234 },
235 actual: []v1beta1.ListenerStatus{
236 {
237 SupportedKinds: []v1beta1.RouteGroupKind{
238 {
239 Group: ptr.To[v1beta1.Group]("gateway.networking.k8s.io"),
240 Kind: v1beta1.Kind("HTTPRoute"),
241 },
242 },
243 },
244 },
245 want: true,
246 },
247 {
248 name: "SupportedKinds: expected kind not found in actual",
249 expected: []v1beta1.ListenerStatus{
250 {
251 SupportedKinds: []v1beta1.RouteGroupKind{
252 {
253 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
254 Kind: v1beta1.Kind("HTTPRoute"),
255 },
256 },
257 },
258 },
259 actual: []v1beta1.ListenerStatus{
260 {
261 SupportedKinds: []v1beta1.RouteGroupKind{
262 {
263 Group: (*v1beta1.Group)(&v1alpha2.GroupVersion.Group),
264 Kind: v1beta1.Kind("GRPCRoute"),
265 },
266 },
267 },
268 },
269 want: false,
270 },
271 {
272 name: "SupportedKinds: expected is a subset of actual",
273 expected: []v1beta1.ListenerStatus{
274 {
275 SupportedKinds: []v1beta1.RouteGroupKind{
276 {
277 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
278 Kind: v1beta1.Kind("HTTPRoute"),
279 },
280 },
281 },
282 },
283 actual: []v1beta1.ListenerStatus{
284 {
285 SupportedKinds: []v1beta1.RouteGroupKind{
286 {
287 Group: (*v1beta1.Group)(&v1alpha2.GroupVersion.Group),
288 Kind: v1beta1.Kind("GRPCRoute"),
289 },
290 {
291 Group: (*v1beta1.Group)(&v1beta1.GroupVersion.Group),
292 Kind: v1beta1.Kind("HTTPRoute"),
293 },
294 },
295 },
296 },
297 want: true,
298 },
299 {
300 name: "expected and actual can be in different orders",
301 expected: []v1beta1.ListenerStatus{
302 {Name: "listener-2"},
303 {Name: "listener-3"},
304 {Name: "listener-1"},
305 },
306 actual: []v1beta1.ListenerStatus{
307 {Name: "listener-1"},
308 {Name: "listener-2"},
309 {Name: "listener-3"},
310 },
311 want: true,
312 },
313 }
314
315 for _, test := range tests {
316 test := test
317 t.Run(test.name, func(t *testing.T) {
318 assert.Equal(t, test.want, listenersMatch(t, test.expected, test.actual))
319 })
320 }
321 }
322
View as plain text