From 2a08d8a8df0708382931f5c5029080633fce6666 Mon Sep 17 00:00:00 2001 From: joshvanl Date: Mon, 15 Mar 2021 14:51:54 +0000 Subject: [PATCH] Adds integration tests for revision manager Signed-off-by: joshvanl --- test/integration/certificates/BUILD.bazel | 2 + .../revisionmanager_controller_test.go | 184 ++++++++++++++++++ test/unit/gen/certificate.go | 6 + test/unit/gen/certificaterequest.go | 10 + 4 files changed, 202 insertions(+) create mode 100644 test/integration/certificates/revisionmanager_controller_test.go diff --git a/test/integration/certificates/BUILD.bazel b/test/integration/certificates/BUILD.bazel index 9289b1e59..5fdc55d75 100644 --- a/test/integration/certificates/BUILD.bazel +++ b/test/integration/certificates/BUILD.bazel @@ -5,6 +5,7 @@ go_test( srcs = [ "issuing_controller_test.go", "metrics_controller_test.go", + "revisionmanager_controller_test.go", "trigger_controller_test.go", ], deps = [ @@ -15,6 +16,7 @@ go_test( "//pkg/controller:go_default_library", "//pkg/controller/certificates/issuing:go_default_library", "//pkg/controller/certificates/metrics:go_default_library", + "//pkg/controller/certificates/revisionmanager:go_default_library", "//pkg/controller/certificates/trigger:go_default_library", "//pkg/controller/certificates/trigger/policies:go_default_library", "//pkg/logs:go_default_library", diff --git a/test/integration/certificates/revisionmanager_controller_test.go b/test/integration/certificates/revisionmanager_controller_test.go new file mode 100644 index 000000000..e279ddf9e --- /dev/null +++ b/test/integration/certificates/revisionmanager_controller_test.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package certificates + +import ( + "context" + "encoding/pem" + "strconv" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + apiutil "github.com/jetstack/cert-manager/pkg/api/util" + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + controllerpkg "github.com/jetstack/cert-manager/pkg/controller" + "github.com/jetstack/cert-manager/pkg/controller/certificates/revisionmanager" + logf "github.com/jetstack/cert-manager/pkg/logs" + "github.com/jetstack/cert-manager/pkg/metrics" + utilpki "github.com/jetstack/cert-manager/pkg/util/pki" + "github.com/jetstack/cert-manager/test/integration/framework" + "github.com/jetstack/cert-manager/test/unit/gen" +) + +// TestRevisionManagerController will ensure that the revision manager +// controller will delete old CertificateRequests occording to the +// spec.revisionHistoryLimit value +func TestRevisionManagerController(t *testing.T) { + config, stopFn := framework.RunControlPlane(t) + defer stopFn() + + // Build, instantiate and run the revision manager controller. + kubeClient, factory, cmCl, cmFactory := framework.NewClients(t, config) + + ctrl, queue, mustSync := revisionmanager.NewController(logf.Log, cmCl, cmFactory) + + c := controllerpkg.NewController( + context.Background(), + "issuing_test", + metrics.New(logf.Log), + ctrl.ProcessItem, + mustSync, + nil, + queue, + ) + stopController := framework.StartInformersAndController(t, factory, cmFactory, c) + defer stopController() + + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) + defer cancel() + + var ( + crtName = "testcrt" + namespace = "testns" + secretName = "test-crt-tls" + ) + + // Create Namespace + ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}} + _, err := kubeClient.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + + // Create Certificate + crt := gen.Certificate(crtName, + gen.SetCertificateNamespace(namespace), + gen.SetCertificateCommonName("my-common-name"), + gen.SetCertificateSecretName(secretName), + gen.SetCertificateRevisionHistoryLimit(3), + gen.SetCertificateIssuer(cmmeta.ObjectReference{Name: "testissuer", Group: "foo.io", Kind: "Issuer"}), + ) + + crt, err = cmCl.CertmanagerV1().Certificates(namespace).Create(ctx, crt, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + + // Set Certificate to Ready + apiutil.SetCertificateCondition(crt, crt.Generation, + cmapi.CertificateConditionReady, cmmeta.ConditionTrue, "Issued", "integration test") + crt, err = cmCl.CertmanagerV1().Certificates(namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{}) + if err != nil { + t.Fatal(err) + } + + // Create a new private key + sk, err := utilpki.GenerateRSAPrivateKey(2048) + if err != nil { + t.Fatal(err) + } + + csr, err := utilpki.GenerateCSR(crt) + if err != nil { + t.Fatal(err) + } + + // Encode CSR + csrDER, err := utilpki.EncodeCSR(csr, sk) + if err != nil { + t.Fatal(err) + } + + csrPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE REQUEST", Bytes: csrDER, + }) + + // Create 6 CertificateRequests which are owned by this Certificate + for i := 0; i < 6; i++ { + _, err = cmCl.CertmanagerV1().CertificateRequests(namespace).Create(ctx, &cmapi.CertificateRequest{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: crtName + "-", + Namespace: namespace, + Annotations: map[string]string{ + cmapi.CertificateRequestRevisionAnnotationKey: strconv.Itoa(i), + }, + OwnerReferences: []metav1.OwnerReference{ + *metav1.NewControllerRef(crt, cmapi.SchemeGroupVersion.WithKind("Certificate")), + }, + }, + Spec: cmapi.CertificateRequestSpec{ + Request: csrPEM, + IssuerRef: cmmeta.ObjectReference{Name: "testissuer", Group: "foo.io", Kind: "Issuer"}, + }, + }, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + } + + var crs []cmapi.CertificateRequest + + // Wait for 3 CertificateRequests to be deleted, and that they have the correct revisions + err = wait.Poll(time.Millisecond*100, time.Second*5, func() (done bool, err error) { + requests, err := cmCl.CertmanagerV1().CertificateRequests(namespace).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + return false, err + } + + if len(requests.Items) != 3 { + t.Logf("waiting for 3 requests to be deleted, got=%d", len(requests.Items)) + return false, nil + } + + crs = requests.Items + + return true, nil + }) + if err != nil { + t.Fatal(err) + } + + // Expect that the remaining requests have the largest revisions (3, 4, 5) + for _, revision := range []string{"3", "4", "5"} { + var found bool + for _, cr := range crs { + if cr.Annotations[cmapi.CertificateRequestRevisionAnnotationKey] == revision { + found = true + break + } + } + + if !found { + t.Errorf("failed to find a CertificateRequest with a revision=%s", revision) + } + } +} diff --git a/test/unit/gen/certificate.go b/test/unit/gen/certificate.go index 86a55b1e7..205b8c26a 100644 --- a/test/unit/gen/certificate.go +++ b/test/unit/gen/certificate.go @@ -237,3 +237,9 @@ func CertificateRef(certName, ownedUID string) metav1.OwnerReference { v1.SchemeGroupVersion.WithKind("Certificate"), ) } + +func SetCertificateRevisionHistoryLimit(limit int32) CertificateModifier { + return func(crt *v1.Certificate) { + crt.Spec.RevisionHistoryLimit = &limit + } +} diff --git a/test/unit/gen/certificaterequest.go b/test/unit/gen/certificaterequest.go index a24fbd0fe..5b7392325 100644 --- a/test/unit/gen/certificaterequest.go +++ b/test/unit/gen/certificaterequest.go @@ -177,3 +177,13 @@ func SetCertificateRequestGroups(groups []string) CertificateRequestModifier { cr.Spec.Groups = groups } } + +func SetCertificateRequestRevision(rev string) CertificateRequestModifier { + return func(cr *v1.CertificateRequest) { + if cr.Annotations == nil { + cr.Annotations = make(map[string]string) + } + + cr.Annotations[v1.CertificateRequestRevisionAnnotationKey] = rev + } +}