1
2
3
4 package e2e
5
6 import (
7 "context"
8 "fmt"
9
10 . "github.com/onsi/ginkgo/v2"
11 . "github.com/onsi/gomega"
12 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
13 "sigs.k8s.io/cli-utils/pkg/apply"
14 "sigs.k8s.io/cli-utils/pkg/apply/event"
15 "sigs.k8s.io/cli-utils/pkg/inventory"
16 "sigs.k8s.io/cli-utils/pkg/object"
17 "sigs.k8s.io/cli-utils/pkg/testutil"
18 "sigs.k8s.io/cli-utils/test/e2e/e2eutil"
19 "sigs.k8s.io/cli-utils/test/e2e/invconfig"
20 "sigs.k8s.io/controller-runtime/pkg/client"
21 )
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 func mutationTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
38 By("apply resources in order with substitutions based on apply-time-mutation annotation")
39 applier := invConfig.ApplierFactoryFunc()
40
41 inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
42
43 fields := struct{ Namespace string }{Namespace: namespaceName}
44 podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
45 podBObj := e2eutil.TemplateToUnstructured(podBTemplate, fields)
46
47
48
49 resources := []*unstructured.Unstructured{
50 podAObj,
51 podBObj,
52 }
53
54 applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
55 EmitStatusEvents: false,
56 }))
57
58 expEvents := []testutil.ExpEvent{
59 {
60
61 EventType: event.InitType,
62 InitEvent: &testutil.ExpInitEvent{},
63 },
64 {
65
66 EventType: event.ActionGroupType,
67 ActionGroupEvent: &testutil.ExpActionGroupEvent{
68 Action: event.InventoryAction,
69 GroupName: "inventory-add-0",
70 Type: event.Started,
71 },
72 },
73 {
74
75 EventType: event.ActionGroupType,
76 ActionGroupEvent: &testutil.ExpActionGroupEvent{
77 Action: event.InventoryAction,
78 GroupName: "inventory-add-0",
79 Type: event.Finished,
80 },
81 },
82 {
83
84 EventType: event.ActionGroupType,
85 ActionGroupEvent: &testutil.ExpActionGroupEvent{
86 Action: event.ApplyAction,
87 GroupName: "apply-0",
88 Type: event.Started,
89 },
90 },
91 {
92
93 EventType: event.ApplyType,
94 ApplyEvent: &testutil.ExpApplyEvent{
95 GroupName: "apply-0",
96 Status: event.ApplySuccessful,
97 Identifier: object.UnstructuredToObjMetadata(podBObj),
98 Error: nil,
99 },
100 },
101 {
102
103 EventType: event.ActionGroupType,
104 ActionGroupEvent: &testutil.ExpActionGroupEvent{
105 Action: event.ApplyAction,
106 GroupName: "apply-0",
107 Type: event.Finished,
108 },
109 },
110 {
111
112 EventType: event.ActionGroupType,
113 ActionGroupEvent: &testutil.ExpActionGroupEvent{
114 Action: event.WaitAction,
115 GroupName: "wait-0",
116 Type: event.Started,
117 },
118 },
119 {
120
121 EventType: event.WaitType,
122 WaitEvent: &testutil.ExpWaitEvent{
123 GroupName: "wait-0",
124 Status: event.ReconcilePending,
125 Identifier: object.UnstructuredToObjMetadata(podBObj),
126 },
127 },
128 {
129
130 EventType: event.WaitType,
131 WaitEvent: &testutil.ExpWaitEvent{
132 GroupName: "wait-0",
133 Status: event.ReconcileSuccessful,
134 Identifier: object.UnstructuredToObjMetadata(podBObj),
135 },
136 },
137 {
138
139 EventType: event.ActionGroupType,
140 ActionGroupEvent: &testutil.ExpActionGroupEvent{
141 Action: event.WaitAction,
142 GroupName: "wait-0",
143 Type: event.Finished,
144 },
145 },
146 {
147
148 EventType: event.ActionGroupType,
149 ActionGroupEvent: &testutil.ExpActionGroupEvent{
150 Action: event.ApplyAction,
151 GroupName: "apply-1",
152 Type: event.Started,
153 },
154 },
155 {
156
157 EventType: event.ApplyType,
158 ApplyEvent: &testutil.ExpApplyEvent{
159 GroupName: "apply-1",
160 Status: event.ApplySuccessful,
161 Identifier: object.UnstructuredToObjMetadata(podAObj),
162 Error: nil,
163 },
164 },
165 {
166
167 EventType: event.ActionGroupType,
168 ActionGroupEvent: &testutil.ExpActionGroupEvent{
169 Action: event.ApplyAction,
170 GroupName: "apply-1",
171 Type: event.Finished,
172 },
173 },
174 {
175
176 EventType: event.ActionGroupType,
177 ActionGroupEvent: &testutil.ExpActionGroupEvent{
178 Action: event.WaitAction,
179 GroupName: "wait-1",
180 Type: event.Started,
181 },
182 },
183 {
184
185 EventType: event.WaitType,
186 WaitEvent: &testutil.ExpWaitEvent{
187 GroupName: "wait-1",
188 Status: event.ReconcilePending,
189 Identifier: object.UnstructuredToObjMetadata(podAObj),
190 },
191 },
192 {
193
194 EventType: event.WaitType,
195 WaitEvent: &testutil.ExpWaitEvent{
196 GroupName: "wait-1",
197 Status: event.ReconcileSuccessful,
198 Identifier: object.UnstructuredToObjMetadata(podAObj),
199 },
200 },
201 {
202
203 EventType: event.ActionGroupType,
204 ActionGroupEvent: &testutil.ExpActionGroupEvent{
205 Action: event.WaitAction,
206 GroupName: "wait-1",
207 Type: event.Finished,
208 },
209 },
210 {
211
212 EventType: event.ActionGroupType,
213 ActionGroupEvent: &testutil.ExpActionGroupEvent{
214 Action: event.InventoryAction,
215 GroupName: "inventory-set-0",
216 Type: event.Started,
217 },
218 },
219 {
220
221 EventType: event.ActionGroupType,
222 ActionGroupEvent: &testutil.ExpActionGroupEvent{
223 Action: event.InventoryAction,
224 GroupName: "inventory-set-0",
225 Type: event.Finished,
226 },
227 },
228 }
229 receivedEvents := testutil.EventsToExpEvents(applierEvents)
230
231 expEvents, receivedEvents = e2eutil.FilterOptionalEvents(expEvents, receivedEvents)
232
233 Expect(receivedEvents).To(testutil.Equal(expEvents))
234
235 By("verify podB is created and ready")
236 result := e2eutil.AssertUnstructuredExists(ctx, c, podBObj)
237
238 podIP, found, err := object.NestedField(result.Object, "status", "podIP")
239 Expect(err).NotTo(HaveOccurred())
240 Expect(found).To(BeTrue())
241 Expect(podIP).NotTo(BeEmpty())
242
243 containerPort, found, err := object.NestedField(result.Object, "spec", "containers", 0, "ports", 0, "containerPort")
244 Expect(err).NotTo(HaveOccurred())
245 Expect(found).To(BeTrue())
246 Expect(containerPort).To(Equal(int64(80)))
247
248 host := fmt.Sprintf("%s:%d", podIP, containerPort)
249
250 By("verify podA is mutated, created, and ready")
251 result = e2eutil.AssertUnstructuredExists(ctx, c, podAObj)
252
253 podIP, found, err = object.NestedField(result.Object, "status", "podIP")
254 Expect(err).NotTo(HaveOccurred())
255 Expect(found).To(BeTrue())
256 Expect(podIP).NotTo(BeEmpty())
257
258 envValue, found, err := object.NestedField(result.Object, "spec", "containers", 0, "env", 0, "value")
259 Expect(err).NotTo(HaveOccurred())
260 Expect(found).To(BeTrue())
261 Expect(envValue).To(Equal(host))
262
263 By("destroy resources in opposite order")
264 destroyer := invConfig.DestroyerFactoryFunc()
265 options := apply.DestroyerOptions{InventoryPolicy: inventory.PolicyAdoptIfNoInventory}
266 destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, options))
267
268 expEvents = []testutil.ExpEvent{
269 {
270
271 EventType: event.InitType,
272 InitEvent: &testutil.ExpInitEvent{},
273 },
274 {
275
276 EventType: event.ActionGroupType,
277 ActionGroupEvent: &testutil.ExpActionGroupEvent{
278 Action: event.DeleteAction,
279 GroupName: "prune-0",
280 Type: event.Started,
281 },
282 },
283 {
284
285 EventType: event.DeleteType,
286 DeleteEvent: &testutil.ExpDeleteEvent{
287 GroupName: "prune-0",
288 Status: event.DeleteSuccessful,
289 Identifier: object.UnstructuredToObjMetadata(podAObj),
290 Error: nil,
291 },
292 },
293 {
294
295 EventType: event.ActionGroupType,
296 ActionGroupEvent: &testutil.ExpActionGroupEvent{
297 Action: event.DeleteAction,
298 GroupName: "prune-0",
299 Type: event.Finished,
300 },
301 },
302 {
303
304 EventType: event.ActionGroupType,
305 ActionGroupEvent: &testutil.ExpActionGroupEvent{
306 Action: event.WaitAction,
307 GroupName: "wait-0",
308 Type: event.Started,
309 },
310 },
311 {
312
313 EventType: event.WaitType,
314 WaitEvent: &testutil.ExpWaitEvent{
315 GroupName: "wait-0",
316 Status: event.ReconcilePending,
317 Identifier: object.UnstructuredToObjMetadata(podAObj),
318 },
319 },
320 {
321
322 EventType: event.WaitType,
323 WaitEvent: &testutil.ExpWaitEvent{
324 GroupName: "wait-0",
325 Status: event.ReconcileSuccessful,
326 Identifier: object.UnstructuredToObjMetadata(podAObj),
327 },
328 },
329 {
330
331 EventType: event.ActionGroupType,
332 ActionGroupEvent: &testutil.ExpActionGroupEvent{
333 Action: event.WaitAction,
334 GroupName: "wait-0",
335 Type: event.Finished,
336 },
337 },
338 {
339
340 EventType: event.ActionGroupType,
341 ActionGroupEvent: &testutil.ExpActionGroupEvent{
342 Action: event.DeleteAction,
343 GroupName: "prune-1",
344 Type: event.Started,
345 },
346 },
347 {
348
349 EventType: event.DeleteType,
350 DeleteEvent: &testutil.ExpDeleteEvent{
351 GroupName: "prune-1",
352 Status: event.DeleteSuccessful,
353 Identifier: object.UnstructuredToObjMetadata(podBObj),
354 Error: nil,
355 },
356 },
357 {
358
359 EventType: event.ActionGroupType,
360 ActionGroupEvent: &testutil.ExpActionGroupEvent{
361 Action: event.DeleteAction,
362 GroupName: "prune-1",
363 Type: event.Finished,
364 },
365 },
366 {
367
368 EventType: event.ActionGroupType,
369 ActionGroupEvent: &testutil.ExpActionGroupEvent{
370 Action: event.WaitAction,
371 GroupName: "wait-1",
372 Type: event.Started,
373 },
374 },
375 {
376
377 EventType: event.WaitType,
378 WaitEvent: &testutil.ExpWaitEvent{
379 GroupName: "wait-1",
380 Status: event.ReconcilePending,
381 Identifier: object.UnstructuredToObjMetadata(podBObj),
382 },
383 },
384 {
385
386 EventType: event.WaitType,
387 WaitEvent: &testutil.ExpWaitEvent{
388 GroupName: "wait-1",
389 Status: event.ReconcileSuccessful,
390 Identifier: object.UnstructuredToObjMetadata(podBObj),
391 },
392 },
393 {
394
395 EventType: event.ActionGroupType,
396 ActionGroupEvent: &testutil.ExpActionGroupEvent{
397 Action: event.WaitAction,
398 GroupName: "wait-1",
399 Type: event.Finished,
400 },
401 },
402 {
403
404 EventType: event.ActionGroupType,
405 ActionGroupEvent: &testutil.ExpActionGroupEvent{
406 Action: event.InventoryAction,
407 GroupName: "delete-inventory-0",
408 Type: event.Started,
409 },
410 },
411 {
412
413 EventType: event.ActionGroupType,
414 ActionGroupEvent: &testutil.ExpActionGroupEvent{
415 Action: event.InventoryAction,
416 GroupName: "delete-inventory-0",
417 Type: event.Finished,
418 },
419 },
420 }
421 receivedEvents = testutil.EventsToExpEvents(destroyerEvents)
422
423 expEvents, receivedEvents = e2eutil.FilterOptionalEvents(expEvents, receivedEvents)
424
425 Expect(receivedEvents).To(testutil.Equal(expEvents))
426
427 By("verify podB deleted")
428 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
429
430 By("verify podA deleted")
431 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
432 }
433
View as plain text