From e936d2242c1c14f1ca44d9330c2b32683c1433a1 Mon Sep 17 00:00:00 2001 From: JoshVanL Date: Mon, 18 May 2020 17:45:12 +0100 Subject: [PATCH] Adds integration test for new metrics controller Signed-off-by: JoshVanL --- test/integration/certificates/BUILD.bazel | 3 + .../certificates/issuing_controller_test.go | 9 +- .../certificates/metrics_controller_test.go | 174 ++++++++++++++++++ .../certificates/trigger_controller_test.go | 12 +- test/unit/gen/BUILD.bazel | 1 + test/unit/gen/certificate.go | 7 + 6 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 test/integration/certificates/metrics_controller_test.go diff --git a/test/integration/certificates/BUILD.bazel b/test/integration/certificates/BUILD.bazel index c912b7cad..8730d36f2 100644 --- a/test/integration/certificates/BUILD.bazel +++ b/test/integration/certificates/BUILD.bazel @@ -4,6 +4,7 @@ go_test( name = "go_default_test", srcs = [ "issuing_controller_test.go", + "metrics_controller_test.go", "trigger_controller_test.go", ], deps = [ @@ -14,7 +15,9 @@ go_test( "//pkg/controller/expcertificates/issuing:go_default_library", "//pkg/controller/expcertificates/trigger:go_default_library", "//pkg/controller/expcertificates/trigger/policies:go_default_library", + "//pkg/controller/metrics:go_default_library", "//pkg/logs:go_default_library", + "//pkg/metrics:go_default_library", "//pkg/util/pki:go_default_library", "//test/integration/framework:go_default_library", "//test/unit/gen:go_default_library", diff --git a/test/integration/certificates/issuing_controller_test.go b/test/integration/certificates/issuing_controller_test.go index 80b013f6c..eb98e3c0f 100644 --- a/test/integration/certificates/issuing_controller_test.go +++ b/test/integration/certificates/issuing_controller_test.go @@ -35,6 +35,7 @@ import ( controllerpkg "github.com/jetstack/cert-manager/pkg/controller" "github.com/jetstack/cert-manager/pkg/controller/expcertificates/issuing" 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" @@ -55,9 +56,14 @@ func TestIssuingController(t *testing.T) { EnableOwnerRef: true, } + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) + defer cancel() + ctrl, queue, mustSync := issuing.NewController(logf.Log, kubeClient, cmCl, factory, cmFactory, framework.NewEventRecorder(t), clock.RealClock{}, controllerOptions) c := controllerpkg.NewController( context.Background(), + "issuing_test", + metrics.New(logf.Log), ctrl.ProcessItem, mustSync, nil, @@ -66,9 +72,6 @@ func TestIssuingController(t *testing.T) { stopController := framework.StartInformersAndController(t, factory, cmFactory, c) defer stopController() - ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) - defer cancel() - var ( crtName = "testcrt" revision = 1 diff --git a/test/integration/certificates/metrics_controller_test.go b/test/integration/certificates/metrics_controller_test.go new file mode 100644 index 000000000..0b9f0fb7b --- /dev/null +++ b/test/integration/certificates/metrics_controller_test.go @@ -0,0 +1,174 @@ +/* +Copyright 2020 The Jetstack cert-manager contributors. + +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" + "fmt" + "io/ioutil" + "net/http" + "strings" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2" + cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + controllerpkg "github.com/jetstack/cert-manager/pkg/controller" + controllermetrics "github.com/jetstack/cert-manager/pkg/controller/metrics" + logf "github.com/jetstack/cert-manager/pkg/logs" + "github.com/jetstack/cert-manager/pkg/metrics" + "github.com/jetstack/cert-manager/test/integration/framework" + "github.com/jetstack/cert-manager/test/unit/gen" +) + +// TestMetricscontoller performs a basic test to ensure that Certificates +// metrics are exposed when a Certificate is created, updated, and removed when +// it is deleted. +func TestMetricsController(t *testing.T) { + config, stopFn := framework.RunControlPlane(t) + defer stopFn() + + // Build, instantiate and run the issuing controller. + _, factory, cmClient, cmFactory := framework.NewClients(t, config) + + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) + defer cancel() + + metricsHandler := metrics.New(logf.Log) + go metricsHandler.Start(make(chan struct{})) + time.Sleep(time.Second) + + ctrl, queue, mustSync := controllermetrics.NewController(factory, cmFactory, metricsHandler) + c := controllerpkg.NewController( + context.Background(), + "metrics_test", + metricsHandler, + ctrl.ProcessItem, + mustSync, + nil, + queue, + ) + stopController := framework.StartInformersAndController(t, factory, cmFactory, c) + defer stopController() + + var ( + crtName = "testcrt" + namespace = "testns" + + lastErr error + ) + + testMetrics := func(expectedOutput string) error { + resp, err := http.DefaultClient.Get("http://127.0.0.1:9402/metrics") + if err != nil { + return err + } + + output, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + + if strings.TrimSpace(string(output)) != strings.TrimSpace(expectedOutput) { + return fmt.Errorf("got unexpected metrics output\nexp:\n%s\ngot:\n%s\n", + expectedOutput, output) + } + + return nil + } + + waitForMetrics := func(expectedOutput string) { + err := wait.Poll(time.Millisecond*100, time.Second*5, func() (done bool, err error) { + if err := testMetrics(expectedOutput); err != nil { + lastErr = err + return false, nil + } + + return true, nil + }) + if err != nil { + t.Fatalf("%s: failed to wait for expected metrics to be exposed: %s", err, lastErr) + } + } + + // Should expose no metrics + + // Create Certificate + crt := gen.Certificate(crtName, + gen.SetCertificateNamespace(namespace), + gen.SetCertificateUID("uid-1"), + ) + + waitForMetrics("") + crt, err := cmClient.CertmanagerV1alpha2().Certificates(namespace).Create(ctx, crt, metav1.CreateOptions{}) + if err != nil { + t.Fatal(err) + } + + waitForMetrics(`# HELP certmanager_certificate_expiration_timestamp_seconds The date after which the certificate expires. Expressed as a Unix Epoch Time. +# TYPE certmanager_certificate_expiration_timestamp_seconds gauge +certmanager_certificate_expiration_timestamp_seconds{name="testcrt",namespace="testns"} 0 +# HELP certmanager_certificate_ready_status The ready status of the certificate. +# TYPE certmanager_certificate_ready_status gauge +certmanager_certificate_ready_status{condition="False",name="testcrt",namespace="testns"} 0 +certmanager_certificate_ready_status{condition="True",name="testcrt",namespace="testns"} 0 +certmanager_certificate_ready_status{condition="Unknown",name="testcrt",namespace="testns"} 1 +# HELP certmanager_controller_sync_call_count The number of sync() calls made by a controller. +# TYPE certmanager_controller_sync_call_count counter +certmanager_controller_sync_call_count{controller="metrics_test"} 1 +`) + + // Set Certificate Expiry and Ready status True + crt.Status.NotAfter = &metav1.Time{ + Time: time.Unix(100, 0), + } + crt.Status.Conditions = []cmapi.CertificateCondition{ + { + Type: cmapi.CertificateConditionReady, + Status: cmmeta.ConditionTrue, + }, + } + _, err = cmClient.CertmanagerV1alpha2().Certificates(namespace).UpdateStatus(ctx, crt, metav1.UpdateOptions{}) + if err != nil { + t.Fatal(err) + } + + waitForMetrics(`# HELP certmanager_certificate_expiration_timestamp_seconds The date after which the certificate expires. Expressed as a Unix Epoch Time. +# TYPE certmanager_certificate_expiration_timestamp_seconds gauge +certmanager_certificate_expiration_timestamp_seconds{name="testcrt",namespace="testns"} 100 +# HELP certmanager_certificate_ready_status The ready status of the certificate. +# TYPE certmanager_certificate_ready_status gauge +certmanager_certificate_ready_status{condition="False",name="testcrt",namespace="testns"} 0 +certmanager_certificate_ready_status{condition="True",name="testcrt",namespace="testns"} 1 +certmanager_certificate_ready_status{condition="Unknown",name="testcrt",namespace="testns"} 0 +# HELP certmanager_controller_sync_call_count The number of sync() calls made by a controller. +# TYPE certmanager_controller_sync_call_count counter +certmanager_controller_sync_call_count{controller="metrics_test"} 2 +`) + + err = cmClient.CertmanagerV1alpha2().Certificates(namespace).Delete(ctx, crt.Name, metav1.DeleteOptions{}) + if err != nil { + t.Fatal(err) + } + waitForMetrics(`# HELP certmanager_controller_sync_call_count The number of sync() calls made by a controller. +# TYPE certmanager_controller_sync_call_count counter +certmanager_controller_sync_call_count{controller="metrics_test"} 3 +`) +} diff --git a/test/integration/certificates/trigger_controller_test.go b/test/integration/certificates/trigger_controller_test.go index e10879131..891778bbd 100644 --- a/test/integration/certificates/trigger_controller_test.go +++ b/test/integration/certificates/trigger_controller_test.go @@ -32,6 +32,7 @@ import ( "github.com/jetstack/cert-manager/pkg/controller/expcertificates/trigger" "github.com/jetstack/cert-manager/pkg/controller/expcertificates/trigger/policies" logf "github.com/jetstack/cert-manager/pkg/logs" + "github.com/jetstack/cert-manager/pkg/metrics" "github.com/jetstack/cert-manager/test/integration/framework" ) @@ -44,11 +45,16 @@ func TestTriggerController(t *testing.T) { config, stopFn := framework.RunControlPlane(t) defer stopFn() + ctx, cancel := context.WithTimeout(context.TODO(), time.Second*20) + defer cancel() + // Build, instantiate and run the trigger controller. _, factory, cmCl, cmFactory := framework.NewClients(t, config) ctrl, queue, mustSync := trigger.NewController(logf.Log, cmCl, factory, cmFactory, framework.NewEventRecorder(t), clock.RealClock{}, policies.TriggerPolicyChain) c := controllerpkg.NewController( context.Background(), + "trigger_test", + metrics.New(logf.Log), ctrl.ProcessItem, mustSync, nil, @@ -57,7 +63,6 @@ func TestTriggerController(t *testing.T) { stopController := framework.StartInformersAndController(t, factory, cmFactory, c) defer stopController() - ctx := context.TODO() // Create a Certificate resource and wait for it to have the 'Issuing' condition. cert, err := cmCl.CertmanagerV1alpha2().Certificates("testns").Create(ctx, &cmapi.Certificate{ ObjectMeta: metav1.ObjectMeta{Name: "testcrt", Namespace: "testns"}, @@ -71,7 +76,7 @@ func TestTriggerController(t *testing.T) { t.Fatal(err) } - wait.Poll(time.Millisecond*100, time.Second*5, func() (done bool, err error) { + err = wait.Poll(time.Millisecond*100, time.Second*5, func() (done bool, err error) { c, err := cmCl.CertmanagerV1alpha2().Certificates(cert.Namespace).Get(ctx, cert.Name, metav1.GetOptions{}) if err != nil { t.Logf("Failed to fetch Certificate resource, retrying: %v", err) @@ -86,4 +91,7 @@ func TestTriggerController(t *testing.T) { } return true, nil }) + if err != nil { + t.Fatal(err) + } } diff --git a/test/unit/gen/BUILD.bazel b/test/unit/gen/BUILD.bazel index 54592013d..d2491cfcc 100644 --- a/test/unit/gen/BUILD.bazel +++ b/test/unit/gen/BUILD.bazel @@ -22,6 +22,7 @@ go_library( "//pkg/util/pki:go_default_library", "@io_k8s_api//core/v1:go_default_library", "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library", + "@io_k8s_apimachinery//pkg/types:go_default_library", ], ) diff --git a/test/unit/gen/certificate.go b/test/unit/gen/certificate.go index df7e63e35..d86d827c9 100644 --- a/test/unit/gen/certificate.go +++ b/test/unit/gen/certificate.go @@ -20,6 +20,7 @@ import ( "time" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha2" cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" @@ -176,6 +177,12 @@ func SetCertificateRevision(revision int) CertificateModifier { } } +func SetCertificateUID(uid types.UID) CertificateModifier { + return func(crt *v1alpha2.Certificate) { + crt.UID = uid + } +} + func AddCertificateAnnotations(annotations map[string]string) CertificateModifier { return func(crt *v1alpha2.Certificate) { if crt.Annotations == nil {