...

Source file src/sigs.k8s.io/cli-utils/test/e2e/dependency_filter_test.go

Documentation: sigs.k8s.io/cli-utils/test/e2e

     1  // Copyright 2020 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     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/apis/actuation"
    14  	"sigs.k8s.io/cli-utils/pkg/apply"
    15  	"sigs.k8s.io/cli-utils/pkg/apply/event"
    16  	"sigs.k8s.io/cli-utils/pkg/apply/filter"
    17  	"sigs.k8s.io/cli-utils/pkg/object"
    18  	"sigs.k8s.io/cli-utils/pkg/object/validation"
    19  	"sigs.k8s.io/cli-utils/pkg/testutil"
    20  	"sigs.k8s.io/cli-utils/test/e2e/e2eutil"
    21  	"sigs.k8s.io/cli-utils/test/e2e/invconfig"
    22  	"sigs.k8s.io/controller-runtime/pkg/client"
    23  )
    24  
    25  //nolint:dupl // expEvents similar to other tests
    26  func dependencyFilterTest(ctx context.Context, c client.Client, invConfig invconfig.InventoryConfig, inventoryName, namespaceName string) {
    27  	By("apply resources in order based on depends-on annotation")
    28  	applier := invConfig.ApplierFactoryFunc()
    29  
    30  	inv := invConfig.InvWrapperFunc(invConfig.FactoryFunc(inventoryName, namespaceName, "test"))
    31  
    32  	pod1Obj := e2eutil.WithDependsOn(e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod1), namespaceName), fmt.Sprintf("/namespaces/%s/Pod/pod2", namespaceName))
    33  	pod2Obj := e2eutil.WithNamespace(e2eutil.ManifestToUnstructured(pod2), namespaceName)
    34  
    35  	// Dependency order: pod1 -> pod2
    36  	// Apply order: pod2, pod1
    37  	resources := []*unstructured.Unstructured{
    38  		pod1Obj,
    39  		pod2Obj,
    40  	}
    41  
    42  	// Cleanup
    43  	defer func(ctx context.Context, c client.Client) {
    44  		e2eutil.DeleteUnstructuredIfExists(ctx, c, pod1Obj)
    45  		e2eutil.DeleteUnstructuredIfExists(ctx, c, pod2Obj)
    46  	}(ctx, c)
    47  
    48  	applierEvents := e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
    49  		EmitStatusEvents: false,
    50  	}))
    51  
    52  	expEvents := []testutil.ExpEvent{
    53  		{
    54  			// InitTask
    55  			EventType: event.InitType,
    56  			InitEvent: &testutil.ExpInitEvent{},
    57  		},
    58  		{
    59  			// InvAddTask start
    60  			EventType: event.ActionGroupType,
    61  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
    62  				Action:    event.InventoryAction,
    63  				GroupName: "inventory-add-0",
    64  				Type:      event.Started,
    65  			},
    66  		},
    67  		{
    68  			// InvAddTask finished
    69  			EventType: event.ActionGroupType,
    70  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
    71  				Action:    event.InventoryAction,
    72  				GroupName: "inventory-add-0",
    73  				Type:      event.Finished,
    74  			},
    75  		},
    76  		{
    77  			// ApplyTask start
    78  			EventType: event.ActionGroupType,
    79  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
    80  				Action:    event.ApplyAction,
    81  				GroupName: "apply-0",
    82  				Type:      event.Started,
    83  			},
    84  		},
    85  		{
    86  			// Apply pod2 first
    87  			EventType: event.ApplyType,
    88  			ApplyEvent: &testutil.ExpApplyEvent{
    89  				GroupName:  "apply-0",
    90  				Status:     event.ApplySuccessful,
    91  				Identifier: object.UnstructuredToObjMetadata(pod2Obj),
    92  				Error:      nil,
    93  			},
    94  		},
    95  		{
    96  			// ApplyTask finished
    97  			EventType: event.ActionGroupType,
    98  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
    99  				Action:    event.ApplyAction,
   100  				GroupName: "apply-0",
   101  				Type:      event.Finished,
   102  			},
   103  		},
   104  		{
   105  			// WaitTask start
   106  			EventType: event.ActionGroupType,
   107  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   108  				Action:    event.WaitAction,
   109  				GroupName: "wait-0",
   110  				Type:      event.Started,
   111  			},
   112  		},
   113  		{
   114  			// pod2 reconcile Pending.
   115  			EventType: event.WaitType,
   116  			WaitEvent: &testutil.ExpWaitEvent{
   117  				GroupName:  "wait-0",
   118  				Status:     event.ReconcilePending,
   119  				Identifier: object.UnstructuredToObjMetadata(pod2Obj),
   120  			},
   121  		},
   122  		{
   123  			// pod2 confirmed Current.
   124  			EventType: event.WaitType,
   125  			WaitEvent: &testutil.ExpWaitEvent{
   126  				GroupName:  "wait-0",
   127  				Status:     event.ReconcileSuccessful,
   128  				Identifier: object.UnstructuredToObjMetadata(pod2Obj),
   129  			},
   130  		},
   131  		{
   132  			// WaitTask finished
   133  			EventType: event.ActionGroupType,
   134  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   135  				Action:    event.WaitAction,
   136  				GroupName: "wait-0",
   137  				Type:      event.Finished,
   138  			},
   139  		},
   140  		{
   141  			// ApplyTask start
   142  			EventType: event.ActionGroupType,
   143  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   144  				Action:    event.ApplyAction,
   145  				GroupName: "apply-1",
   146  				Type:      event.Started,
   147  			},
   148  		},
   149  		{
   150  			// Apply pod1 second
   151  			EventType: event.ApplyType,
   152  			ApplyEvent: &testutil.ExpApplyEvent{
   153  				GroupName:  "apply-1",
   154  				Status:     event.ApplySuccessful,
   155  				Identifier: object.UnstructuredToObjMetadata(pod1Obj),
   156  				Error:      nil,
   157  			},
   158  		},
   159  		{
   160  			// ApplyTask finished
   161  			EventType: event.ActionGroupType,
   162  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   163  				Action:    event.ApplyAction,
   164  				GroupName: "apply-1",
   165  				Type:      event.Finished,
   166  			},
   167  		},
   168  		{
   169  			// WaitTask start
   170  			EventType: event.ActionGroupType,
   171  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   172  				Action:    event.WaitAction,
   173  				GroupName: "wait-1",
   174  				Type:      event.Started,
   175  			},
   176  		},
   177  		{
   178  			// pod1 reconcile Pending.
   179  			EventType: event.WaitType,
   180  			WaitEvent: &testutil.ExpWaitEvent{
   181  				GroupName:  "wait-1",
   182  				Status:     event.ReconcilePending,
   183  				Identifier: object.UnstructuredToObjMetadata(pod1Obj),
   184  			},
   185  		},
   186  		{
   187  			// pod1 confirmed Current.
   188  			EventType: event.WaitType,
   189  			WaitEvent: &testutil.ExpWaitEvent{
   190  				GroupName:  "wait-1",
   191  				Status:     event.ReconcileSuccessful,
   192  				Identifier: object.UnstructuredToObjMetadata(pod1Obj),
   193  			},
   194  		},
   195  		{
   196  			// WaitTask finished
   197  			EventType: event.ActionGroupType,
   198  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   199  				Action:    event.WaitAction,
   200  				GroupName: "wait-1",
   201  				Type:      event.Finished,
   202  			},
   203  		},
   204  		{
   205  			// InvSetTask start
   206  			EventType: event.ActionGroupType,
   207  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   208  				Action:    event.InventoryAction,
   209  				GroupName: "inventory-set-0",
   210  				Type:      event.Started,
   211  			},
   212  		},
   213  		{
   214  			// InvSetTask finished
   215  			EventType: event.ActionGroupType,
   216  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   217  				Action:    event.InventoryAction,
   218  				GroupName: "inventory-set-0",
   219  				Type:      event.Finished,
   220  			},
   221  		},
   222  	}
   223  	receivedEvents := testutil.EventsToExpEvents(applierEvents)
   224  
   225  	expEvents, receivedEvents = e2eutil.FilterOptionalEvents(expEvents, receivedEvents)
   226  
   227  	Expect(receivedEvents).To(testutil.Equal(expEvents))
   228  
   229  	By("verify pod1 created and ready")
   230  	result := e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
   231  	podIP, found, err := object.NestedField(result.Object, "status", "podIP")
   232  	Expect(err).NotTo(HaveOccurred())
   233  	Expect(found).To(BeTrue())
   234  	Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
   235  
   236  	By("verify pod2 created and ready")
   237  	result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
   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()) // use podIP as proxy for readiness
   242  
   243  	// Attempt to Prune pod2
   244  	resources = []*unstructured.Unstructured{
   245  		pod1Obj,
   246  	}
   247  
   248  	applierEvents = e2eutil.RunCollect(applier.Run(ctx, inv, resources, apply.ApplierOptions{
   249  		EmitStatusEvents: false,
   250  		ValidationPolicy: validation.SkipInvalid,
   251  	}))
   252  
   253  	expEvents = []testutil.ExpEvent{
   254  		{
   255  			// InitTask
   256  			EventType: event.InitType,
   257  			InitEvent: &testutil.ExpInitEvent{},
   258  		},
   259  		{
   260  			// InvAddTask start
   261  			EventType: event.ActionGroupType,
   262  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   263  				Action:    event.InventoryAction,
   264  				GroupName: "inventory-add-0",
   265  				Type:      event.Started,
   266  			},
   267  		},
   268  		{
   269  			// InvAddTask finished
   270  			EventType: event.ActionGroupType,
   271  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   272  				Action:    event.InventoryAction,
   273  				GroupName: "inventory-add-0",
   274  				Type:      event.Finished,
   275  			},
   276  		},
   277  		{
   278  			// ApplyTask start
   279  			EventType: event.ActionGroupType,
   280  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   281  				Action:    event.ApplyAction,
   282  				GroupName: "apply-0",
   283  				Type:      event.Started,
   284  			},
   285  		},
   286  		{
   287  			// Apply pod1 Skipped (dependency actuation strategy mismatch)
   288  			EventType: event.ApplyType,
   289  			ApplyEvent: &testutil.ExpApplyEvent{
   290  				GroupName:  "apply-0",
   291  				Status:     event.ApplySkipped,
   292  				Identifier: object.UnstructuredToObjMetadata(pod1Obj),
   293  				Error: testutil.EqualError(&filter.DependencyActuationMismatchError{
   294  					Object:           object.UnstructuredToObjMetadata(pod1Obj),
   295  					Strategy:         actuation.ActuationStrategyApply,
   296  					Relationship:     filter.RelationshipDependency,
   297  					Relation:         object.UnstructuredToObjMetadata(pod2Obj),
   298  					RelationStrategy: actuation.ActuationStrategyDelete,
   299  				}),
   300  			},
   301  		},
   302  		{
   303  			// ApplyTask finished
   304  			EventType: event.ActionGroupType,
   305  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   306  				Action:    event.ApplyAction,
   307  				GroupName: "apply-0",
   308  				Type:      event.Finished,
   309  			},
   310  		},
   311  		{
   312  			// WaitTask start
   313  			EventType: event.ActionGroupType,
   314  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   315  				Action:    event.WaitAction,
   316  				GroupName: "wait-0",
   317  				Type:      event.Started,
   318  			},
   319  		},
   320  		{
   321  			// pod1 reconcile Skipped (because apply skipped)
   322  			EventType: event.WaitType,
   323  			WaitEvent: &testutil.ExpWaitEvent{
   324  				GroupName:  "wait-0",
   325  				Status:     event.ReconcileSkipped,
   326  				Identifier: object.UnstructuredToObjMetadata(pod1Obj),
   327  			},
   328  		},
   329  		{
   330  			// WaitTask finished
   331  			EventType: event.ActionGroupType,
   332  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   333  				Action:    event.WaitAction,
   334  				GroupName: "wait-0",
   335  				Type:      event.Finished,
   336  			},
   337  		},
   338  		{
   339  			// PruneTask start
   340  			EventType: event.ActionGroupType,
   341  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   342  				Action:    event.PruneAction,
   343  				GroupName: "prune-0",
   344  				Type:      event.Started,
   345  			},
   346  		},
   347  		{
   348  			// Prune pod2 Skipped (dependency actuation strategy mismatch)
   349  			EventType: event.PruneType,
   350  			PruneEvent: &testutil.ExpPruneEvent{
   351  				GroupName:  "prune-0",
   352  				Status:     event.PruneSkipped,
   353  				Identifier: object.UnstructuredToObjMetadata(pod2Obj),
   354  				Error: testutil.EqualError(&filter.DependencyActuationMismatchError{
   355  					Object:           object.UnstructuredToObjMetadata(pod2Obj),
   356  					Strategy:         actuation.ActuationStrategyDelete,
   357  					Relationship:     filter.RelationshipDependent,
   358  					Relation:         object.UnstructuredToObjMetadata(pod1Obj),
   359  					RelationStrategy: actuation.ActuationStrategyApply,
   360  				}),
   361  			},
   362  		},
   363  		{
   364  			// PruneTask finished
   365  			EventType: event.ActionGroupType,
   366  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   367  				Action:    event.PruneAction,
   368  				GroupName: "prune-0",
   369  				Type:      event.Finished,
   370  			},
   371  		},
   372  		{
   373  			// WaitTask start
   374  			EventType: event.ActionGroupType,
   375  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   376  				Action:    event.WaitAction,
   377  				GroupName: "wait-1",
   378  				Type:      event.Started,
   379  			},
   380  		},
   381  		{
   382  			// pod2 reconcile Skipped (because prune skipped)
   383  			EventType: event.WaitType,
   384  			WaitEvent: &testutil.ExpWaitEvent{
   385  				GroupName:  "wait-1",
   386  				Status:     event.ReconcileSkipped,
   387  				Identifier: object.UnstructuredToObjMetadata(pod2Obj),
   388  			},
   389  		},
   390  		{
   391  			// WaitTask finished
   392  			EventType: event.ActionGroupType,
   393  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   394  				Action:    event.WaitAction,
   395  				GroupName: "wait-1",
   396  				Type:      event.Finished,
   397  			},
   398  		},
   399  		{
   400  			// InvSetTask start
   401  			EventType: event.ActionGroupType,
   402  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   403  				Action:    event.InventoryAction,
   404  				GroupName: "inventory-set-0",
   405  				Type:      event.Started,
   406  			},
   407  		},
   408  		{
   409  			// InvSetTask finished
   410  			EventType: event.ActionGroupType,
   411  			ActionGroupEvent: &testutil.ExpActionGroupEvent{
   412  				Action:    event.InventoryAction,
   413  				GroupName: "inventory-set-0",
   414  				Type:      event.Finished,
   415  			},
   416  		},
   417  	}
   418  	receivedEvents = testutil.EventsToExpEvents(applierEvents)
   419  
   420  	expEvents, receivedEvents = e2eutil.FilterOptionalEvents(expEvents, receivedEvents)
   421  
   422  	Expect(receivedEvents).To(testutil.Equal(expEvents))
   423  
   424  	By("verify pod1 not deleted")
   425  	result = e2eutil.AssertUnstructuredExists(ctx, c, pod1Obj)
   426  	ts, found, err := object.NestedField(result.Object, "metadata", "deletionTimestamp")
   427  	Expect(err).NotTo(HaveOccurred())
   428  	Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
   429  
   430  	By("verify pod2 not deleted")
   431  	result = e2eutil.AssertUnstructuredExists(ctx, c, pod2Obj)
   432  	ts, found, err = object.NestedField(result.Object, "metadata", "deletionTimestamp")
   433  	Expect(err).NotTo(HaveOccurred())
   434  	Expect(found).To(BeFalse(), "deletionTimestamp found: ", ts)
   435  }
   436  

View as plain text