Skip to content

Commit b2d5cd7

Browse files
committed
Add unit tests for trust-manager
Signed-off-by: chiragkyal <ckyal@redhat.com>
1 parent c09f913 commit b2d5cd7

9 files changed

Lines changed: 2771 additions & 0 deletions

File tree

pkg/controller/trustmanager/certificates_test.go

Lines changed: 424 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
package trustmanager
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
corev1 "k8s.io/api/core/v1"
9+
apierrors "k8s.io/apimachinery/pkg/api/errors"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/types"
12+
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
16+
"github.com/openshift/cert-manager-operator/api/operator/v1alpha1"
17+
"github.com/openshift/cert-manager-operator/pkg/controller/common/fakes"
18+
)
19+
20+
func TestReconcile(t *testing.T) {
21+
tests := []struct {
22+
name string
23+
preReq func(*Reconciler, *fakes.FakeCtrlClient)
24+
wantErr string
25+
}{
26+
{
27+
name: "resource not found returns no error",
28+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
29+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
30+
return apierrors.NewNotFound(v1alpha1.Resource("trustmanager"), trustManagerObjectName)
31+
})
32+
},
33+
},
34+
{
35+
name: "failed to fetch resource propagates error",
36+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
37+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
38+
switch obj.(type) {
39+
case *v1alpha1.TrustManager:
40+
return apierrors.NewBadRequest("test error")
41+
}
42+
return nil
43+
})
44+
},
45+
wantErr: "failed to fetch trustmanager.openshift.operator.io",
46+
},
47+
{
48+
name: "resource marked for deletion without finalizer",
49+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
50+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
51+
switch o := obj.(type) {
52+
case *v1alpha1.TrustManager:
53+
tm := testTrustManager().Build()
54+
tm.DeletionTimestamp = &metav1.Time{Time: time.Now()}
55+
tm.DeepCopyInto(o)
56+
}
57+
return nil
58+
})
59+
},
60+
},
61+
{
62+
name: "remove finalizer fails on deletion",
63+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
64+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
65+
switch o := obj.(type) {
66+
case *v1alpha1.TrustManager:
67+
tm := testTrustManager().Build()
68+
tm.DeletionTimestamp = &metav1.Time{Time: time.Now()}
69+
tm.Finalizers = []string{finalizer}
70+
tm.DeepCopyInto(o)
71+
}
72+
return nil
73+
})
74+
m.UpdateWithRetryCalls(func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
75+
return errTestClient
76+
})
77+
},
78+
wantErr: "failed to remove finalizers",
79+
},
80+
{
81+
name: "adding finalizer fails",
82+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
83+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
84+
switch o := obj.(type) {
85+
case *v1alpha1.TrustManager:
86+
tm := testTrustManager().Build()
87+
tm.DeepCopyInto(o)
88+
}
89+
return nil
90+
})
91+
m.UpdateWithRetryCalls(func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
92+
return errTestClient
93+
})
94+
},
95+
wantErr: `failed to update "/cluster" trustmanager.openshift.operator.io with finalizers`,
96+
},
97+
{
98+
name: "status update failure",
99+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
100+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
101+
switch o := obj.(type) {
102+
case *v1alpha1.TrustManager:
103+
tm := testTrustManager().Build()
104+
tm.Spec.TrustManagerConfig = v1alpha1.TrustManagerConfig{}
105+
tm.Finalizers = []string{finalizer}
106+
tm.DeepCopyInto(o)
107+
}
108+
return nil
109+
})
110+
m.StatusUpdateCalls(func(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error {
111+
return apierrors.NewBadRequest("test error")
112+
})
113+
},
114+
wantErr: "failed to update cluster status",
115+
},
116+
}
117+
118+
for _, tt := range tests {
119+
t.Run(tt.name, func(t *testing.T) {
120+
r := testReconciler(t)
121+
mock := &fakes.FakeCtrlClient{}
122+
if tt.preReq != nil {
123+
tt.preReq(r, mock)
124+
}
125+
r.CtrlClient = mock
126+
127+
_, err := r.Reconcile(context.Background(),
128+
ctrl.Request{
129+
NamespacedName: types.NamespacedName{Name: trustManagerObjectName},
130+
},
131+
)
132+
assertError(t, err, tt.wantErr)
133+
})
134+
}
135+
}
136+
137+
func TestProcessReconcileRequest(t *testing.T) {
138+
t.Setenv(trustManagerImageNameEnvVarName, testImage)
139+
140+
tests := []struct {
141+
name string
142+
getTrustManager func() *v1alpha1.TrustManager
143+
preReq func(*Reconciler, *fakes.FakeCtrlClient)
144+
wantConditions []metav1.Condition
145+
wantErr string
146+
}{
147+
{
148+
name: "successful reconciliation sets ready true",
149+
getTrustManager: func() *v1alpha1.TrustManager {
150+
return testTrustManager().Build()
151+
},
152+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
153+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
154+
switch o := obj.(type) {
155+
case *v1alpha1.TrustManager:
156+
testTrustManager().Build().DeepCopyInto(o)
157+
}
158+
return nil
159+
})
160+
// Namespace exists; all other resources return not-found so they
161+
// are created via SSA Patch (which succeeds by default).
162+
m.ExistsCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) (bool, error) {
163+
switch obj.(type) {
164+
case *corev1.Namespace:
165+
return true, nil
166+
}
167+
return false, nil
168+
})
169+
},
170+
wantConditions: []metav1.Condition{
171+
{
172+
Type: v1alpha1.Degraded,
173+
Status: metav1.ConditionFalse,
174+
Reason: v1alpha1.ReasonReady,
175+
},
176+
{
177+
Type: v1alpha1.Ready,
178+
Status: metav1.ConditionTrue,
179+
Reason: v1alpha1.ReasonReady,
180+
Message: "reconciliation successful",
181+
},
182+
},
183+
},
184+
{
185+
name: "irrecoverable error sets degraded true",
186+
getTrustManager: func() *v1alpha1.TrustManager {
187+
// Empty TrustManagerConfig triggers validateTrustManagerConfig failure,
188+
// which is wrapped as an irrecoverable error in reconcileTrustManagerDeployment.
189+
tm := testTrustManager().Build()
190+
tm.Spec.TrustManagerConfig = v1alpha1.TrustManagerConfig{}
191+
return tm
192+
},
193+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
194+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
195+
switch o := obj.(type) {
196+
case *v1alpha1.TrustManager:
197+
tm := testTrustManager().Build()
198+
tm.Spec.TrustManagerConfig = v1alpha1.TrustManagerConfig{}
199+
tm.DeepCopyInto(o)
200+
}
201+
return nil
202+
})
203+
},
204+
wantConditions: []metav1.Condition{
205+
{
206+
Type: v1alpha1.Degraded,
207+
Status: metav1.ConditionTrue,
208+
Reason: v1alpha1.ReasonFailed,
209+
},
210+
{
211+
Type: v1alpha1.Ready,
212+
Status: metav1.ConditionFalse,
213+
Reason: v1alpha1.ReasonReady,
214+
},
215+
},
216+
},
217+
{
218+
name: "recoverable error sets in progress",
219+
getTrustManager: func() *v1alpha1.TrustManager {
220+
return testTrustManager().Build()
221+
},
222+
preReq: func(r *Reconciler, m *fakes.FakeCtrlClient) {
223+
m.GetCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
224+
switch o := obj.(type) {
225+
case *v1alpha1.TrustManager:
226+
testTrustManager().Build().DeepCopyInto(o)
227+
}
228+
return nil
229+
})
230+
// Namespace Exists succeeds (passes validateTrustNamespace), but
231+
// ServiceAccount Exists returns a FromClientError
232+
m.ExistsCalls(func(ctx context.Context, key client.ObjectKey, obj client.Object) (bool, error) {
233+
switch obj.(type) {
234+
case *corev1.Namespace:
235+
return true, nil
236+
}
237+
return false, errTestClient
238+
})
239+
},
240+
wantConditions: []metav1.Condition{
241+
{
242+
Type: v1alpha1.Degraded,
243+
Status: metav1.ConditionFalse,
244+
Reason: v1alpha1.ReasonReady,
245+
},
246+
{
247+
Type: v1alpha1.Ready,
248+
Status: metav1.ConditionFalse,
249+
Reason: v1alpha1.ReasonInProgress,
250+
},
251+
},
252+
wantErr: "failed to get serviceaccount",
253+
},
254+
}
255+
256+
for _, tt := range tests {
257+
t.Run(tt.name, func(t *testing.T) {
258+
r := testReconciler(t)
259+
mock := &fakes.FakeCtrlClient{}
260+
if tt.preReq != nil {
261+
tt.preReq(r, mock)
262+
}
263+
r.CtrlClient = mock
264+
265+
tm := tt.getTrustManager()
266+
_, err := r.processReconcileRequest(tm, types.NamespacedName{Name: tm.GetName()})
267+
assertError(t, err, tt.wantErr)
268+
269+
for _, want := range tt.wantConditions {
270+
found := false
271+
for _, got := range tm.Status.Conditions {
272+
if got.Type == want.Type {
273+
found = true
274+
if got.Status != want.Status {
275+
t.Errorf("condition %s: expected status %s, got %s", want.Type, want.Status, got.Status)
276+
}
277+
if got.Reason != want.Reason {
278+
t.Errorf("condition %s: expected reason %s, got %s", want.Type, want.Reason, got.Reason)
279+
}
280+
if want.Message != "" && got.Message != want.Message {
281+
t.Errorf("condition %s: expected message %q, got %q", want.Type, want.Message, got.Message)
282+
}
283+
}
284+
}
285+
if !found {
286+
t.Errorf("expected condition %s not found in status conditions %v", want.Type, tm.Status.Conditions)
287+
}
288+
}
289+
})
290+
}
291+
}

0 commit comments

Comments
 (0)