k8s.io/kubernetes@v1.29.3/pkg/controller/certificates/cleaner/cleaner_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes 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 cleaner 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 capi "k8s.io/api/certificates/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/client-go/kubernetes/fake" 27 ) 28 29 const ( 30 expiredCert = `-----BEGIN CERTIFICATE----- 31 MIICIzCCAc2gAwIBAgIJAOApTlMFDOUnMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV 32 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 33 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD 34 VQQDDAEqMB4XDTE3MTAwNDIwNDgzOFoXDTE3MTAwMzIwNDgzOFowbTELMAkGA1UE 35 BhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9uZG9uMRgwFgYDVQQK 36 DA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQxCjAIBgNV 37 BAMMASowXDANBgkqhkiG9w0BAQEFAANLADBIAkEA3Gt0KmuRXDxvqZUiX/xqAn1t 38 nZZX98guZvPPyxnQtV3YpA274W0sX3jL+U71Ya+3kaUstXQa4YrWBUHiXoqJnwID 39 AQABo1AwTjAdBgNVHQ4EFgQUtDsIpzHoUiLsO88f9fm+G0tYSPowHwYDVR0jBBgw 40 FoAUtDsIpzHoUiLsO88f9fm+G0tYSPowDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B 41 AQsFAANBADfrlKof5CUkxGlX9Rifxv/mWOk8ZuTLWfMYQH2nycBHnmOxy6sR+87W 42 /Mb/uRz0TXVnGVcbu5E8Bz7e/Far1ZI= 43 -----END CERTIFICATE-----` 44 unexpiredCert = `-----BEGIN CERTIFICATE----- 45 MIICJTCCAc+gAwIBAgIJAIRjMToP+pPEMA0GCSqGSIb3DQEBCwUAMG0xCzAJBgNV 46 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 47 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MQowCAYD 48 VQQDDAEqMCAXDTE3MTAwNDIwNDUyNFoYDzIxMTcwOTEwMjA0NTI0WjBtMQswCQYD 49 VQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNV 50 BAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEKMAgG 51 A1UEAwwBKjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC7j9BAV5HqIJGi6r4G4YeI 52 ioHxH2loVu8IOKSK7xVs3v/EjR/eXbQzM+jZU7duyZqn6YjySZNLl0K0MfHCHBgX 53 AgMBAAGjUDBOMB0GA1UdDgQWBBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAfBgNVHSME 54 GDAWgBTwxV40NFSNW7lpQ3eUWX7Mxs03yzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 55 DQEBCwUAA0EALDi9OidANHflx8q+w3p0rJo9gpA6cJcFpEtP2Lv4kvOtB1f6L0jY 56 MLd7MVm4cS/MNcx4L7l23UC3Hx4+nAxvIg== 57 -----END CERTIFICATE-----` 58 ) 59 60 func TestCleanerWithApprovedExpiredCSR(t *testing.T) { 61 testCases := []struct { 62 name string 63 created metav1.Time 64 certificate []byte 65 conditions []capi.CertificateSigningRequestCondition 66 expectedActions []string 67 }{ 68 { 69 "no delete approved not passed deadline", 70 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 71 []byte(unexpiredCert), 72 []capi.CertificateSigningRequestCondition{ 73 { 74 Type: capi.CertificateApproved, 75 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 76 }, 77 }, 78 []string{}, 79 }, 80 { 81 "no delete approved passed deadline not issued", 82 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 83 nil, 84 []capi.CertificateSigningRequestCondition{ 85 { 86 Type: capi.CertificateApproved, 87 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 88 }, 89 }, 90 []string{}, 91 }, 92 { 93 "delete approved passed deadline", 94 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 95 []byte(unexpiredCert), 96 []capi.CertificateSigningRequestCondition{ 97 { 98 Type: capi.CertificateApproved, 99 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 100 }, 101 }, 102 []string{"delete"}, 103 }, 104 { 105 "no delete denied not passed deadline", 106 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 107 nil, 108 []capi.CertificateSigningRequestCondition{ 109 { 110 Type: capi.CertificateDenied, 111 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 112 }, 113 }, 114 []string{}, 115 }, 116 { 117 "delete denied passed deadline", 118 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 119 nil, 120 []capi.CertificateSigningRequestCondition{ 121 { 122 Type: capi.CertificateDenied, 123 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 124 }, 125 }, 126 []string{"delete"}, 127 }, 128 { 129 "no delete failed not passed deadline", 130 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 131 nil, 132 []capi.CertificateSigningRequestCondition{ 133 { 134 Type: capi.CertificateApproved, 135 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 136 }, 137 { 138 Type: capi.CertificateFailed, 139 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 140 }, 141 }, 142 []string{}, 143 }, 144 { 145 "delete failed passed deadline", 146 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 147 nil, 148 []capi.CertificateSigningRequestCondition{ 149 { 150 Type: capi.CertificateApproved, 151 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 152 }, 153 { 154 Type: capi.CertificateFailed, 155 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 156 }, 157 }, 158 []string{"delete"}, 159 }, 160 { 161 "no delete pending not passed deadline", 162 metav1.NewTime(time.Now().Add(-5 * time.Hour)), 163 nil, 164 []capi.CertificateSigningRequestCondition{}, 165 []string{}, 166 }, 167 { 168 "delete pending passed deadline", 169 metav1.NewTime(time.Now().Add(-25 * time.Hour)), 170 nil, 171 []capi.CertificateSigningRequestCondition{}, 172 []string{"delete"}, 173 }, 174 { 175 "no delete approved not passed deadline unexpired", 176 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 177 []byte(unexpiredCert), 178 []capi.CertificateSigningRequestCondition{ 179 { 180 Type: capi.CertificateApproved, 181 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 182 }, 183 }, 184 []string{}, 185 }, 186 { 187 "delete approved not passed deadline expired", 188 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 189 []byte(expiredCert), 190 []capi.CertificateSigningRequestCondition{ 191 { 192 Type: capi.CertificateApproved, 193 LastUpdateTime: metav1.NewTime(time.Now().Add(-50 * time.Minute)), 194 }, 195 }, 196 []string{"delete"}, 197 }, 198 { 199 "delete approved passed deadline unparseable", 200 metav1.NewTime(time.Now().Add(-1 * time.Minute)), 201 []byte(`garbage`), 202 []capi.CertificateSigningRequestCondition{ 203 { 204 Type: capi.CertificateApproved, 205 LastUpdateTime: metav1.NewTime(time.Now().Add(-2 * time.Hour)), 206 }, 207 }, 208 []string{"delete"}, 209 }, 210 } 211 212 for _, tc := range testCases { 213 t.Run(tc.name, func(t *testing.T) { 214 csr := &capi.CertificateSigningRequest{ 215 ObjectMeta: metav1.ObjectMeta{ 216 Name: "fake-csr", 217 CreationTimestamp: tc.created, 218 }, 219 Status: capi.CertificateSigningRequestStatus{ 220 Certificate: tc.certificate, 221 Conditions: tc.conditions, 222 }, 223 } 224 225 client := fake.NewSimpleClientset(csr) 226 s := &CSRCleanerController{ 227 csrClient: client.CertificatesV1().CertificateSigningRequests(), 228 } 229 ctx := context.TODO() 230 err := s.handle(ctx, csr) 231 if err != nil { 232 t.Fatalf("failed to clean CSR: %v", err) 233 } 234 235 actions := client.Actions() 236 if len(actions) != len(tc.expectedActions) { 237 t.Fatalf("got %d actions, wanted %d actions", len(actions), len(tc.expectedActions)) 238 } 239 for i := 0; i < len(actions); i++ { 240 if a := actions[i]; !a.Matches(tc.expectedActions[i], "certificatesigningrequests") { 241 t.Errorf("got action %#v, wanted %v", a, tc.expectedActions[i]) 242 } 243 } 244 }) 245 } 246 }