github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/reconcileresults/reconcile_results_test.go (about)

     1  // Copyright (c) 2020, 2022, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package reconcileresults
     5  
     6  import (
     7  	"fmt"
     8  	oamrt "github.com/crossplane/crossplane-runtime/apis/common/v1"
     9  	asserts "github.com/stretchr/testify/assert"
    10  	"github.com/verrazzano/verrazzano/application-operator/apis/oam/v1alpha1"
    11  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    12  	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
    13  	"testing"
    14  )
    15  
    16  // TestContainsErrors tests positive and negative use cases using ContainsErrors
    17  func TestContainsErrors(t *testing.T) {
    18  	assert := asserts.New(t)
    19  	var status ReconcileResults
    20  
    21  	// GIVEN status with all default fields
    22  	// WHEN the status is checked for errors
    23  	// THEN verify that errors are not detected
    24  	status = ReconcileResults{}
    25  	assert.False(status.ContainsErrors())
    26  
    27  	// GIVEN status that contains an error
    28  	// WHEN the status is checked for errors
    29  	// THEN verify that errors are detected
    30  	status = ReconcileResults{Errors: []error{fmt.Errorf("test-error")}}
    31  	assert.True(status.ContainsErrors())
    32  
    33  	// GIVEN status that contains no errors
    34  	// WHEN the status is checked for errors
    35  	// THEN verify that errors are not detected
    36  	status = ReconcileResults{Errors: []error{nil}}
    37  	assert.False(status.ContainsErrors())
    38  
    39  	// GIVEN status that contains both errors and nils
    40  	// WHEN the status is checked for errors
    41  	// THEN verify that errors are detected
    42  	status = ReconcileResults{Errors: []error{nil, fmt.Errorf("test-error"), nil}}
    43  	assert.True(status.ContainsErrors())
    44  }
    45  
    46  // TestContainsUpdates tests the ContainsUpdates method
    47  func TestContainsUpdates(t *testing.T) {
    48  	assert := asserts.New(t)
    49  	var status ReconcileResults
    50  
    51  	// GIVEN an empty reconcile result
    52  	// WHEN a check is made for updates
    53  	// THEN verify false is returned
    54  	assert.False(status.ContainsUpdates())
    55  
    56  	// GIVEN an empty reconcile result with an update
    57  	// WHEN a check is made for updates
    58  	// THEN verify true is returned
    59  	status = ReconcileResults{}
    60  	status.RecordOutcome(v1alpha1.QualifiedResourceRelation{}, controllerutil.OperationResultUpdated, nil)
    61  	assert.True(status.ContainsUpdates())
    62  
    63  	// GIVEN an empty reconcile result with no updates
    64  	// WHEN a check is made for updates
    65  	// THEN verify false is returned
    66  	status = ReconcileResults{}
    67  	status.RecordOutcome(v1alpha1.QualifiedResourceRelation{}, controllerutil.OperationResultNone, nil)
    68  	assert.False(status.ContainsUpdates())
    69  }
    70  
    71  // func (s *ReconcileResults) ContainsRelation(relation v1alpha1.QualifiedResourceRelation) bool {
    72  // TestContainsRelation tests the ContainsRelation method.
    73  func TestContainsRelation(t *testing.T) {
    74  	assert := asserts.New(t)
    75  	var results ReconcileResults
    76  	var rel = v1alpha1.QualifiedResourceRelation{
    77  		APIVersion: "test-apiver",
    78  		Kind:       "test-kind",
    79  		Name:       "test-name",
    80  		Role:       "test-role"}
    81  
    82  	// GIVEN a reconcile result with no relations
    83  	// WHEN a search is made for a relation
    84  	// THEN verify no relation is found
    85  	results = ReconcileResults{}
    86  	assert.False(results.ContainsRelation(rel))
    87  
    88  	// GIVEN a reconcile result with at least one relation
    89  	// WHEN a search is made for a relation that was recorded
    90  	// THEN verify the relation is found
    91  	results = ReconcileResults{}
    92  	results.RecordOutcome(rel, controllerutil.OperationResultNone, nil)
    93  	assert.True(results.ContainsRelation(rel))
    94  }
    95  
    96  // TestCreateConditionedStatus tests the CreateConditionedStatus method.
    97  func TestCreateConditionedStatus(t *testing.T) {
    98  	assert := asserts.New(t)
    99  	var recStatus ReconcileResults
   100  	var condStatus oamrt.ConditionedStatus
   101  
   102  	// GIVEN a default reconcile status
   103  	// WHEN the conditioned status is created from the reconcile status
   104  	// THEN verify that the conditioned status indicates success
   105  	recStatus = ReconcileResults{}
   106  	condStatus = recStatus.CreateConditionedStatus()
   107  	assert.Len(condStatus.Conditions, 1)
   108  	assert.Equal(oamrt.ReasonReconcileSuccess, condStatus.Conditions[0].Reason)
   109  
   110  	// GIVEN a reconcile status with one error
   111  	// WHEN the conditioned status is created from the reconcile status
   112  	// THEN verify that the error is included in the conditioned status
   113  	recStatus = ReconcileResults{Errors: []error{fmt.Errorf("test-error")}}
   114  	condStatus = recStatus.CreateConditionedStatus()
   115  	assert.Len(condStatus.Conditions, 1)
   116  	assert.Equal(oamrt.ReasonReconcileError, condStatus.Conditions[0].Reason)
   117  	assert.Equal("test-error", condStatus.Conditions[0].Message)
   118  
   119  	// GIVEN a reconcile status with one success
   120  	// WHEN the conditioned status is created from the reconcile status
   121  	// THEN verify that the conditioned status indicates success
   122  	recStatus = ReconcileResults{Errors: []error{nil}}
   123  	condStatus = recStatus.CreateConditionedStatus()
   124  	assert.Len(condStatus.Conditions, 1)
   125  	assert.Equal(oamrt.ReasonReconcileSuccess, condStatus.Conditions[0].Reason)
   126  
   127  	// GIVEN a reconcile status with both success and error
   128  	// WHEN the conditioned status is created from the reconcile status
   129  	// THEN verify that the conditioned status indicates failure
   130  	recStatus = ReconcileResults{Errors: []error{fmt.Errorf("test-error"), nil}}
   131  	condStatus = recStatus.CreateConditionedStatus()
   132  	assert.Len(condStatus.Conditions, 1)
   133  	assert.Equal(oamrt.ReasonReconcileError, condStatus.Conditions[0].Reason)
   134  	assert.Equal("test-error", condStatus.Conditions[0].Message)
   135  }
   136  
   137  // TestCreateResources tests the CreateResources method
   138  func TestCreateResources(t *testing.T) {
   139  	assert := asserts.New(t)
   140  	var status ReconcileResults
   141  	var resources []oamrt.TypedReference
   142  
   143  	// GIVEN a default reconcile results
   144  	// WHEN a resources slice is retrieved
   145  	// THEN verify the slice is empty.
   146  	status = ReconcileResults{}
   147  	resources = status.CreateResources()
   148  	assert.Len(resources, 0)
   149  
   150  	// GIVEN a reconcile status with a related resource
   151  	// WHEN related resources are retrieved
   152  	// THEN verify the retrieved slice matches the recorded resources.
   153  	relation := v1alpha1.QualifiedResourceRelation{
   154  		APIVersion: "test-apiver",
   155  		Kind:       "test-kind",
   156  		Name:       "test-name",
   157  		Role:       "test-role"}
   158  	resource := oamrt.TypedReference{
   159  		APIVersion: "test-apiver",
   160  		Kind:       "test-kind",
   161  		Name:       "test-name"}
   162  	status.RecordOutcome(relation, controllerutil.OperationResultUpdated, nil)
   163  	resources = status.CreateResources()
   164  	assert.Len(resources, 1)
   165  	assert.Equal(resource, resources[0])
   166  }
   167  
   168  // TestCreateStatusRelations tests the CreateStatusRelations method.
   169  func TestCreateRelations(t *testing.T) {
   170  	assert := asserts.New(t)
   171  	var status ReconcileResults
   172  	var rels []v1alpha1.QualifiedResourceRelation
   173  
   174  	// GIVEN a default reconcile results
   175  	// WHEN a relations slice is retrieved
   176  	// THEN verify the slice is empty.
   177  	status = ReconcileResults{}
   178  	rels = status.CreateRelations()
   179  	assert.Len(rels, 0)
   180  
   181  	// GIVEN a reconcile status with a related resource
   182  	// WHEN related resources are retrieved
   183  	// THEN verify the retrieved slice matches the recorded relations.
   184  	rel := v1alpha1.QualifiedResourceRelation{
   185  		APIVersion: "test-apiver",
   186  		Kind:       "test-kind",
   187  		Name:       "test-name",
   188  		Role:       "test-role"}
   189  	status.RecordOutcome(rel, controllerutil.OperationResultUpdated, nil)
   190  	rels = status.CreateRelations()
   191  	assert.Len(rels, 1)
   192  	assert.Equal(rel, rels[0])
   193  }
   194  
   195  // TestRecordOutcomeIfError tests the RecordOutcomeIfError method.
   196  func TestRecordOutcomeIfError(t *testing.T) {
   197  	assert := asserts.New(t)
   198  	var status ReconcileResults
   199  	var rels []v1alpha1.QualifiedResourceRelation
   200  	var rel v1alpha1.QualifiedResourceRelation
   201  	var res controllerutil.OperationResult
   202  
   203  	// GIVEN an empty reconcile results
   204  	// WHEN no error outcomes have been recorded
   205  	// THEN verify that no relations have been recorded
   206  	rel = v1alpha1.QualifiedResourceRelation{
   207  		APIVersion: "test-api-ver",
   208  		Kind:       "test-kind",
   209  		Namespace:  "test-space",
   210  		Name:       "test-name",
   211  		Role:       "test-role"}
   212  	res = controllerutil.OperationResultNone
   213  	status = ReconcileResults{}
   214  	status.RecordOutcomeIfError(rel, res, nil)
   215  	rels = status.CreateRelations()
   216  	assert.Len(rels, 0)
   217  
   218  	// GIVEN reconcile results that has recorded some errors and some successes.
   219  	// WHEN the recorded relations are returned
   220  	// THEN verify that only error relations have been recorded
   221  	err := fmt.Errorf("test-error")
   222  	relError := v1alpha1.QualifiedResourceRelation{
   223  		APIVersion: "test-api-ver",
   224  		Kind:       "test-kind",
   225  		Namespace:  "test-space",
   226  		Name:       "test-error-name",
   227  		Role:       "test-role"}
   228  	relSuccess := v1alpha1.QualifiedResourceRelation{
   229  		APIVersion: "test-api-ver",
   230  		Kind:       "test-kind",
   231  		Namespace:  "test-space",
   232  		Name:       "test-error-name",
   233  		Role:       "test-role"}
   234  	res = controllerutil.OperationResultNone
   235  	status = ReconcileResults{}
   236  	status.RecordOutcomeIfError(relSuccess, res, nil)
   237  	status.RecordOutcomeIfError(relError, res, err)
   238  	status.RecordOutcomeIfError(relSuccess, res, nil)
   239  	rels = status.CreateRelations()
   240  	assert.Len(rels, 1)
   241  	assert.Equal(relError, rels[0])
   242  }
   243  
   244  // TestConditionsEquivalent tests the ConditionsEquivalent method.
   245  func TestConditionsEquivalent(t *testing.T) {
   246  	assert := asserts.New(t)
   247  	var one oamrt.Condition
   248  	var two oamrt.Condition
   249  
   250  	one = oamrt.Condition{
   251  		Type:               "test-type",
   252  		Status:             "test-status-1",
   253  		LastTransitionTime: metav1.Unix(0, 0),
   254  		Reason:             "test-reason",
   255  		Message:            "test-message"}
   256  	two = oamrt.Condition{
   257  		Type:               "test-type",
   258  		Status:             "test-status-2",
   259  		LastTransitionTime: metav1.Unix(1, 1),
   260  		Reason:             "test-reason",
   261  		Message:            "test-message"}
   262  
   263  	// GIVEN two nil conditions
   264  	// WHEN the conditions are compared for equivalence
   265  	// THEN verify they are considered equivalent
   266  	assert.True(ConditionsEquivalent(nil, nil))
   267  
   268  	// GIVEN one nil and one non-nil condition
   269  	// WHEN the conditions are compared for equivalence
   270  	// THEN verify they are not considered equivalent
   271  	assert.False(ConditionsEquivalent(&one, nil))
   272  
   273  	// GIVEN one nil and one non-nil condition
   274  	// WHEN the conditions are compared for equivalence
   275  	// THEN verify they are not considered equivalent
   276  	assert.False(ConditionsEquivalent(nil, &two))
   277  
   278  	// GIVEN two identical conditions
   279  	// WHEN the conditions are compared for equivalence
   280  	// THEN verify they are considered equivalent
   281  	assert.True(ConditionsEquivalent(&one, &one))
   282  
   283  	// GIVEN two non-equivalent conditions
   284  	// WHEN the conditions are compared for equivalence
   285  	// THEN verify they are not considered equivalent
   286  	assert.False(ConditionsEquivalent(&one, &two))
   287  }
   288  
   289  // TestConditionedStatusEquivalent tests the ConditionedStatusEquivalent method.
   290  func TestConditionedStatusEquivalent(t *testing.T) {
   291  	assert := asserts.New(t)
   292  
   293  	one := oamrt.ConditionedStatus{Conditions: []oamrt.Condition{{
   294  		Type:               "test-type",
   295  		Status:             "test-status-1",
   296  		LastTransitionTime: metav1.Unix(1, 1),
   297  		Reason:             "test-reason",
   298  		Message:            "test-message"}}}
   299  	two := oamrt.ConditionedStatus{Conditions: []oamrt.Condition{{
   300  		Type:               "test-type",
   301  		Status:             "test-status-2",
   302  		LastTransitionTime: metav1.Unix(2, 2),
   303  		Reason:             "test-reason",
   304  		Message:            "test-message"}}}
   305  	three := oamrt.ConditionedStatus{Conditions: []oamrt.Condition{one.Conditions[0], one.Conditions[0]}}
   306  
   307  	// GIVEN two nil conditioned statuses
   308  	// WHEN they are compared for equivalence
   309  	// THEN verify they are considered equivalent
   310  	assert.True(ConditionedStatusEquivalent(nil, nil))
   311  
   312  	// GIVEN a nil and non-nil conditioned statuses
   313  	// WHEN they are compared for equivalence
   314  	// THEN verify they are considered not equivalent
   315  	assert.False(ConditionedStatusEquivalent(&one, nil))
   316  
   317  	// GIVEN a nil and non-nil conditioned statuses
   318  	// WHEN they are compared for equivalence
   319  	// THEN verify they are considered not equivalent
   320  	assert.False(ConditionedStatusEquivalent(nil, &two))
   321  
   322  	// GIVEN two identical conditioned statuses
   323  	// WHEN they are compared for equivalence
   324  	// THEN verify they are considered equivalent
   325  	assert.True(ConditionedStatusEquivalent(&one, &one))
   326  
   327  	// GIVEN two non-identical conditioned statuses
   328  	// WHEN they are compared for equivalence
   329  	// THEN verify they are considered not equivalent
   330  	assert.False(ConditionedStatusEquivalent(&one, &two))
   331  
   332  	// GIVEN two conditioned statuses of different lengths
   333  	// WHEN they are compared for equivalence
   334  	// THEN verify they are considered not equivalent
   335  	assert.False(ConditionedStatusEquivalent(&one, &three))
   336  }