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 "k8s.io/apimachinery/pkg/runtime/schema"
14 "k8s.io/apimachinery/pkg/util/validation/field"
15 "sigs.k8s.io/cli-utils/pkg/apply"
16 "sigs.k8s.io/cli-utils/pkg/apply/event"
17 "sigs.k8s.io/cli-utils/pkg/inventory"
18 "sigs.k8s.io/cli-utils/pkg/object"
19 "sigs.k8s.io/cli-utils/pkg/object/dependson"
20 "sigs.k8s.io/cli-utils/pkg/object/graph"
21 "sigs.k8s.io/cli-utils/pkg/object/mutation"
22 "sigs.k8s.io/cli-utils/pkg/object/validation"
23 "sigs.k8s.io/cli-utils/pkg/testutil"
24 "sigs.k8s.io/cli-utils/test/e2e/e2eutil"
25 "sigs.k8s.io/cli-utils/test/e2e/invconfig"
26 "sigs.k8s.io/controller-runtime/pkg/client"
27 )
28
29 func skipInvalidTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
30 By("apply valid objects and skip invalid objects")
31 applier := invConfig.ApplierFactoryFunc()
32
33 inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
34
35 fields := struct{ Namespace string }{Namespace: namespaceName}
36
37 pod1Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName)
38
39 deployment1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(deployment1), namespaceName),
40 fmt.Sprintf("/namespaces/%s/Pod/%s", namespaceName, pod1Obj.GetName()))
41
42 pod3Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod3), namespaceName),
43 fmt.Sprintf("/namespaces/%s/Pod/pod0", namespaceName))
44
45 podAObj := e2eutil.TemplateToUnstructured(podATemplate, fields)
46
47 podBObj := e2eutil.TemplateToUnstructured(invalidMutationPodBTemplate, fields)
48
49 invalidPodObj := e2eutil.TemplateToUnstructured(invalidPodTemplate, fields)
50
51 resources := []*unstructured.Unstructured{
52 pod1Obj,
53 deployment1Obj,
54 pod3Obj,
55 podAObj,
56 podBObj,
57 invalidPodObj,
58 }
59
60 applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
61 EmitStatusEvents: false,
62 ValidationPolicy: validation.SkipInvalid,
63 }))
64
65 expEvents := []testutil.ExpEvent{
66 {
67
68 EventType: event.ValidationType,
69 ValidationEvent: &testutil.ExpValidationEvent{
70 Identifiers: object.ObjMetadataSet{
71 object.UnstructuredToObjMetadata(invalidPodObj),
72 },
73 Error: testutil.EqualError(
74 validation.NewError(
75 field.Required(field.NewPath("metadata", "name"), "name is required"),
76 object.UnstructuredToObjMetadata(invalidPodObj),
77 ),
78 ),
79 },
80 },
81 {
82
83 EventType: event.ValidationType,
84 ValidationEvent: &testutil.ExpValidationEvent{
85 Identifiers: object.ObjMetadataSet{
86 object.UnstructuredToObjMetadata(pod3Obj),
87 },
88 Error: testutil.EqualError(
89 validation.NewError(
90 object.InvalidAnnotationError{
91 Annotation: dependson.Annotation,
92 Cause: graph.ExternalDependencyError{
93 Edge: graph.Edge{
94 From: object.UnstructuredToObjMetadata(pod3Obj),
95 To: object.ObjMetadata{
96 GroupKind: schema.GroupKind{Kind: "Pod"},
97 Name: "pod0",
98 Namespace: namespaceName,
99 },
100 },
101 },
102 },
103 object.UnstructuredToObjMetadata(pod3Obj),
104 ),
105 ),
106 },
107 },
108 {
109
110 EventType: event.ValidationType,
111 ValidationEvent: &testutil.ExpValidationEvent{
112 Identifiers: object.ObjMetadataSet{
113 object.UnstructuredToObjMetadata(podBObj),
114 },
115 Error: testutil.EqualError(
116 validation.NewError(
117 object.InvalidAnnotationError{
118 Annotation: mutation.Annotation,
119 Cause: graph.ExternalDependencyError{
120 Edge: graph.Edge{
121 From: object.UnstructuredToObjMetadata(podBObj),
122 To: object.ObjMetadata{
123 GroupKind: schema.GroupKind{Kind: "Pod"},
124 Name: "pod-a",
125 },
126 },
127 },
128 },
129 object.UnstructuredToObjMetadata(podBObj),
130 ),
131 ),
132 },
133 },
134 {
135
136 EventType: event.ValidationType,
137 ValidationEvent: &testutil.ExpValidationEvent{
138 Identifiers: object.ObjMetadataSet{
139 object.UnstructuredToObjMetadata(podAObj),
140 object.UnstructuredToObjMetadata(podBObj),
141 },
142 Error: testutil.EqualError(
143 validation.NewError(
144 graph.CyclicDependencyError{
145 Edges: []graph.Edge{
146 {
147 From: object.UnstructuredToObjMetadata(podAObj),
148 To: object.UnstructuredToObjMetadata(podBObj),
149 },
150 {
151 From: object.UnstructuredToObjMetadata(podBObj),
152 To: object.UnstructuredToObjMetadata(podAObj),
153 },
154 },
155 },
156 object.UnstructuredToObjMetadata(podAObj),
157 object.UnstructuredToObjMetadata(podBObj),
158 ),
159 ),
160 },
161 },
162 {
163
164 EventType: event.InitType,
165 InitEvent: &testutil.ExpInitEvent{},
166 },
167 {
168
169 EventType: event.ActionGroupType,
170 ActionGroupEvent: &testutil.ExpActionGroupEvent{
171 Action: event.InventoryAction,
172 GroupName: "inventory-add-0",
173 Type: event.Started,
174 },
175 },
176 {
177
178 EventType: event.ActionGroupType,
179 ActionGroupEvent: &testutil.ExpActionGroupEvent{
180 Action: event.InventoryAction,
181 GroupName: "inventory-add-0",
182 Type: event.Finished,
183 },
184 },
185 {
186
187 EventType: event.ActionGroupType,
188 ActionGroupEvent: &testutil.ExpActionGroupEvent{
189 Action: event.ApplyAction,
190 GroupName: "apply-0",
191 Type: event.Started,
192 },
193 },
194 {
195
196 EventType: event.ApplyType,
197 ApplyEvent: &testutil.ExpApplyEvent{
198 GroupName: "apply-0",
199 Status: event.ApplySuccessful,
200 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
201 },
202 },
203 {
204
205 EventType: event.ActionGroupType,
206 ActionGroupEvent: &testutil.ExpActionGroupEvent{
207 Action: event.ApplyAction,
208 GroupName: "apply-0",
209 Type: event.Finished,
210 },
211 },
212 {
213
214 EventType: event.ActionGroupType,
215 ActionGroupEvent: &testutil.ExpActionGroupEvent{
216 Action: event.WaitAction,
217 GroupName: "wait-0",
218 Type: event.Started,
219 },
220 },
221 {
222
223 EventType: event.WaitType,
224 WaitEvent: &testutil.ExpWaitEvent{
225 GroupName: "wait-0",
226 Status: event.ReconcilePending,
227 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
228 },
229 },
230 {
231
232 EventType: event.WaitType,
233 WaitEvent: &testutil.ExpWaitEvent{
234 GroupName: "wait-0",
235 Status: event.ReconcileSuccessful,
236 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
237 },
238 },
239 {
240
241 EventType: event.ActionGroupType,
242 ActionGroupEvent: &testutil.ExpActionGroupEvent{
243 Action: event.WaitAction,
244 GroupName: "wait-0",
245 Type: event.Finished,
246 },
247 },
248 {
249
250 EventType: event.ActionGroupType,
251 ActionGroupEvent: &testutil.ExpActionGroupEvent{
252 Action: event.ApplyAction,
253 GroupName: "apply-1",
254 Type: event.Started,
255 },
256 },
257 {
258
259 EventType: event.ApplyType,
260 ApplyEvent: &testutil.ExpApplyEvent{
261 GroupName: "apply-1",
262 Status: event.ApplySuccessful,
263 Identifier: object.UnstructuredToObjMetadata(deployment1Obj),
264 },
265 },
266 {
267
268 EventType: event.ActionGroupType,
269 ActionGroupEvent: &testutil.ExpActionGroupEvent{
270 Action: event.ApplyAction,
271 GroupName: "apply-1",
272 Type: event.Finished,
273 },
274 },
275 {
276
277 EventType: event.ActionGroupType,
278 ActionGroupEvent: &testutil.ExpActionGroupEvent{
279 Action: event.WaitAction,
280 GroupName: "wait-1",
281 Type: event.Started,
282 },
283 },
284 {
285
286 EventType: event.WaitType,
287 WaitEvent: &testutil.ExpWaitEvent{
288 GroupName: "wait-1",
289 Status: event.ReconcilePending,
290 Identifier: object.UnstructuredToObjMetadata(deployment1Obj),
291 },
292 },
293 {
294
295 EventType: event.WaitType,
296 WaitEvent: &testutil.ExpWaitEvent{
297 GroupName: "wait-1",
298 Status: event.ReconcileSuccessful,
299 Identifier: object.UnstructuredToObjMetadata(deployment1Obj),
300 },
301 },
302 {
303
304 EventType: event.ActionGroupType,
305 ActionGroupEvent: &testutil.ExpActionGroupEvent{
306 Action: event.WaitAction,
307 GroupName: "wait-1",
308 Type: event.Finished,
309 },
310 },
311 {
312
313 EventType: event.ActionGroupType,
314 ActionGroupEvent: &testutil.ExpActionGroupEvent{
315 Action: event.InventoryAction,
316 GroupName: "inventory-set-0",
317 Type: event.Started,
318 },
319 },
320 {
321
322 EventType: event.ActionGroupType,
323 ActionGroupEvent: &testutil.ExpActionGroupEvent{
324 Action: event.InventoryAction,
325 GroupName: "inventory-set-0",
326 Type: event.Finished,
327 },
328 },
329 }
330 Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
331
332 By("verify pod1 created and ready")
333 result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
334 podIP, found, err := object.NestedField(result.Object, "status", "podIP")
335 Expect(err).NotTo(HaveOccurred())
336 Expect(found).To(BeTrue())
337 Expect(podIP).NotTo(BeEmpty())
338
339 By("verify deployment1 created and ready")
340 result = e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
341 e2eutil.AssertUnstructuredAvailable(result)
342
343 By("verify pod3 not found")
344 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
345
346 By("verify podA not found")
347 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
348
349 By("verify podB not found")
350 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
351
352 By("modify deployment1 depends-on annotation to be invalid")
353 e2eutil.ApplyUnstructured(ctx, c, e2eutil.WithDependsOn(deployment1Obj, "invalid"))
354
355 By("destroy valid objects and skip invalid objects")
356 destroyer := invConfig.DestroyerFactoryFunc()
357 destroyerEvents := e2eutil.RunCollect(destroyer.Run(ctx, inv, apply.DestroyerOptions{
358 InventoryPolicy: inventory.PolicyAdoptIfNoInventory,
359 ValidationPolicy: validation.SkipInvalid,
360 }))
361
362 expEvents = []testutil.ExpEvent{
363 {
364
365 EventType: event.ValidationType,
366 ValidationEvent: &testutil.ExpValidationEvent{
367 Identifiers: object.ObjMetadataSet{
368 object.UnstructuredToObjMetadata(deployment1Obj),
369 },
370 Error: testutil.EqualError(
371 validation.NewError(
372 object.InvalidAnnotationError{
373 Annotation: dependson.Annotation,
374 Cause: fmt.Errorf("failed to parse object reference (index: 0): %w",
375 fmt.Errorf("expected 3 or 5 fields, found 1: %q", "invalid")),
376 },
377 object.UnstructuredToObjMetadata(deployment1Obj),
378 ),
379 ),
380 },
381 },
382 {
383
384 EventType: event.InitType,
385 InitEvent: &testutil.ExpInitEvent{},
386 },
387 {
388
389 EventType: event.ActionGroupType,
390 ActionGroupEvent: &testutil.ExpActionGroupEvent{
391 Action: event.DeleteAction,
392 GroupName: "prune-0",
393 Type: event.Started,
394 },
395 },
396
397 {
398
399 EventType: event.DeleteType,
400 DeleteEvent: &testutil.ExpDeleteEvent{
401 GroupName: "prune-0",
402 Status: event.DeleteSuccessful,
403 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
404 },
405 },
406 {
407
408 EventType: event.ActionGroupType,
409 ActionGroupEvent: &testutil.ExpActionGroupEvent{
410 Action: event.DeleteAction,
411 GroupName: "prune-0",
412 Type: event.Finished,
413 },
414 },
415 {
416
417 EventType: event.ActionGroupType,
418 ActionGroupEvent: &testutil.ExpActionGroupEvent{
419 Action: event.WaitAction,
420 GroupName: "wait-0",
421 Type: event.Started,
422 },
423 },
424 {
425
426 EventType: event.WaitType,
427 WaitEvent: &testutil.ExpWaitEvent{
428 GroupName: "wait-0",
429 Status: event.ReconcilePending,
430 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
431 },
432 },
433 {
434
435 EventType: event.WaitType,
436 WaitEvent: &testutil.ExpWaitEvent{
437 GroupName: "wait-0",
438 Status: event.ReconcileSuccessful,
439 Identifier: object.UnstructuredToObjMetadata(pod1Obj),
440 },
441 },
442 {
443
444 EventType: event.ActionGroupType,
445 ActionGroupEvent: &testutil.ExpActionGroupEvent{
446 Action: event.WaitAction,
447 GroupName: "wait-0",
448 Type: event.Finished,
449 },
450 },
451 {
452
453 EventType: event.ActionGroupType,
454 ActionGroupEvent: &testutil.ExpActionGroupEvent{
455 Action: event.InventoryAction,
456 GroupName: "delete-inventory-0",
457 Type: event.Started,
458 },
459 },
460 {
461
462 EventType: event.ActionGroupType,
463 ActionGroupEvent: &testutil.ExpActionGroupEvent{
464 Action: event.InventoryAction,
465 GroupName: "delete-inventory-0",
466 Type: event.Finished,
467 },
468 },
469 }
470 Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
471
472 By("verify pod1 deleted")
473 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod1Obj)
474
475 By("verify deployment1 not deleted")
476 e2eutil.AssertUnstructuredExists(ctx, c, deployment1Obj)
477 e2eutil.DeleteUnstructuredIfExists(ctx, c, deployment1Obj)
478
479 By("verify pod3 not found")
480 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, pod3Obj)
481
482 By("verify podA not found")
483 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podAObj)
484
485 By("verify podB not found")
486 e2eutil.AssertUnstructuredDoesNotExist(ctx, c, podBObj)
487 }
488
View as plain text