github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/operatorstatus/builder_test.go (about)

     1  package operatorstatus
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	configv1 "github.com/openshift/api/config/v1"
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  	utilclock "k8s.io/utils/clock/testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  func TestBuilder(t *testing.T) {
    15  	fakeClock := utilclock.NewFakeClock(time.Now())
    16  	minuteAgo := metav1.NewTime(time.Now().Add(-1 * time.Minute))
    17  
    18  	tests := []struct {
    19  		name     string
    20  		action   func(b *Builder)
    21  		existing *configv1.ClusterOperatorStatus
    22  		expected *configv1.ClusterOperatorStatus
    23  	}{
    24  		// Condition: (Progressing, True).
    25  		// existing status.Conditions is empty.
    26  		{
    27  			name: "WithProgressing/NoProgressingConditionPresentInExistingStatus",
    28  			action: func(b *Builder) {
    29  				b.WithProgressing(configv1.ConditionTrue, "message")
    30  			},
    31  			expected: &configv1.ClusterOperatorStatus{
    32  				Conditions: []configv1.ClusterOperatorStatusCondition{
    33  					{
    34  						Type:               configv1.OperatorProgressing,
    35  						Status:             configv1.ConditionTrue,
    36  						Message:            "message",
    37  						LastTransitionTime: metav1.NewTime(fakeClock.Now()),
    38  					},
    39  				},
    40  				Versions:       []configv1.OperandVersion{},
    41  				RelatedObjects: []configv1.ObjectReference{},
    42  			},
    43  		},
    44  
    45  		// Condition: (Progressing, True).
    46  		// (Progressing, False) is already present in existing status.Conditions.
    47  		{
    48  			name: "WithProgressing/ProgressingConditionPresentInExistingStatus",
    49  			action: func(b *Builder) {
    50  				b.WithProgressing(configv1.ConditionTrue, "message")
    51  			},
    52  			existing: &configv1.ClusterOperatorStatus{
    53  				Conditions: []configv1.ClusterOperatorStatusCondition{
    54  					{
    55  						Type:   configv1.OperatorProgressing,
    56  						Status: configv1.ConditionFalse,
    57  					},
    58  				},
    59  				Versions:       []configv1.OperandVersion{},
    60  				RelatedObjects: []configv1.ObjectReference{},
    61  			},
    62  			expected: &configv1.ClusterOperatorStatus{
    63  				Conditions: []configv1.ClusterOperatorStatusCondition{
    64  					{
    65  						Type:               configv1.OperatorProgressing,
    66  						Status:             configv1.ConditionTrue,
    67  						Message:            "message",
    68  						LastTransitionTime: metav1.NewTime(fakeClock.Now()),
    69  					},
    70  				},
    71  				Versions:       []configv1.OperandVersion{},
    72  				RelatedObjects: []configv1.ObjectReference{},
    73  			},
    74  		},
    75  
    76  		// Condition: (Progressing, True).
    77  		// (Progressing, True) is already present in existing status.Conditions.
    78  		{
    79  			name: "WithProgressing/ProgressingConditionMatchesInExistingStatus",
    80  			action: func(b *Builder) {
    81  				b.WithProgressing(configv1.ConditionTrue, "message")
    82  			},
    83  			existing: &configv1.ClusterOperatorStatus{
    84  				Conditions: []configv1.ClusterOperatorStatusCondition{
    85  					{
    86  						Type:               configv1.OperatorProgressing,
    87  						Status:             configv1.ConditionTrue,
    88  						LastTransitionTime: minuteAgo,
    89  					},
    90  				},
    91  				Versions:       []configv1.OperandVersion{},
    92  				RelatedObjects: []configv1.ObjectReference{},
    93  			},
    94  			expected: &configv1.ClusterOperatorStatus{
    95  				Conditions: []configv1.ClusterOperatorStatusCondition{
    96  					{
    97  						Type:               configv1.OperatorProgressing,
    98  						Status:             configv1.ConditionTrue,
    99  						Message:            "message",
   100  						LastTransitionTime: minuteAgo,
   101  					},
   102  				},
   103  				Versions:       []configv1.OperandVersion{},
   104  				RelatedObjects: []configv1.ObjectReference{},
   105  			},
   106  		},
   107  
   108  		// Condition: (Upgradeable, True).
   109  		// existing status.Conditions is empty.
   110  		{
   111  			name: "WithUpgradeable/NoUpgradeableConditionPresentInExistingStatus",
   112  			action: func(b *Builder) {
   113  				b.WithUpgradeable(configv1.ConditionTrue, "message")
   114  			},
   115  			expected: &configv1.ClusterOperatorStatus{
   116  				Conditions: []configv1.ClusterOperatorStatusCondition{
   117  					{
   118  						Type:               configv1.OperatorUpgradeable,
   119  						Status:             configv1.ConditionTrue,
   120  						Message:            "message",
   121  						LastTransitionTime: metav1.NewTime(fakeClock.Now()),
   122  					},
   123  				},
   124  				Versions:       []configv1.OperandVersion{},
   125  				RelatedObjects: []configv1.ObjectReference{},
   126  			},
   127  		},
   128  
   129  		// Condition: (Upgradeable, True).
   130  		// (Upgradeable, False) is already present in existing status.Conditions.
   131  		{
   132  			name: "WithUpgradeable/UpgradeableConditionPresentInExistingStatus",
   133  			action: func(b *Builder) {
   134  				b.WithUpgradeable(configv1.ConditionTrue, "message")
   135  			},
   136  			existing: &configv1.ClusterOperatorStatus{
   137  				Conditions: []configv1.ClusterOperatorStatusCondition{
   138  					{
   139  						Type:   configv1.OperatorUpgradeable,
   140  						Status: configv1.ConditionFalse,
   141  					},
   142  				},
   143  				Versions:       []configv1.OperandVersion{},
   144  				RelatedObjects: []configv1.ObjectReference{},
   145  			},
   146  			expected: &configv1.ClusterOperatorStatus{
   147  				Conditions: []configv1.ClusterOperatorStatusCondition{
   148  					{
   149  						Type:               configv1.OperatorUpgradeable,
   150  						Status:             configv1.ConditionTrue,
   151  						Message:            "message",
   152  						LastTransitionTime: metav1.NewTime(fakeClock.Now()),
   153  					},
   154  				},
   155  				Versions:       []configv1.OperandVersion{},
   156  				RelatedObjects: []configv1.ObjectReference{},
   157  			},
   158  		},
   159  
   160  		// Condition: (Upgradeable, True).
   161  		// (Upgradeable, True) is already present in existing status.Conditions.
   162  		{
   163  			name: "WithUpgradeable/UpgradeableConditionMatchesInExistingStatus",
   164  			action: func(b *Builder) {
   165  				b.WithUpgradeable(configv1.ConditionTrue, "message")
   166  			},
   167  			existing: &configv1.ClusterOperatorStatus{
   168  				Conditions: []configv1.ClusterOperatorStatusCondition{
   169  					{
   170  						Type:               configv1.OperatorUpgradeable,
   171  						Status:             configv1.ConditionTrue,
   172  						LastTransitionTime: minuteAgo,
   173  					},
   174  				},
   175  				Versions:       []configv1.OperandVersion{},
   176  				RelatedObjects: []configv1.ObjectReference{},
   177  			},
   178  			expected: &configv1.ClusterOperatorStatus{
   179  				Conditions: []configv1.ClusterOperatorStatusCondition{
   180  					{
   181  						Type:               configv1.OperatorUpgradeable,
   182  						Status:             configv1.ConditionTrue,
   183  						Message:            "message",
   184  						LastTransitionTime: minuteAgo,
   185  					},
   186  				},
   187  				Versions:       []configv1.OperandVersion{},
   188  				RelatedObjects: []configv1.ObjectReference{},
   189  			},
   190  		},
   191  
   192  		// A new version is being added to status.
   193  		// Existing status does not have any matching name.
   194  		{
   195  			name: "WithVersion/WithNoMatchingName",
   196  			action: func(b *Builder) {
   197  				b.WithVersion("foo", "1.00")
   198  			},
   199  			expected: &configv1.ClusterOperatorStatus{
   200  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   201  				Versions: []configv1.OperandVersion{
   202  					{
   203  						Name:    "foo",
   204  						Version: "1.00",
   205  					},
   206  				},
   207  				RelatedObjects: []configv1.ObjectReference{},
   208  			},
   209  		},
   210  
   211  		// A new version is being added to status.
   212  		// Existing status already has a matching same name and version.
   213  		{
   214  			name: "WithVersion/WithMatchingNameAndVersion",
   215  			action: func(b *Builder) {
   216  				b.WithVersion("foo", "1.00")
   217  			},
   218  			existing: &configv1.ClusterOperatorStatus{
   219  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   220  				Versions: []configv1.OperandVersion{
   221  					{
   222  						Name:    "foo",
   223  						Version: "1.00",
   224  					},
   225  				},
   226  				RelatedObjects: []configv1.ObjectReference{},
   227  			},
   228  			expected: &configv1.ClusterOperatorStatus{
   229  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   230  				Versions: []configv1.OperandVersion{
   231  					{
   232  						Name:    "foo",
   233  						Version: "1.00",
   234  					},
   235  				},
   236  				RelatedObjects: []configv1.ObjectReference{},
   237  			},
   238  		},
   239  
   240  		// A new version is being added to status.
   241  		// Existing status already has a matching name but a different version.
   242  		{
   243  			name: "WithVersion/WithMatchingNameButDifferentVersion",
   244  			action: func(b *Builder) {
   245  				b.WithVersion("foo", "2.00")
   246  			},
   247  			existing: &configv1.ClusterOperatorStatus{
   248  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   249  				Versions: []configv1.OperandVersion{
   250  					{
   251  						Name:    "foo",
   252  						Version: "1.00",
   253  					},
   254  				},
   255  				RelatedObjects: []configv1.ObjectReference{},
   256  			},
   257  			expected: &configv1.ClusterOperatorStatus{
   258  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   259  				Versions: []configv1.OperandVersion{
   260  					{
   261  						Name:    "foo",
   262  						Version: "2.00",
   263  					},
   264  				},
   265  				RelatedObjects: []configv1.ObjectReference{},
   266  			},
   267  		},
   268  
   269  		// Multiple versions are added to status.
   270  		{
   271  			name: "WithVersion/WithMultipleVersions",
   272  			action: func(b *Builder) {
   273  				b.WithVersion("foo", "2.00").WithVersion("bar", "1.00")
   274  			},
   275  			existing: &configv1.ClusterOperatorStatus{
   276  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   277  				Versions: []configv1.OperandVersion{
   278  					{
   279  						Name:    "foo",
   280  						Version: "1.00",
   281  					},
   282  				},
   283  				RelatedObjects: []configv1.ObjectReference{},
   284  			},
   285  			expected: &configv1.ClusterOperatorStatus{
   286  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   287  				Versions: []configv1.OperandVersion{
   288  					{
   289  						Name:    "foo",
   290  						Version: "2.00",
   291  					},
   292  					{
   293  						Name:    "bar",
   294  						Version: "1.00",
   295  					},
   296  				},
   297  				RelatedObjects: []configv1.ObjectReference{},
   298  			},
   299  		},
   300  
   301  		// A version is being removed from status.
   302  		// Existing status already has a matching name.
   303  		{
   304  			name: "WithoutVersion/WithMatchingName",
   305  			action: func(b *Builder) {
   306  				b.WithoutVersion("foo", "1.00")
   307  			},
   308  			existing: &configv1.ClusterOperatorStatus{
   309  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   310  				Versions: []configv1.OperandVersion{
   311  					{
   312  						Name:    "foo",
   313  						Version: "1.00",
   314  					},
   315  					{
   316  						Name:    "bar",
   317  						Version: "1.00",
   318  					},
   319  				},
   320  				RelatedObjects: []configv1.ObjectReference{},
   321  			},
   322  			expected: &configv1.ClusterOperatorStatus{
   323  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   324  				Versions: []configv1.OperandVersion{
   325  					{
   326  						Name:    "bar",
   327  						Version: "1.00",
   328  					},
   329  				},
   330  				RelatedObjects: []configv1.ObjectReference{},
   331  			},
   332  		},
   333  
   334  		// A new related object is being added.
   335  		// Existing status is empty.
   336  		{
   337  			name: "WithRelatedObject/ReferenceNotPresentInStatus",
   338  			action: func(b *Builder) {
   339  				b.WithRelatedObject("group", "resources", "namespace", "name")
   340  			},
   341  			expected: &configv1.ClusterOperatorStatus{
   342  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   343  				Versions:   []configv1.OperandVersion{},
   344  				RelatedObjects: []configv1.ObjectReference{
   345  					{
   346  						Group:     "group",
   347  						Resource:  "resources",
   348  						Namespace: "namespace",
   349  						Name:      "name",
   350  					},
   351  				},
   352  			},
   353  		},
   354  
   355  		// A new related object reference is being added.
   356  		// Existing status already has the same related object reference.
   357  		{
   358  			name: "WithRelatedObject/ReferencePresentInStatus",
   359  			action: func(b *Builder) {
   360  				b.WithRelatedObject("group", "resources", "namespace", "name")
   361  			},
   362  			existing: &configv1.ClusterOperatorStatus{
   363  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   364  				Versions:   []configv1.OperandVersion{},
   365  				RelatedObjects: []configv1.ObjectReference{
   366  					{
   367  						Group:     "group",
   368  						Resource:  "resources",
   369  						Namespace: "namespace",
   370  						Name:      "name",
   371  					},
   372  				},
   373  			},
   374  			expected: &configv1.ClusterOperatorStatus{
   375  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   376  				Versions:   []configv1.OperandVersion{},
   377  				RelatedObjects: []configv1.ObjectReference{
   378  					{
   379  						Group:     "group",
   380  						Resource:  "resources",
   381  						Namespace: "namespace",
   382  						Name:      "name",
   383  					},
   384  				},
   385  			},
   386  		},
   387  
   388  		// A related object reference is being removed.
   389  		// Existing status already has the same related object reference.
   390  		{
   391  			name: "WithoutRelatedObject/ReferenceBeingRemoved",
   392  			action: func(b *Builder) {
   393  				b.WithoutRelatedObject("group", "resources", "namespace", "name")
   394  			},
   395  			existing: &configv1.ClusterOperatorStatus{
   396  				Conditions: []configv1.ClusterOperatorStatusCondition{},
   397  				Versions:   []configv1.OperandVersion{},
   398  				RelatedObjects: []configv1.ObjectReference{
   399  					{
   400  						Group:     "group",
   401  						Resource:  "resources",
   402  						Namespace: "namespace",
   403  						Name:      "name",
   404  					},
   405  				},
   406  			},
   407  			expected: &configv1.ClusterOperatorStatus{
   408  				Conditions:     []configv1.ClusterOperatorStatusCondition{},
   409  				Versions:       []configv1.OperandVersion{},
   410  				RelatedObjects: []configv1.ObjectReference{},
   411  			},
   412  		},
   413  	}
   414  
   415  	for _, tt := range tests {
   416  		t.Run(tt.name, func(t *testing.T) {
   417  			builder := &Builder{
   418  				clock:  fakeClock,
   419  				status: tt.existing,
   420  			}
   421  
   422  			// Go through the build steps specified.
   423  			tt.action(builder)
   424  
   425  			statusWant := tt.expected
   426  			statusGot := builder.GetStatus()
   427  
   428  			assert.Equal(t, statusWant, statusGot)
   429  		})
   430  	}
   431  }