[OOM-K8S-CERT-EXTERNAL-PROVIDER] Add CertificateRequest controller test 35/114535/5
authorPiotr Marcinkiewicz <piotr.marcinkiewicz@nokia.com>
Tue, 3 Nov 2020 16:06:13 +0000 (17:06 +0100)
committerPiotr Marcinkiewicz <piotr.marcinkiewicz@nokia.com>
Thu, 5 Nov 2020 08:34:41 +0000 (08:34 +0000)
- Add CertificateRequest controller test with fake K8s API

Issue-ID: OOM-2559
Signed-off-by: Piotr Marcinkiewicz <piotr.marcinkiewicz@nokia.com>
Change-Id: I4e32c2d28f5c4ea35dd013119dfc31acb1646582

certServiceK8sExternalProvider/src/cmpv2controller/certificate_request_controller_test.go
certServiceK8sExternalProvider/src/cmpv2controller/cmpv2_issuer_controller_test.go
certServiceK8sExternalProvider/src/cmpv2provisioner/cmpv2_provisioner_test.go
certServiceK8sExternalProvider/src/testdata/provider.go
certServiceK8sExternalProvider/src/testdata/utils.go [new file with mode: 0644]

index 2c401cc..f5869ea 100644 (file)
 package cmpv2controller
 
 import (
+       "context"
        "testing"
 
        cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
+       cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1"
        "github.com/stretchr/testify/assert"
+       v1 "k8s.io/api/core/v1"
+       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/types"
+       "k8s.io/client-go/tools/record"
+       ctrl "sigs.k8s.io/controller-runtime"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+       "sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+       "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
+       provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner"
+       provisionersdata "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner/csr/testdata"
+       "onap.org/oom-certservice/k8s-external-provider/src/testdata"
+       x509 "onap.org/oom-certservice/k8s-external-provider/src/x509/testdata"
+)
+
+const (
+       group                  = "certmanager.onap.org"
+       certificateRequestName = "testRequest"
+       recorderBufferSize     = 3
 )
 
-const group = "certmanager.onap.org"
+func Test_shouldSaveCorrectSignedPems_whenRequestReceived(t *testing.T) {
+       verifiedIssuer := getVerifiedIssuer()
+       createProvisioner(verifiedIssuer)
+       fakeClient := fake.NewFakeClientWithScheme(testdata.GetScheme(), &verifiedIssuer,
+               getValidCertificateRequest(), getValidPrivateKeySecret())
+       fakeRecorder := record.NewFakeRecorder(recorderBufferSize)
+       controller := getCertRequestController(fakeRecorder, fakeClient)
+       fakeRequest := testdata.GetFakeRequest(certificateRequestName)
+
+       res, err := controller.Reconcile(fakeRequest)
+
+       signedPEM, trustedCAs := getCertificates(controller, fakeRequest.NamespacedName)
+       assert.Nil(t, err)
+       assert.NotNil(t, res)
+       assert.Equal(t, <-fakeRecorder.Events, "Normal Issued Certificate issued")
+       testdata.VerifyCertsAreEqualToExpected(t, signedPEM, trustedCAs)
+       clearProvisioner()
+}
 
 func Test_shouldBeInvalidCMPv2CertificateRequest_whenEmpty(t *testing.T) {
        request := new(cmapi.CertificateRequest)
@@ -50,3 +88,82 @@ func Test_shouldBeValidCMPv2CertificateRequest_whenKindIsCMPvIssuer(t *testing.T
 
        assert.True(t, isCMPv2CertificateRequest(request))
 }
+
+func getCertificates(controller CertificateRequestController, namespacedName types.NamespacedName) ([]byte, []byte) {
+       certificateRequest := new(cmapi.CertificateRequest)
+       _ = controller.Client.Get(context.Background(), namespacedName, certificateRequest)
+
+       signedPEM := certificateRequest.Status.Certificate
+       trustedCAs := certificateRequest.Status.CA
+
+       return signedPEM, trustedCAs
+}
+
+func getValidPrivateKeySecret() *v1.Secret {
+       const privateKeySecretKey = "tls.key"
+
+       return &v1.Secret{
+               Data: map[string][]byte{
+                       privateKeySecretKey: provisionersdata.PrivateKeyBytes,
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      testdata.PrivateKeySecret,
+                       Namespace: testdata.Namespace,
+               },
+       }
+}
+
+func getValidCertificateRequest() *cmapi.CertificateRequest {
+       return &cmapi.CertificateRequest{
+               TypeMeta: metav1.TypeMeta{
+                       Kind:       "",
+                       APIVersion: testdata.APIVersion,
+               },
+               ObjectMeta: metav1.ObjectMeta{
+                       Name:      certificateRequestName,
+                       Namespace: testdata.Namespace,
+                       Annotations: map[string]string{
+                               privateKeySecretNameAnnotation: testdata.PrivateKeySecret,
+                       },
+               },
+
+               Spec: cmapi.CertificateRequestSpec{
+                       IssuerRef: cmmeta.ObjectReference{
+                               Group: cmpv2api.GroupVersion.Group,
+                               Kind:  cmpv2api.CMPv2IssuerKind,
+                               Name:  testdata.IssuerObjectName,
+                       },
+                       Request: []byte(x509.ValidCertificateSignRequest),
+               },
+       }
+}
+
+func getCertRequestController(fakeRecorder *record.FakeRecorder, fakeClient client.Client) CertificateRequestController {
+       controller := CertificateRequestController{
+               Client:   fakeClient,
+               Log:      ctrl.Log.WithName("controllers").WithName("CertificateRequest"),
+               Recorder: fakeRecorder,
+       }
+       return controller
+}
+
+func getVerifiedIssuer() cmpv2api.CMPv2Issuer {
+       issuer, _ := testdata.GetValidIssuerWithSecret()
+       issuer.Status = cmpv2api.CMPv2IssuerStatus{
+               Conditions: []cmpv2api.CMPv2IssuerCondition{{
+                       Type:   cmpv2api.ConditionReady,
+                       Status: cmpv2api.ConditionTrue}},
+       }
+       return issuer
+}
+
+func createProvisioner(verifiedIssuer cmpv2api.CMPv2Issuer) {
+       provisionerFactory := provisioners.ProvisionerFactoryMock{}
+       fakeProvisioner, _ := provisionerFactory.CreateProvisioner(&verifiedIssuer, v1.Secret{})
+
+       provisioners.Store(testdata.GetIssuerStoreKey(), fakeProvisioner)
+}
+
+func clearProvisioner() {
+       provisioners.Store(testdata.GetIssuerStoreKey(), nil)
+}
index 88aaf5e..f4cb694 100644 (file)
@@ -24,43 +24,37 @@ import (
        "testing"
 
        "github.com/go-logr/logr"
-       certmanager "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
-       apiv1 "k8s.io/api/core/v1"
-       "k8s.io/apimachinery/pkg/runtime"
-       "k8s.io/apimachinery/pkg/types"
-       clientgoscheme "k8s.io/client-go/kubernetes/scheme"
        "k8s.io/client-go/tools/record"
        "k8s.io/utils/clock"
        ctrl "sigs.k8s.io/controller-runtime"
        "sigs.k8s.io/controller-runtime/pkg/client"
        "sigs.k8s.io/controller-runtime/pkg/client/fake"
-       "sigs.k8s.io/controller-runtime/pkg/reconcile"
 
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
-       certserviceapi "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
        provisioners "onap.org/oom-certservice/k8s-external-provider/src/cmpv2provisioner"
        "onap.org/oom-certservice/k8s-external-provider/src/testdata"
 )
 
 func Test_shouldPrepareAndVerifyCMPv2Issuer_whenRequestReceived(t *testing.T) {
-       scheme := initScheme()
+       scheme := testdata.GetScheme()
        issuer, secret := testdata.GetValidIssuerWithSecret()
-       fakeClient := getFakeClient(scheme, issuer, secret)
-       fakeRequest := getFakeRequest()
-       fakeRecorder := record.NewFakeRecorder(3)
-       controller := getController(fakeRecorder, fakeClient)
+       fakeClient := fake.NewFakeClientWithScheme(scheme, &issuer, &secret)
+       fakeRequest := testdata.GetFakeRequest(testdata.IssuerObjectName)
+       fakeRecorder := record.NewFakeRecorder(recorderBufferSize)
+       controller := getCMPv2IssuerController(fakeRecorder, fakeClient)
 
        res, err := controller.Reconcile(fakeRequest)
 
        expectedProvisioner, _ := controller.ProvisionerFactory.CreateProvisioner(&issuer, secret)
-       actualProvisioner, _ := provisioners.Load(types.NamespacedName{Name: testdata.IssuerObjectName, Namespace: testdata.Namespace})
+       actualProvisioner, _ := provisioners.Load(testdata.GetIssuerStoreKey())
        assert.Nil(t, err)
        assert.NotNil(t, res)
        assert.Equal(t, <-fakeRecorder.Events, "Normal Verified CMPv2Issuer verified and ready to sign certificates")
        assert.NotNil(t, actualProvisioner)
        assert.ObjectsAreEqual(expectedProvisioner, actualProvisioner)
+       clearProvisioner()
 }
 
 func Test_shouldBeValidCMPv2IssuerSpec_whenAllFieldsAreSet(t *testing.T) {
@@ -100,7 +94,7 @@ func test_shouldBeInvalidCMPv2IssuerSpec_whenFunctionApplied(t *testing.T, trans
        assert.NotNil(t, err)
 }
 
-func getController(fakeRecorder *record.FakeRecorder, mockClient client.Client) CMPv2IssuerController {
+func getCMPv2IssuerController(fakeRecorder *record.FakeRecorder, mockClient client.Client) CMPv2IssuerController {
        controller := CMPv2IssuerController{
                Log:                ctrl.Log.WithName("controllers").WithName("CertificateRequest"),
                Clock:              clock.RealClock{},
@@ -111,31 +105,6 @@ func getController(fakeRecorder *record.FakeRecorder, mockClient client.Client)
        return controller
 }
 
-func getFakeRequest() reconcile.Request {
-       fakeRequest := reconcile.Request{
-               NamespacedName: types.NamespacedName{
-                       Namespace: testdata.Namespace,
-                       Name:      testdata.IssuerObjectName,
-               },
-       }
-       return fakeRequest
-}
-
-func getFakeClient(scheme *runtime.Scheme, issuer cmpv2api.CMPv2Issuer, secret apiv1.Secret) client.Client {
-       fakeClient := func() client.Client {
-               return fake.NewFakeClientWithScheme(scheme, &issuer, &secret)
-       }()
-       return fakeClient
-}
-
-func initScheme() *runtime.Scheme {
-       scheme := runtime.NewScheme()
-       _ = clientgoscheme.AddToScheme(scheme)
-       _ = certmanager.AddToScheme(scheme)
-       _ = certserviceapi.AddToScheme(scheme)
-       return scheme
-}
-
 type MockLogger struct {
        mock.Mock
 }
index a483c72..cfafe95 100644 (file)
 package cmpv2provisioner
 
 import (
-       "bytes"
        "context"
-       "io/ioutil"
-       "log"
        "testing"
        "time"
 
@@ -32,10 +29,10 @@ import (
        "github.com/stretchr/testify/assert"
        apiv1 "k8s.io/api/core/v1"
        apimach "k8s.io/apimachinery/pkg/apis/meta/v1"
-       "k8s.io/apimachinery/pkg/types"
 
        "onap.org/oom-certservice/k8s-external-provider/src/certserviceclient"
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
+       "onap.org/oom-certservice/k8s-external-provider/src/testdata"
 )
 
 const ISSUER_NAME = "cmpv2-issuer"
@@ -44,7 +41,7 @@ const ISSUER_NAMESPACE = "onap"
 
 func Test_shouldCreateCorrectCertServiceCA(t *testing.T) {
        issuer := createIssuerAndCerts(ISSUER_NAME, ISSUER_URL)
-       provisioner, err := New(&issuer, &certServiceClientMock{})
+       provisioner, err := New(&issuer, &certserviceclient.CertServiceClientMock{})
 
        assert.Nil(t, err)
        assert.Equal(t, provisioner.name, issuer.Name, "Unexpected provisioner name.")
@@ -53,34 +50,31 @@ func Test_shouldCreateCorrectCertServiceCA(t *testing.T) {
 
 func Test_shouldSuccessfullyLoadPreviouslyStoredProvisioner(t *testing.T) {
        issuer := createIssuerAndCerts(ISSUER_NAME, ISSUER_URL)
-       provisioner, err := New(&issuer, &certServiceClientMock{})
+       provisioner, err := New(&issuer, &certserviceclient.CertServiceClientMock{})
 
        assert.Nil(t, err)
 
-       issuerNamespaceName := createIssuerNamespaceName(ISSUER_NAMESPACE, ISSUER_NAME)
+       issuerNamespaceName := testdata.CreateIssuerNamespaceName(ISSUER_NAMESPACE, ISSUER_NAME)
 
        Store(issuerNamespaceName, provisioner)
        provisioner, ok := Load(issuerNamespaceName)
 
-       verifyThatConditionIsTrue(ok, "Provisioner could not be loaded.", t)
+       testdata.VerifyThatConditionIsTrue(ok, "Provisioner could not be loaded.", t)
        assert.Equal(t, provisioner.name, issuer.Name, "Unexpected provisioner name.")
        assert.Equal(t, provisioner.url, issuer.Spec.URL, "Unexpected provisioner url.")
 }
 
 func Test_shouldReturnCorrectSignedPemsWhenParametersAreCorrect(t *testing.T) {
-       const EXPECTED_SIGNED_FILENAME = "testdata/expected_signed.pem"
-       const EXPECTED_TRUSTED_FILENAME = "testdata/expected_trusted.pem"
-
        issuer := createIssuerAndCerts(ISSUER_NAME, ISSUER_URL)
        provisionerFactory := ProvisionerFactoryMock{}
        provisioner, err := provisionerFactory.CreateProvisioner(&issuer, apiv1.Secret{})
 
-       issuerNamespaceName := createIssuerNamespaceName(ISSUER_NAMESPACE, ISSUER_NAME)
+       issuerNamespaceName := testdata.CreateIssuerNamespaceName(ISSUER_NAMESPACE, ISSUER_NAME)
        Store(issuerNamespaceName, provisioner)
 
        provisioner, ok := Load(issuerNamespaceName)
 
-       verifyThatConditionIsTrue(ok, "Provisioner could not be loaded", t)
+       testdata.VerifyThatConditionIsTrue(ok, "Provisioner could not be loaded", t)
 
        ctx := context.Background()
        request := createCertificateRequest()
@@ -90,21 +84,7 @@ func Test_shouldReturnCorrectSignedPemsWhenParametersAreCorrect(t *testing.T) {
 
        assert.Nil(t, err)
 
-       verifyThatConditionIsTrue(areSlicesEqual(signedPEM, readFile(EXPECTED_SIGNED_FILENAME)), "Signed pem is different than expected.", t)
-       verifyThatConditionIsTrue(areSlicesEqual(trustedCAs, readFile(EXPECTED_TRUSTED_FILENAME)), "Trusted CAs pem is different than expected.", t)
-}
-
-func verifyThatConditionIsTrue(cond bool, message string, t *testing.T) {
-       if !cond {
-               t.Fatal(message)
-       }
-}
-
-func createIssuerNamespaceName(namespace string, name string) types.NamespacedName {
-       return types.NamespacedName{
-               Namespace: namespace,
-               Name:      name,
-       }
+       testdata.VerifyCertsAreEqualToExpected(t, signedPEM, trustedCAs)
 }
 
 func createIssuerAndCerts(name string, url string) cmpv2api.CMPv2Issuer {
@@ -114,14 +94,6 @@ func createIssuerAndCerts(name string, url string) cmpv2api.CMPv2Issuer {
        return issuer
 }
 
-func readFile(filename string) []byte {
-       certRequest, err := ioutil.ReadFile(filename)
-       if err != nil {
-               log.Fatal(err)
-       }
-       return certRequest
-}
-
 func createCertificateRequest() *cmapi.CertificateRequest {
        const CERTIFICATE_DURATION = "1h"
        const ISSUER_KIND = "CMPv2Issuer"
@@ -140,33 +112,17 @@ func createCertificateRequest() *cmapi.CertificateRequest {
        request.Spec.IssuerRef.Name = ISSUER_NAME
        request.Spec.IssuerRef.Kind = ISSUER_KIND
        request.Spec.IssuerRef.Group = ISSUER_GROUP
-       request.Spec.Request = readFile(SPEC_REQUEST_FILENAME)
+       request.Spec.Request = testdata.ReadFile(SPEC_REQUEST_FILENAME)
        request.Spec.IsCA = true
 
        cond := new(cmapi.CertificateRequestCondition)
        cond.Type = CONDITION_TYPE
        request.Status.Conditions = []cmapi.CertificateRequestCondition{*cond}
-       request.Status.Certificate = readFile(STATUS_CERTIFICATE_FILENAME)
+       request.Status.Certificate = testdata.ReadFile(STATUS_CERTIFICATE_FILENAME)
 
        return request
 }
 
 func getPrivateKeyBytes() []byte {
-       return readFile("testdata/test_private_key.pem")
-}
-
-func areSlicesEqual(slice1 []byte, slice2 []byte) bool {
-       return bytes.Compare(slice1, slice2) == 0
-}
-
-type certServiceClientMock struct {
-       getCertificatesFunc func(csr []byte, key []byte) (*certserviceclient.CertificatesResponse, error)
-}
-
-func (client *certServiceClientMock) GetCertificates(csr []byte, key []byte) (*certserviceclient.CertificatesResponse, error) {
-       return client.getCertificatesFunc(csr, key)
-}
-
-func (client *certServiceClientMock) CheckHealth() error {
-       return nil
+       return testdata.ReadFile("testdata/test_private_key.pem")
 }
index 2e352cb..6bb420c 100644 (file)
 package testdata
 
 import (
+       cmapi "github.com/jetstack/cert-manager/pkg/apis/certmanager/v1"
        "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+       "k8s.io/apimachinery/pkg/runtime"
+       "k8s.io/apimachinery/pkg/types"
+       scheme2 "k8s.io/client-go/kubernetes/scheme"
+       "sigs.k8s.io/controller-runtime/pkg/reconcile"
 
        "onap.org/oom-certservice/k8s-external-provider/src/cmpv2api"
 )
@@ -36,15 +41,15 @@ const (
        KeySecretKey     = "cmpv2Issuer-key.pem"
        CertSecretKey    = "cmpv2Issuer-cert.pem"
        CacertSecretKey  = "cacert.pem"
-       Namespace        = "default"
-       IssuerObjectName = "fakeIssuer"
+       Namespace        = "onap"
+       IssuerObjectName = "cmpv2-issuer"
        Kind             = "CMPv2Issuer"
        APIVersion       = "v1"
+       PrivateKeySecret = "privateKeySecretName"
 )
 
 func GetValidIssuerWithSecret() (cmpv2api.CMPv2Issuer, v1.Secret) {
        issuer := cmpv2api.CMPv2Issuer{
-
                TypeMeta: metav1.TypeMeta{
                        APIVersion: APIVersion,
                        Kind:       Kind,
@@ -55,8 +60,8 @@ func GetValidIssuerWithSecret() (cmpv2api.CMPv2Issuer, v1.Secret) {
                },
                Spec: GetValidCMPv2IssuerSpec(),
        }
-       secret := v1.Secret{
 
+       secret := v1.Secret{
                Data: map[string][]byte{
                        KeySecretKey:    KeyBytes,
                        CertSecretKey:   CertBytes,
@@ -87,3 +92,28 @@ func GetValidCMPv2IssuerSpec() cmpv2api.CMPv2IssuerSpec {
        return issuerSpec
 }
 
+func GetScheme() *runtime.Scheme {
+       scheme := runtime.NewScheme()
+       _ = scheme2.AddToScheme(scheme)
+       _ = cmapi.AddToScheme(scheme)
+       _ = cmpv2api.AddToScheme(scheme)
+       return scheme
+}
+
+func GetFakeRequest(objectName string) reconcile.Request {
+       fakeRequest := reconcile.Request{
+               NamespacedName: CreateIssuerNamespaceName(Namespace, objectName),
+       }
+       return fakeRequest
+}
+
+func GetIssuerStoreKey() types.NamespacedName {
+       return CreateIssuerNamespaceName(Namespace, IssuerObjectName)
+}
+
+func CreateIssuerNamespaceName(namespace string, name string) types.NamespacedName {
+       return types.NamespacedName{
+               Namespace: namespace,
+               Name:      name,
+       }
+}
diff --git a/certServiceK8sExternalProvider/src/testdata/utils.go b/certServiceK8sExternalProvider/src/testdata/utils.go
new file mode 100644 (file)
index 0000000..af22195
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START=======================================================
+ * oom-certservice-k8s-external-provider
+ * ================================================================================
+ * Copyright (C) 2020 Nokia. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package testdata
+
+import (
+       "bytes"
+       "io/ioutil"
+       "log"
+       "testing"
+)
+
+func ReadFile(filename string) []byte {
+       certRequest, err := ioutil.ReadFile(filename)
+       if err != nil {
+               log.Fatal(err)
+       }
+       return certRequest
+}
+
+func VerifyCertsAreEqualToExpected(t *testing.T, signedPEM []byte, trustedCAs []byte) {
+       expectedSignedFilename := "../cmpv2provisioner/testdata/expected_signed.pem"
+       expectedTrustedFilename := "../cmpv2provisioner/testdata/expected_trusted.pem"
+
+       VerifyThatConditionIsTrue(AreSlicesEqual(signedPEM,
+               ReadFile(expectedSignedFilename)), "Signed pem is different than expected.", t)
+       VerifyThatConditionIsTrue(AreSlicesEqual(trustedCAs,
+               ReadFile(expectedTrustedFilename)), "Trusted CAs pem is different than expected.", t)
+}
+
+func AreSlicesEqual(slice1 []byte, slice2 []byte) bool {
+       return bytes.Compare(slice1, slice2) == 0
+}
+
+func VerifyThatConditionIsTrue(cond bool, message string, t *testing.T) {
+       if !cond {
+               t.Fatal(message)
+       }
+}