...

Source file src/sigs.k8s.io/cli-utils/pkg/apply/filter/dependency-filter_test.go

Documentation: sigs.k8s.io/cli-utils/pkg/apply/filter

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package filter
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  
    10  	"k8s.io/apimachinery/pkg/runtime/schema"
    11  	"sigs.k8s.io/cli-utils/pkg/apis/actuation"
    12  	"sigs.k8s.io/cli-utils/pkg/apply/taskrunner"
    13  	"sigs.k8s.io/cli-utils/pkg/common"
    14  	"sigs.k8s.io/cli-utils/pkg/inventory"
    15  	"sigs.k8s.io/cli-utils/pkg/object"
    16  	"sigs.k8s.io/cli-utils/pkg/testutil"
    17  )
    18  
    19  var idInvalid = object.ObjMetadata{
    20  	GroupKind: schema.GroupKind{
    21  		Kind: "", // required
    22  	},
    23  	Name: "invalid", // required
    24  }
    25  
    26  var idA = object.ObjMetadata{
    27  	GroupKind: schema.GroupKind{
    28  		Group: "group-a",
    29  		Kind:  "kind-a",
    30  	},
    31  	Name:      "name-a",
    32  	Namespace: "namespace-a",
    33  }
    34  
    35  var idB = object.ObjMetadata{
    36  	GroupKind: schema.GroupKind{
    37  		Group: "group-b",
    38  		Kind:  "kind-b",
    39  	},
    40  	Name:      "name-b",
    41  	Namespace: "namespace-b",
    42  }
    43  
    44  func TestDependencyFilter(t *testing.T) {
    45  	tests := map[string]struct {
    46  		dryRunStrategy    common.DryRunStrategy
    47  		actuationStrategy actuation.ActuationStrategy
    48  		contextSetup      func(*taskrunner.TaskContext)
    49  		id                object.ObjMetadata
    50  		expectedError     error
    51  	}{
    52  		"apply A (no deps)": {
    53  			actuationStrategy: actuation.ActuationStrategyApply,
    54  			contextSetup: func(taskContext *taskrunner.TaskContext) {
    55  				taskContext.Graph().AddVertex(idA)
    56  				taskContext.InventoryManager().AddPendingApply(idA)
    57  			},
    58  			id:            idA,
    59  			expectedError: nil,
    60  		},
    61  		"apply A (A -> B) when B is invalid": {
    62  			actuationStrategy: actuation.ActuationStrategyApply,
    63  			contextSetup: func(taskContext *taskrunner.TaskContext) {
    64  				taskContext.Graph().AddVertex(idA)
    65  				taskContext.Graph().AddVertex(idInvalid)
    66  				taskContext.Graph().AddEdge(idA, idInvalid)
    67  				taskContext.InventoryManager().AddPendingApply(idA)
    68  				taskContext.AddInvalidObject(idInvalid)
    69  			},
    70  			id: idA,
    71  			expectedError: testutil.EqualError(
    72  				NewFatalError(fmt.Errorf("invalid dependency: %s", idInvalid)),
    73  			),
    74  		},
    75  		"apply A (A -> B) before B is applied": {
    76  			actuationStrategy: actuation.ActuationStrategyApply,
    77  			contextSetup: func(taskContext *taskrunner.TaskContext) {
    78  				taskContext.Graph().AddVertex(idA)
    79  				taskContext.Graph().AddVertex(idB)
    80  				taskContext.Graph().AddEdge(idA, idB)
    81  				taskContext.InventoryManager().AddPendingApply(idA)
    82  				taskContext.InventoryManager().AddPendingApply(idB)
    83  			},
    84  			id: idA,
    85  			expectedError: testutil.EqualError(
    86  				NewFatalError(fmt.Errorf("premature apply: dependency apply actuation pending: %s", idB)),
    87  			),
    88  		},
    89  		"apply A (A -> B) before B is reconciled": {
    90  			actuationStrategy: actuation.ActuationStrategyApply,
    91  			contextSetup: func(taskContext *taskrunner.TaskContext) {
    92  				taskContext.Graph().AddVertex(idA)
    93  				taskContext.Graph().AddVertex(idB)
    94  				taskContext.Graph().AddEdge(idA, idB)
    95  				taskContext.InventoryManager().AddPendingApply(idA)
    96  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
    97  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
    98  					Strategy:        actuation.ActuationStrategyApply,
    99  					Actuation:       actuation.ActuationSucceeded,
   100  					Reconcile:       actuation.ReconcilePending,
   101  				})
   102  			},
   103  			id: idA,
   104  			expectedError: testutil.EqualError(
   105  				NewFatalError(fmt.Errorf("premature apply: dependency apply reconcile pending: %s", idB)),
   106  			),
   107  		},
   108  		"apply A (A -> B) after B is reconciled": {
   109  			actuationStrategy: actuation.ActuationStrategyApply,
   110  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   111  				taskContext.Graph().AddVertex(idA)
   112  				taskContext.Graph().AddVertex(idB)
   113  				taskContext.Graph().AddEdge(idA, idB)
   114  				taskContext.InventoryManager().AddPendingApply(idA)
   115  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   116  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   117  					Strategy:        actuation.ActuationStrategyApply,
   118  					Actuation:       actuation.ActuationSucceeded,
   119  					Reconcile:       actuation.ReconcileSucceeded,
   120  				})
   121  			},
   122  			id:            idA,
   123  			expectedError: nil,
   124  		},
   125  		"apply A (A -> B) after B apply failed": {
   126  			actuationStrategy: actuation.ActuationStrategyApply,
   127  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   128  				taskContext.Graph().AddVertex(idA)
   129  				taskContext.Graph().AddVertex(idB)
   130  				taskContext.Graph().AddEdge(idA, idB)
   131  				taskContext.InventoryManager().AddPendingApply(idA)
   132  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   133  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   134  					Strategy:        actuation.ActuationStrategyApply,
   135  					Actuation:       actuation.ActuationFailed,
   136  					Reconcile:       actuation.ReconcilePending,
   137  				})
   138  			},
   139  			id: idA,
   140  			expectedError: &DependencyPreventedActuationError{
   141  				Object:                  idA,
   142  				Strategy:                actuation.ActuationStrategyApply,
   143  				Relationship:            RelationshipDependency,
   144  				Relation:                idB,
   145  				RelationPhase:           PhaseActuation,
   146  				RelationActuationStatus: actuation.ActuationFailed,
   147  				RelationReconcileStatus: actuation.ReconcilePending,
   148  			},
   149  		},
   150  		"apply A (A -> B) after B apply skipped": {
   151  			actuationStrategy: actuation.ActuationStrategyApply,
   152  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   153  				taskContext.Graph().AddVertex(idA)
   154  				taskContext.Graph().AddVertex(idB)
   155  				taskContext.Graph().AddEdge(idA, idB)
   156  				taskContext.InventoryManager().AddPendingApply(idA)
   157  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   158  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   159  					Strategy:        actuation.ActuationStrategyApply,
   160  					Actuation:       actuation.ActuationSkipped,
   161  					Reconcile:       actuation.ReconcileSkipped,
   162  				})
   163  			},
   164  			id: idA,
   165  			expectedError: &DependencyPreventedActuationError{
   166  				Object:                  idA,
   167  				Strategy:                actuation.ActuationStrategyApply,
   168  				Relationship:            RelationshipDependency,
   169  				Relation:                idB,
   170  				RelationPhase:           PhaseActuation,
   171  				RelationActuationStatus: actuation.ActuationSkipped,
   172  				RelationReconcileStatus: actuation.ReconcileSkipped,
   173  			},
   174  		},
   175  		"apply A (A -> B) after B reconcile failed": {
   176  			actuationStrategy: actuation.ActuationStrategyApply,
   177  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   178  				taskContext.Graph().AddVertex(idA)
   179  				taskContext.Graph().AddVertex(idB)
   180  				taskContext.Graph().AddEdge(idA, idB)
   181  				taskContext.InventoryManager().AddPendingApply(idA)
   182  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   183  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   184  					Strategy:        actuation.ActuationStrategyApply,
   185  					Actuation:       actuation.ActuationSucceeded,
   186  					Reconcile:       actuation.ReconcileFailed,
   187  				})
   188  			},
   189  			id: idA,
   190  			expectedError: &DependencyPreventedActuationError{
   191  				Object:                  idA,
   192  				Strategy:                actuation.ActuationStrategyApply,
   193  				Relationship:            RelationshipDependency,
   194  				Relation:                idB,
   195  				RelationPhase:           PhaseReconcile,
   196  				RelationActuationStatus: actuation.ActuationSucceeded,
   197  				RelationReconcileStatus: actuation.ReconcileFailed,
   198  			},
   199  		},
   200  		"apply A (A -> B) after B reconcile timeout": {
   201  			actuationStrategy: actuation.ActuationStrategyApply,
   202  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   203  				taskContext.Graph().AddVertex(idA)
   204  				taskContext.Graph().AddVertex(idB)
   205  				taskContext.Graph().AddEdge(idA, idB)
   206  				taskContext.InventoryManager().AddPendingApply(idA)
   207  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   208  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   209  					Strategy:        actuation.ActuationStrategyApply,
   210  					Actuation:       actuation.ActuationSucceeded,
   211  					Reconcile:       actuation.ReconcileTimeout,
   212  				})
   213  			},
   214  			id: idA,
   215  			expectedError: &DependencyPreventedActuationError{
   216  				Object:                  idA,
   217  				Strategy:                actuation.ActuationStrategyApply,
   218  				Relationship:            RelationshipDependency,
   219  				Relation:                idB,
   220  				RelationPhase:           PhaseReconcile,
   221  				RelationActuationStatus: actuation.ActuationSucceeded,
   222  				RelationReconcileStatus: actuation.ReconcileTimeout,
   223  			},
   224  		},
   225  		// artificial use case: reconcile should only be skipped if apply failed or was skipped
   226  		"apply A (A -> B) after B reconcile skipped": {
   227  			actuationStrategy: actuation.ActuationStrategyApply,
   228  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   229  				taskContext.Graph().AddVertex(idA)
   230  				taskContext.Graph().AddVertex(idB)
   231  				taskContext.Graph().AddEdge(idA, idB)
   232  				taskContext.InventoryManager().AddPendingApply(idA)
   233  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   234  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   235  					Strategy:        actuation.ActuationStrategyApply,
   236  					Actuation:       actuation.ActuationSucceeded,
   237  					Reconcile:       actuation.ReconcileSkipped,
   238  				})
   239  			},
   240  			id: idA,
   241  			expectedError: &DependencyPreventedActuationError{
   242  				Object:                  idA,
   243  				Strategy:                actuation.ActuationStrategyApply,
   244  				Relationship:            RelationshipDependency,
   245  				Relation:                idB,
   246  				RelationPhase:           PhaseReconcile,
   247  				RelationActuationStatus: actuation.ActuationSucceeded,
   248  				RelationReconcileStatus: actuation.ReconcileSkipped,
   249  			},
   250  		},
   251  		"apply A (A -> B) when B delete pending": {
   252  			actuationStrategy: actuation.ActuationStrategyApply,
   253  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   254  				taskContext.Graph().AddVertex(idA)
   255  				taskContext.Graph().AddVertex(idB)
   256  				taskContext.Graph().AddEdge(idA, idB)
   257  				taskContext.InventoryManager().AddPendingApply(idA)
   258  				taskContext.InventoryManager().AddPendingDelete(idB)
   259  			},
   260  			id: idA,
   261  			expectedError: &DependencyActuationMismatchError{
   262  				Object:           idA,
   263  				Strategy:         actuation.ActuationStrategyApply,
   264  				Relationship:     RelationshipDependency,
   265  				Relation:         idB,
   266  				RelationStrategy: actuation.ActuationStrategyDelete,
   267  			},
   268  		},
   269  		"delete B (no deps)": {
   270  			actuationStrategy: actuation.ActuationStrategyDelete,
   271  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   272  				taskContext.Graph().AddVertex(idB)
   273  				taskContext.InventoryManager().AddPendingDelete(idB)
   274  			},
   275  			id:            idB,
   276  			expectedError: nil,
   277  		},
   278  		"delete B (A -> B) when A is invalid": {
   279  			actuationStrategy: actuation.ActuationStrategyDelete,
   280  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   281  				taskContext.Graph().AddVertex(idInvalid)
   282  				taskContext.Graph().AddVertex(idB)
   283  				taskContext.Graph().AddEdge(idInvalid, idB)
   284  				taskContext.InventoryManager().AddPendingDelete(idB)
   285  				taskContext.AddInvalidObject(idInvalid)
   286  			},
   287  			id: idB,
   288  			expectedError: testutil.EqualError(
   289  				NewFatalError(fmt.Errorf("invalid dependent: %s", idInvalid)),
   290  			),
   291  		},
   292  		"delete B (A -> B) before A is deleted": {
   293  			actuationStrategy: actuation.ActuationStrategyDelete,
   294  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   295  				taskContext.Graph().AddVertex(idA)
   296  				taskContext.Graph().AddVertex(idB)
   297  				taskContext.Graph().AddEdge(idA, idB)
   298  				taskContext.InventoryManager().AddPendingDelete(idB)
   299  				taskContext.InventoryManager().AddPendingDelete(idA)
   300  			},
   301  			id: idB,
   302  			expectedError: testutil.EqualError(
   303  				NewFatalError(fmt.Errorf("premature delete: dependent delete actuation pending: %s", idA)),
   304  			),
   305  		},
   306  		"delete B (A -> B) before A is reconciled": {
   307  			actuationStrategy: actuation.ActuationStrategyDelete,
   308  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   309  				taskContext.Graph().AddVertex(idA)
   310  				taskContext.Graph().AddVertex(idB)
   311  				taskContext.Graph().AddEdge(idA, idB)
   312  				taskContext.InventoryManager().AddPendingDelete(idB)
   313  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   314  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   315  					Strategy:        actuation.ActuationStrategyDelete,
   316  					Actuation:       actuation.ActuationSucceeded,
   317  					Reconcile:       actuation.ReconcilePending,
   318  				})
   319  			},
   320  			id: idB,
   321  			expectedError: testutil.EqualError(
   322  				NewFatalError(fmt.Errorf("premature delete: dependent delete reconcile pending: %s", idA)),
   323  			),
   324  		},
   325  		"delete B (A -> B) after A is reconciled": {
   326  			actuationStrategy: actuation.ActuationStrategyDelete,
   327  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   328  				taskContext.Graph().AddVertex(idA)
   329  				taskContext.Graph().AddVertex(idB)
   330  				taskContext.Graph().AddEdge(idA, idB)
   331  				taskContext.InventoryManager().AddPendingDelete(idB)
   332  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   333  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   334  					Strategy:        actuation.ActuationStrategyDelete,
   335  					Actuation:       actuation.ActuationSucceeded,
   336  					Reconcile:       actuation.ReconcileSucceeded,
   337  				})
   338  			},
   339  			id:            idB,
   340  			expectedError: nil,
   341  		},
   342  		"delete B (A -> B) after A delete failed": {
   343  			actuationStrategy: actuation.ActuationStrategyDelete,
   344  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   345  				taskContext.Graph().AddVertex(idA)
   346  				taskContext.Graph().AddVertex(idB)
   347  				taskContext.Graph().AddEdge(idA, idB)
   348  				taskContext.InventoryManager().AddPendingDelete(idB)
   349  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   350  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   351  					Strategy:        actuation.ActuationStrategyDelete,
   352  					Actuation:       actuation.ActuationFailed,
   353  					Reconcile:       actuation.ReconcilePending,
   354  				})
   355  			},
   356  			id: idB,
   357  			expectedError: &DependencyPreventedActuationError{
   358  				Object:                  idB,
   359  				Strategy:                actuation.ActuationStrategyDelete,
   360  				Relationship:            RelationshipDependent,
   361  				Relation:                idA,
   362  				RelationPhase:           PhaseActuation,
   363  				RelationActuationStatus: actuation.ActuationFailed,
   364  				RelationReconcileStatus: actuation.ReconcilePending,
   365  			},
   366  		},
   367  		"delete B (A -> B) after A delete skipped": {
   368  			actuationStrategy: actuation.ActuationStrategyDelete,
   369  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   370  				taskContext.Graph().AddVertex(idA)
   371  				taskContext.Graph().AddVertex(idB)
   372  				taskContext.Graph().AddEdge(idA, idB)
   373  				taskContext.InventoryManager().AddPendingDelete(idB)
   374  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   375  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   376  					Strategy:        actuation.ActuationStrategyDelete,
   377  					Actuation:       actuation.ActuationSkipped,
   378  					Reconcile:       actuation.ReconcileSkipped,
   379  				})
   380  			},
   381  			id: idB,
   382  			expectedError: &DependencyPreventedActuationError{
   383  				Object:                  idB,
   384  				Strategy:                actuation.ActuationStrategyDelete,
   385  				Relationship:            RelationshipDependent,
   386  				Relation:                idA,
   387  				RelationPhase:           PhaseActuation,
   388  				RelationActuationStatus: actuation.ActuationSkipped,
   389  				RelationReconcileStatus: actuation.ReconcileSkipped,
   390  			},
   391  		},
   392  		// artificial use case: delete reconcile can't fail, only timeout
   393  		"delete B (A -> B) after A reconcile failed": {
   394  			actuationStrategy: actuation.ActuationStrategyDelete,
   395  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   396  				taskContext.Graph().AddVertex(idA)
   397  				taskContext.Graph().AddVertex(idB)
   398  				taskContext.Graph().AddEdge(idA, idB)
   399  				taskContext.InventoryManager().AddPendingDelete(idB)
   400  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   401  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   402  					Strategy:        actuation.ActuationStrategyDelete,
   403  					Actuation:       actuation.ActuationSucceeded,
   404  					Reconcile:       actuation.ReconcileFailed,
   405  				})
   406  			},
   407  			id: idB,
   408  			expectedError: &DependencyPreventedActuationError{
   409  				Object:                  idB,
   410  				Strategy:                actuation.ActuationStrategyDelete,
   411  				Relationship:            RelationshipDependent,
   412  				Relation:                idA,
   413  				RelationPhase:           PhaseReconcile,
   414  				RelationActuationStatus: actuation.ActuationSucceeded,
   415  				RelationReconcileStatus: actuation.ReconcileFailed,
   416  			},
   417  		},
   418  		"delete B (A -> B) after A reconcile timeout": {
   419  			actuationStrategy: actuation.ActuationStrategyDelete,
   420  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   421  				taskContext.Graph().AddVertex(idA)
   422  				taskContext.Graph().AddVertex(idB)
   423  				taskContext.Graph().AddEdge(idA, idB)
   424  				taskContext.InventoryManager().AddPendingDelete(idB)
   425  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   426  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   427  					Strategy:        actuation.ActuationStrategyDelete,
   428  					Actuation:       actuation.ActuationSucceeded,
   429  					Reconcile:       actuation.ReconcileTimeout,
   430  				})
   431  			},
   432  			id: idB,
   433  			expectedError: &DependencyPreventedActuationError{
   434  				Object:                  idB,
   435  				Strategy:                actuation.ActuationStrategyDelete,
   436  				Relationship:            RelationshipDependent,
   437  				Relation:                idA,
   438  				RelationPhase:           PhaseReconcile,
   439  				RelationActuationStatus: actuation.ActuationSucceeded,
   440  				RelationReconcileStatus: actuation.ReconcileTimeout,
   441  			},
   442  		},
   443  		// artificial use case: reconcile should only be skipped if delete failed or was skipped
   444  		"delete B (A -> B) after A reconcile skipped": {
   445  			actuationStrategy: actuation.ActuationStrategyDelete,
   446  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   447  				taskContext.Graph().AddVertex(idA)
   448  				taskContext.Graph().AddVertex(idB)
   449  				taskContext.Graph().AddEdge(idA, idB)
   450  				taskContext.InventoryManager().AddPendingDelete(idB)
   451  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   452  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   453  					Strategy:        actuation.ActuationStrategyDelete,
   454  					Actuation:       actuation.ActuationSucceeded,
   455  					Reconcile:       actuation.ReconcileSkipped,
   456  				})
   457  			},
   458  			id: idB,
   459  			expectedError: &DependencyPreventedActuationError{
   460  				Object:                  idB,
   461  				Strategy:                actuation.ActuationStrategyDelete,
   462  				Relationship:            RelationshipDependent,
   463  				Relation:                idA,
   464  				RelationPhase:           PhaseReconcile,
   465  				RelationActuationStatus: actuation.ActuationSucceeded,
   466  				RelationReconcileStatus: actuation.ReconcileSkipped,
   467  			},
   468  		},
   469  		"delete B (A -> B) when A apply succeeded": {
   470  			actuationStrategy: actuation.ActuationStrategyDelete,
   471  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   472  				taskContext.Graph().AddVertex(idA)
   473  				taskContext.Graph().AddVertex(idB)
   474  				taskContext.Graph().AddEdge(idA, idB)
   475  				taskContext.InventoryManager().AddPendingDelete(idB)
   476  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   477  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   478  					Strategy:        actuation.ActuationStrategyApply,
   479  					Actuation:       actuation.ActuationSucceeded,
   480  					Reconcile:       actuation.ReconcileSucceeded,
   481  				})
   482  			},
   483  			id: idB,
   484  			expectedError: &DependencyActuationMismatchError{
   485  				Object:           idB,
   486  				Strategy:         actuation.ActuationStrategyDelete,
   487  				Relationship:     RelationshipDependent,
   488  				Relation:         idA,
   489  				RelationStrategy: actuation.ActuationStrategyApply,
   490  			},
   491  		},
   492  		"DryRun: apply A (A -> B) when B apply reconcile pending": {
   493  			dryRunStrategy:    common.DryRunClient,
   494  			actuationStrategy: actuation.ActuationStrategyApply,
   495  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   496  				taskContext.Graph().AddVertex(idA)
   497  				taskContext.Graph().AddVertex(idB)
   498  				taskContext.Graph().AddEdge(idA, idB)
   499  				taskContext.InventoryManager().AddPendingApply(idA)
   500  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   501  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idB),
   502  					Strategy:        actuation.ActuationStrategyApply,
   503  					Actuation:       actuation.ActuationSucceeded,
   504  					Reconcile:       actuation.ReconcilePending,
   505  				})
   506  			},
   507  			id:            idA,
   508  			expectedError: nil,
   509  		},
   510  		"DryRun: delete B (A -> B) when A delete reconcile pending": {
   511  			dryRunStrategy:    common.DryRunClient,
   512  			actuationStrategy: actuation.ActuationStrategyDelete,
   513  			contextSetup: func(taskContext *taskrunner.TaskContext) {
   514  				taskContext.Graph().AddVertex(idA)
   515  				taskContext.Graph().AddVertex(idB)
   516  				taskContext.Graph().AddEdge(idA, idB)
   517  				taskContext.InventoryManager().AddPendingDelete(idB)
   518  				taskContext.InventoryManager().SetObjectStatus(actuation.ObjectStatus{
   519  					ObjectReference: inventory.ObjectReferenceFromObjMetadata(idA),
   520  					Strategy:        actuation.ActuationStrategyDelete,
   521  					Actuation:       actuation.ActuationSucceeded,
   522  					Reconcile:       actuation.ReconcilePending,
   523  				})
   524  			},
   525  			id:            idB,
   526  			expectedError: nil,
   527  		},
   528  	}
   529  
   530  	for name, tc := range tests {
   531  		t.Run(name, func(t *testing.T) {
   532  			taskContext := taskrunner.NewTaskContext(nil, nil)
   533  			tc.contextSetup(taskContext)
   534  
   535  			filter := DependencyFilter{
   536  				TaskContext:       taskContext,
   537  				ActuationStrategy: tc.actuationStrategy,
   538  				DryRunStrategy:    tc.dryRunStrategy,
   539  			}
   540  			obj := defaultObj.DeepCopy()
   541  			obj.SetGroupVersionKind(tc.id.GroupKind.WithVersion("v1"))
   542  			obj.SetName(tc.id.Name)
   543  			obj.SetNamespace(tc.id.Namespace)
   544  
   545  			err := filter.Filter(obj)
   546  			testutil.AssertEqual(t, tc.expectedError, err)
   547  		})
   548  	}
   549  }
   550  

View as plain text