Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions pkg/controller/trustmanager/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package trustmanager

import (
"context"
"fmt"
"testing"
"time"

Expand Down Expand Up @@ -251,6 +252,86 @@ func TestProcessReconcileRequest(t *testing.T) {
},
wantErr: "failed to check if serviceaccount",
},
{
name: "trust namespace does not exist sets degraded true",
getTrustManager: func() *v1alpha1.TrustManager {
return testTrustManager().Build()
},
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
switch o := obj.(type) {
case *v1alpha1.TrustManager:
testTrustManager().Build().DeepCopyInto(o)
}
return nil
})
// Namespace does not exist - validateTrustNamespace will fail
m.ExistsCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) (bool, error) {
switch obj.(type) {
case *corev1.Namespace:
return false, nil
}
return false, nil
})
},
wantConditions: []metav1.Condition{
{
Type: v1alpha1.Degraded,
Status: metav1.ConditionTrue,
Reason: v1alpha1.ReasonFailed,
Message: fmt.Sprintf(
"reconciliation failed with irrecoverable error not retrying: trust namespace %q validation failed: trust namespace %q does not exist, create the namespace before creating TrustManager CR",
defaultTrustNamespace,
defaultTrustNamespace,
),
},
{
Type: v1alpha1.Ready,
Status: metav1.ConditionFalse,
Reason: v1alpha1.ReasonFailed,
},
},
},
{
name: "custom trust namespace configures resources correctly",
getTrustManager: func() *v1alpha1.TrustManager {
tm := testTrustManager().Build()
tm.Spec.TrustManagerConfig.TrustNamespace = "custom-trust-ns"
return tm
},
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
switch o := obj.(type) {
case *v1alpha1.TrustManager:
tm := testTrustManager().Build()
tm.Spec.TrustManagerConfig.TrustNamespace = "custom-trust-ns"
tm.DeepCopyInto(o)
}
return nil
})
// Custom namespace exists; so SSA Patch will create or update all resources successfully.
m.ExistsCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) (bool, error) {
switch obj.(type) {
case *corev1.Namespace:
return true, nil
}
return false, nil
})
},
wantConditions: []metav1.Condition{
{
Type: v1alpha1.Degraded,
Status: metav1.ConditionFalse,
Reason: v1alpha1.ReasonReady,
},
{
Type: v1alpha1.Ready,
Status: metav1.ConditionTrue,
Reason: v1alpha1.ReasonReady,
Message: "reconciliation successful",
},
},
},
}

for _, tt := range tests {
Expand Down
105 changes: 105 additions & 0 deletions pkg/controller/trustmanager/install_trustmanager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package trustmanager

import (
"context"
"reflect"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/openshift/cert-manager-operator/api/operator/v1alpha1"
"github.com/openshift/cert-manager-operator/pkg/controller/common/fakes"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func TestUpdateStatusObservedState(t *testing.T) {
t.Setenv(trustManagerImageNameEnvVarName, testImage)

// Observed status after sync from testTrustManager() defaults (empty status fields + default spec).
wantStatusSyncedFromDefaultSpec := v1alpha1.TrustManagerStatus{
TrustManagerImage: testImage,
TrustNamespace: defaultTrustNamespace,
SecretTargetsPolicy: "",
DefaultCAPackagePolicy: "",
FilterExpiredCertificatesPolicy: "",
}

tests := []struct {
name string
trustManager func() *v1alpha1.TrustManager
wantStatusUpdate int
wantStatus v1alpha1.TrustManagerStatus
}{
{
name: "updates all observed fields when status is empty",
trustManager: func() *v1alpha1.TrustManager {
return testTrustManager().Build()
},
wantStatusUpdate: 1,
wantStatus: wantStatusSyncedFromDefaultSpec,
},
{
name: "updates all observed fields for custom spec",
trustManager: func() *v1alpha1.TrustManager {
return testTrustManager().
WithTrustNamespace("custom-trust-ns").
WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"allowed-secret"}).
WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled).
WithFilterExpiredCertificates(v1alpha1.FilterExpiredCertificatesPolicyEnabled).
Build()
},
wantStatusUpdate: 1,
wantStatus: v1alpha1.TrustManagerStatus{
TrustManagerImage: testImage,
TrustNamespace: "custom-trust-ns",
SecretTargetsPolicy: v1alpha1.SecretTargetsPolicyCustom,
DefaultCAPackagePolicy: v1alpha1.DefaultCAPackagePolicyEnabled,
FilterExpiredCertificatesPolicy: v1alpha1.FilterExpiredCertificatesPolicyEnabled,
},
},
{
name: "no-op when observed state already matches spec and env",
trustManager: func() *v1alpha1.TrustManager {
tm := testTrustManager().Build()
tm.Status.TrustManagerImage = testImage
tm.Status.TrustNamespace = defaultTrustNamespace
tm.Status.SecretTargetsPolicy = tm.Spec.TrustManagerConfig.SecretTargets.Policy
tm.Status.DefaultCAPackagePolicy = tm.Spec.TrustManagerConfig.DefaultCAPackage.Policy
tm.Status.FilterExpiredCertificatesPolicy = tm.Spec.TrustManagerConfig.FilterExpiredCertificates
return tm
},
wantStatusUpdate: 0,
wantStatus: wantStatusSyncedFromDefaultSpec,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := testReconciler(t)
mock := &fakes.FakeCtrlClient{}
tm := tt.trustManager()

mock.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
switch o := obj.(type) {
case *v1alpha1.TrustManager:
tm.DeepCopyInto(o)
}
return nil
})
mock.StatusUpdateCalls(func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
return nil
})
r.CtrlClient = mock

if err := r.updateStatusObservedState(tm); err != nil {
t.Fatalf("updateStatusObservedState: %v", err)
}
if got := mock.StatusUpdateCallCount(); got != tt.wantStatusUpdate {
t.Errorf("StatusUpdateCallCount() = %d, want %d", got, tt.wantStatusUpdate)
}

if !reflect.DeepEqual(tm.Status, tt.wantStatus) {
t.Errorf("TrustManager.Status mismatch (-want +got):\n%s", cmp.Diff(tt.wantStatus, tm.Status))
}
})
}
}
12 changes: 5 additions & 7 deletions pkg/controller/trustmanager/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ func (b *trustManagerBuilder) WithFilterExpiredCertificates(policy v1alpha1.Filt
return b
}

func (b *trustManagerBuilder) WithDefaultCAPackage(policy v1alpha1.DefaultCAPackagePolicy) *trustManagerBuilder {
b.Spec.TrustManagerConfig.DefaultCAPackage.Policy = policy
return b
}

func (b *trustManagerBuilder) WithSecretTargets(policy v1alpha1.SecretTargetsPolicy, authorizedSecrets []string) *trustManagerBuilder {
b.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{
Policy: policy,
Expand All @@ -97,13 +102,6 @@ func (b *trustManagerBuilder) WithSecretTargets(policy v1alpha1.SecretTargetsPol
return b
}

func (b *trustManagerBuilder) WithDefaultCAPackage(policy v1alpha1.DefaultCAPackagePolicy) *trustManagerBuilder {
b.Spec.TrustManagerConfig.DefaultCAPackage = v1alpha1.DefaultCAPackageConfig{
Policy: policy,
}
return b
}

func (b *trustManagerBuilder) Build() *v1alpha1.TrustManager {
return b.TrustManager
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/controller/trustmanager/webhooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func getValidatingWebhookConfigObject(resourceLabels, resourceAnnotations map[st
return webhookConfig
}

// updateWebhookClientConfig sets the webhook clientConfig service name and namespace
// updateWebhookClientConfig sets the webhook clientConfig service name and namespace.
func updateWebhookClientConfig(webhookConfig *admissionregistrationv1.ValidatingWebhookConfiguration) {
for i := range webhookConfig.Webhooks {
if webhookConfig.Webhooks[i].ClientConfig.Service != nil {
Expand Down
Loading