...

Source file src/github.com/cert-manager/issuer-lib/conditions/certificaterequest_test.go

Documentation: github.com/cert-manager/issuer-lib/conditions

     1  /*
     2  Copyright 2023 The cert-manager Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package conditions
    18  
    19  import (
    20  	"math/rand"
    21  	"testing"
    22  	"time"
    23  
    24  	cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    25  	cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
    26  	"github.com/stretchr/testify/require"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	clocktesting "k8s.io/utils/clock/testing"
    29  )
    30  
    31  // We are using a random time generator to generate random times for the
    32  // fakeClock. This will result in different times for each test run and
    33  // should make sure we don't incorrectly rely on `time.Now()` in the code.
    34  // WARNING: This approach does not guarantee that incorrect use of `time.Now()`
    35  // is always detected, but after a few test runs it should be very unlikely.
    36  func randomTime() time.Time {
    37  	min := time.Date(1970, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
    38  	max := time.Date(2070, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
    39  	delta := max - min
    40  
    41  	sec := rand.Int63n(delta) + min
    42  	return time.Unix(sec, 0)
    43  }
    44  
    45  func TestSetCertificateRequestStatusCondition(t *testing.T) {
    46  	type testCase struct {
    47  		name string
    48  
    49  		existingConditions []cmapi.CertificateRequestCondition
    50  		patchConditions    []cmapi.CertificateRequestCondition
    51  		conditionType      cmapi.CertificateRequestConditionType
    52  		status             cmmeta.ConditionStatus
    53  
    54  		expectedCondition *cmapi.CertificateRequestCondition
    55  		expectNewEntry    bool
    56  	}
    57  
    58  	fakeTime1 := randomTime()
    59  	fakeTimeObj1 := metav1.NewTime(fakeTime1)
    60  
    61  	fakeTime2 := randomTime()
    62  	fakeTimeObj2 := metav1.NewTime(fakeTime2)
    63  	fakeClock2 := clocktesting.NewFakeClock(fakeTime2)
    64  
    65  	testCases := []testCase{
    66  		{
    67  			name: "if the condition does NOT change its status, the last transition time should not be updated",
    68  			existingConditions: []cmapi.CertificateRequestCondition{
    69  				{
    70  					Type:   cmapi.CertificateRequestConditionReady,
    71  					Status: cmmeta.ConditionTrue,
    72  				},
    73  			},
    74  			patchConditions: []cmapi.CertificateRequestCondition{},
    75  			conditionType:   cmapi.CertificateRequestConditionReady,
    76  			status:          cmmeta.ConditionTrue,
    77  
    78  			expectedCondition: &cmapi.CertificateRequestCondition{
    79  				Type:               cmapi.CertificateRequestConditionReady,
    80  				Status:             cmmeta.ConditionTrue,
    81  				LastTransitionTime: &fakeTimeObj1,
    82  			},
    83  			expectNewEntry: true,
    84  		},
    85  		{
    86  			name: "if the condition DOES change its status, the last transition time should be updated",
    87  			existingConditions: []cmapi.CertificateRequestCondition{
    88  				{
    89  					Type:   cmapi.CertificateRequestConditionReady,
    90  					Status: cmmeta.ConditionTrue,
    91  				},
    92  			},
    93  			patchConditions: []cmapi.CertificateRequestCondition{},
    94  			conditionType:   cmapi.CertificateRequestConditionReady,
    95  			status:          cmmeta.ConditionFalse,
    96  
    97  			expectedCondition: &cmapi.CertificateRequestCondition{
    98  				Type:               cmapi.CertificateRequestConditionReady,
    99  				Status:             cmmeta.ConditionFalse,
   100  				LastTransitionTime: &fakeTimeObj2,
   101  			},
   102  			expectNewEntry: true,
   103  		},
   104  		{
   105  			name: "if the patch contains already contains the condition, it should get overwritten",
   106  			existingConditions: []cmapi.CertificateRequestCondition{
   107  				{
   108  					Type:   cmapi.CertificateRequestConditionReady,
   109  					Status: cmmeta.ConditionTrue,
   110  				},
   111  			},
   112  			patchConditions: []cmapi.CertificateRequestCondition{
   113  				{
   114  					Type:   cmapi.CertificateRequestConditionReady,
   115  					Status: cmmeta.ConditionTrue,
   116  				},
   117  			},
   118  			conditionType: cmapi.CertificateRequestConditionReady,
   119  			status:        cmmeta.ConditionTrue,
   120  
   121  			expectedCondition: &cmapi.CertificateRequestCondition{
   122  				Type:               cmapi.CertificateRequestConditionReady,
   123  				Status:             cmmeta.ConditionTrue,
   124  				LastTransitionTime: &fakeTimeObj1,
   125  			},
   126  			expectNewEntry: false,
   127  		},
   128  		{
   129  			name: "if the patch contains another condition type, it should get added",
   130  			existingConditions: []cmapi.CertificateRequestCondition{
   131  				{
   132  					Type:   cmapi.CertificateRequestConditionReady,
   133  					Status: cmmeta.ConditionTrue,
   134  				},
   135  			},
   136  			patchConditions: []cmapi.CertificateRequestCondition{
   137  				{
   138  					Type:   cmapi.CertificateRequestConditionReady,
   139  					Status: cmmeta.ConditionTrue,
   140  				},
   141  			},
   142  			conditionType: cmapi.CertificateRequestConditionApproved,
   143  			status:        cmmeta.ConditionTrue,
   144  
   145  			expectedCondition: &cmapi.CertificateRequestCondition{
   146  				Type:               cmapi.CertificateRequestConditionApproved,
   147  				Status:             cmmeta.ConditionTrue,
   148  				LastTransitionTime: &fakeTimeObj2,
   149  			},
   150  			expectNewEntry: true,
   151  		},
   152  	}
   153  
   154  	defaultConditions := func(t *testing.T, conditions []cmapi.CertificateRequestCondition) []cmapi.CertificateRequestCondition {
   155  		t.Helper()
   156  
   157  		for i := range conditions {
   158  			if conditions[i].LastTransitionTime != nil ||
   159  				conditions[i].Reason != "" ||
   160  				conditions[i].Message != "" {
   161  				t.Fatal("this field is managed by the test and should not be set")
   162  			}
   163  			conditions[i].LastTransitionTime = &fakeTimeObj1
   164  			conditions[i].Reason = "OldReason"
   165  			conditions[i].Message = "OldMessage"
   166  		}
   167  
   168  		return conditions
   169  	}
   170  
   171  	for _, test := range testCases {
   172  		test := test
   173  
   174  		t.Run(test.name, func(t *testing.T) {
   175  			test.existingConditions = defaultConditions(t, test.existingConditions)
   176  			test.patchConditions = defaultConditions(t, test.patchConditions)
   177  
   178  			patchConditions := append([]cmapi.CertificateRequestCondition{}, test.patchConditions...)
   179  
   180  			cond, time := SetCertificateRequestStatusCondition(
   181  				fakeClock2,
   182  				test.existingConditions,
   183  				&patchConditions,
   184  				test.conditionType,
   185  				test.status,
   186  				"NewReason",
   187  				"NewMessage",
   188  			)
   189  
   190  			if test.expectedCondition.Reason != "" ||
   191  				test.expectedCondition.Message != "" {
   192  				t.Fatal("this field is managed by the test and should not be set")
   193  			}
   194  			test.expectedCondition.Reason = "NewReason"
   195  			test.expectedCondition.Message = "NewMessage"
   196  			require.Equal(t, test.expectedCondition, cond)
   197  			require.Equal(t, &fakeTimeObj2, time)
   198  
   199  			// Check that the patchConditions slice got a new entry if expected
   200  			if test.expectNewEntry {
   201  				require.Equal(t, len(test.patchConditions)+1, len(patchConditions))
   202  			} else {
   203  				require.Equal(t, len(test.patchConditions), len(patchConditions))
   204  			}
   205  
   206  			// Make sure only the expected condition in the patchConditions slice got updated
   207  			for _, c := range patchConditions {
   208  				if c.Type == test.conditionType {
   209  					require.Equal(t, test.expectedCondition, &c)
   210  					continue
   211  				}
   212  
   213  				for _, ec := range test.patchConditions {
   214  					if ec.Type == c.Type {
   215  						require.Equal(t, ec, c)
   216  					}
   217  				}
   218  			}
   219  		})
   220  	}
   221  }
   222  

View as plain text