Skip to content

Commit bc7d2da

Browse files
committed
Unit tests
1 parent 55cefeb commit bc7d2da

File tree

5 files changed

+325
-3
lines changed

5 files changed

+325
-3
lines changed

controllers/operator/clustermongodbrole_controller.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@ func (r *ClusterMongoDBRoleReconciler) Reconcile(ctx context.Context, request ct
4949
return reconcile.Result{RequeueAfter: time.Second * util.RetryTimeSec}, nil
5050
}
5151

52-
// res := mdbv1.RoleIsCorrectlyConfigured(role.Spec.MongoDBRole, "8.0.6")
53-
5452
log.Infow("ClusterMongoDBRole.Spec", "spec", role.Spec)
5553

5654
if !role.DeletionTimestamp.IsZero() {
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package operator
2+
3+
import (
4+
"context"
5+
"github.com/mongodb/mongodb-kubernetes/api/v1/mdb"
6+
rolev1 "github.com/mongodb/mongodb-kubernetes/api/v1/role"
7+
"github.com/mongodb/mongodb-kubernetes/controllers/operator/mock"
8+
"github.com/mongodb/mongodb-kubernetes/controllers/operator/workflow"
9+
"github.com/mongodb/mongodb-kubernetes/pkg/util"
10+
"github.com/stretchr/testify/assert"
11+
apiErrors "k8s.io/apimachinery/pkg/api/errors"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/types"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
16+
"testing"
17+
)
18+
19+
func TestReconcileClusterMongoDBRole(t *testing.T) {
20+
ctx := context.Background()
21+
role := DefaultClusterMongoDBRoleBuilder().Build()
22+
reconciler, _ := defaultRoleReconciler(ctx, role)
23+
24+
actual, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
25+
if err != nil {
26+
return
27+
}
28+
29+
expected, _ := workflow.OK().ReconcileResult()
30+
31+
assert.Nil(t, err, "there should be no error on successful reconciliation")
32+
assert.Equal(t, expected, actual, "there should be a successful reconciliation if the password is a valid reference")
33+
}
34+
35+
func TestEnsureFinalizer(t *testing.T) {
36+
ctx := context.Background()
37+
role := DefaultClusterMongoDBRoleBuilder().Build()
38+
reconciler, fakeClient := defaultRoleReconciler(ctx, role)
39+
40+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
41+
assert.NoError(t, err)
42+
43+
err = fakeClient.Get(ctx, types.NamespacedName{Name: role.Name}, role)
44+
assert.NoError(t, err)
45+
46+
assert.Contains(t, role.GetFinalizers(), util.RoleFinalizer, "the finalizer should be present")
47+
}
48+
49+
func TestRoleIsRemovedWhenNoReferences(t *testing.T) {
50+
ctx := context.Background()
51+
role := DefaultClusterMongoDBRoleBuilder().Build()
52+
reconciler, fakeClient := defaultRoleReconciler(ctx, role)
53+
54+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
55+
assert.NoError(t, err)
56+
57+
err = fakeClient.Delete(ctx, role)
58+
assert.NoError(t, err)
59+
60+
newResult, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
61+
62+
newExpected, _ := workflow.OK().ReconcileResult()
63+
64+
assert.Nil(t, err, "there should be no error on successful reconciliation")
65+
assert.Equal(t, newExpected, newResult, "there should be a successful reconciliation if the password is a valid reference")
66+
67+
err = fakeClient.Get(ctx, types.NamespacedName{Name: role.Name}, role)
68+
assert.True(t, apiErrors.IsNotFound(err), "the role should not exist")
69+
}
70+
71+
func TestRoleIsNotRemovedWhenReferenced(t *testing.T) {
72+
ctx := context.Background()
73+
role := DefaultClusterMongoDBRoleBuilder().Build()
74+
reconciler, fakeClient := defaultRoleReconciler(ctx, role)
75+
76+
_ = fakeClient.Create(ctx, DefaultReplicaSetBuilder().
77+
SetRoleRefs([]mdb.MongoDBRoleRef{
78+
{
79+
Name: role.Name,
80+
Kind: util.ClusterMongoDBRoleKind,
81+
},
82+
}).
83+
SetName("my-rs").Build())
84+
85+
// Add finalizer
86+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
87+
assert.NoError(t, err)
88+
89+
// Delete resource, should fail since it is still referenced
90+
err = fakeClient.Delete(ctx, role)
91+
assert.NoError(t, err)
92+
93+
// Should not remove the finalizer
94+
_, _ = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
95+
96+
err = fakeClient.Get(ctx, types.NamespacedName{Name: role.Name}, role)
97+
assert.NoError(t, err, "the role should still exist")
98+
assert.NotEmpty(t, role.GetFinalizers(), "the finalizer should still be present")
99+
}
100+
101+
func TestRoleIsRemovedAfterRemovingReference(t *testing.T) {
102+
ctx := context.Background()
103+
role := DefaultClusterMongoDBRoleBuilder().Build()
104+
mdbrs := DefaultReplicaSetBuilder().
105+
SetRoleRefs([]mdb.MongoDBRoleRef{
106+
{
107+
Name: role.Name,
108+
Kind: util.ClusterMongoDBRoleKind,
109+
},
110+
}).
111+
SetName("my-rs").Build()
112+
reconciler, fakeClient := defaultRoleReconciler(ctx, role)
113+
114+
_ = fakeClient.Create(ctx, mdbrs)
115+
116+
// Add finalizer
117+
_, _ = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
118+
119+
// Delete resource, should fail since it is still referenced
120+
_ = fakeClient.Delete(ctx, role)
121+
122+
// Should not remove the finalizer
123+
_, _ = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
124+
125+
err := fakeClient.Get(ctx, types.NamespacedName{Name: role.Name}, role)
126+
assert.NoError(t, err, "the role should still exist")
127+
128+
// Remove reference
129+
mdbrs.Spec.Security.RoleRefs = []mdb.MongoDBRoleRef{}
130+
err = fakeClient.Update(ctx, mdbrs)
131+
132+
// Should remove finalizer
133+
_, _ = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: types.NamespacedName{Name: role.Name}})
134+
135+
// Resource should be removed
136+
err = fakeClient.Get(ctx, types.NamespacedName{Name: role.Name}, role)
137+
assert.True(t, apiErrors.IsNotFound(err), "the role should not exist")
138+
139+
}
140+
141+
func defaultRoleReconciler(ctx context.Context, role *rolev1.ClusterMongoDBRole) (*ClusterMongoDBRoleReconciler, client.Client) {
142+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient(role)
143+
memberClusterMap := getFakeMultiClusterMap(omConnectionFactory)
144+
return newClusterMongoDBRoleReconciler(ctx, kubeClient, memberClusterMap), kubeClient
145+
}
146+
147+
type ClusterMongoDBRoleBuilder struct {
148+
name string
149+
finalizers []string
150+
annotations map[string]string
151+
mongoDBRole mdb.MongoDBRole
152+
}
153+
154+
func DefaultClusterMongoDBRoleBuilder() *ClusterMongoDBRoleBuilder {
155+
return &ClusterMongoDBRoleBuilder{
156+
name: "default-role",
157+
finalizers: []string{},
158+
mongoDBRole: mdb.MongoDBRole{
159+
Role: "default-role",
160+
AuthenticationRestrictions: nil,
161+
Db: "admin",
162+
Privileges: nil,
163+
Roles: []mdb.InheritedRole{
164+
{
165+
Role: "readWrite",
166+
Db: "admin",
167+
},
168+
},
169+
},
170+
annotations: map[string]string{},
171+
}
172+
}
173+
174+
func (b *ClusterMongoDBRoleBuilder) SetName(name string) *ClusterMongoDBRoleBuilder {
175+
b.name = name
176+
return b
177+
}
178+
179+
func (b *ClusterMongoDBRoleBuilder) AddFinalizer(finalizer string) *ClusterMongoDBRoleBuilder {
180+
b.finalizers = append(b.finalizers, finalizer)
181+
return b
182+
}
183+
184+
func (b *ClusterMongoDBRoleBuilder) SetMongoDBRole(role mdb.MongoDBRole) *ClusterMongoDBRoleBuilder {
185+
b.mongoDBRole = role
186+
return b
187+
}
188+
189+
func (b *ClusterMongoDBRoleBuilder) AddAnnotation(key, value string) *ClusterMongoDBRoleBuilder {
190+
b.annotations[key] = value
191+
return b
192+
}
193+
194+
func (b *ClusterMongoDBRoleBuilder) Build() *rolev1.ClusterMongoDBRole {
195+
return &rolev1.ClusterMongoDBRole{
196+
ObjectMeta: metav1.ObjectMeta{
197+
Name: b.name,
198+
Finalizers: b.finalizers,
199+
Annotations: b.annotations,
200+
},
201+
Spec: rolev1.ClusterMongoDBRoleSpec{
202+
MongoDBRole: b.mongoDBRole,
203+
},
204+
}
205+
}

controllers/operator/common_controller_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,115 @@ func TestReadSubjectNoCertificate(t *testing.T) {
265265
assertSubjectFromFileFails(t, "testdata/certificates/just_key")
266266
}
267267

268+
func TestFailWhenRoleAndRoleRefsAreConfigured(t *testing.T) {
269+
ctx := context.Background()
270+
customRole := mdbv1.MongoDBRole{
271+
Role: "foo",
272+
AuthenticationRestrictions: []mdbv1.AuthenticationRestriction{},
273+
Db: "admin",
274+
Roles: []mdbv1.InheritedRole{{
275+
Db: "admin",
276+
Role: "readWriteAnyDatabase",
277+
}},
278+
}
279+
roleResource := DefaultClusterMongoDBRoleBuilder().Build()
280+
roleRef := mdbv1.MongoDBRoleRef{
281+
Name: roleResource.Name,
282+
Kind: util.ClusterMongoDBRoleKind,
283+
}
284+
assert.Nil(t, customRole.Privileges)
285+
rs := DefaultReplicaSetBuilder().SetRoles([]mdbv1.MongoDBRole{customRole}).SetRoleRefs([]mdbv1.MongoDBRoleRef{roleRef}).Build()
286+
287+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient()
288+
controller := NewReconcileCommonController(ctx, kubeClient)
289+
mockOm, _ := prepareConnection(ctx, controller, omConnectionFactory.GetConnectionFunc, t)
290+
291+
result := controller.ensureRoles(ctx, rs.Spec.Security.Roles, rs.Spec.Security.RoleRefs, mockOm, kube.ObjectKeyFromApiObject(rs), &zap.SugaredLogger{})
292+
assert.False(t, result.IsOK())
293+
assert.Equal(t, status.PhaseFailed, result.Phase())
294+
295+
ac, err := mockOm.ReadAutomationConfig()
296+
assert.NoError(t, err)
297+
roles, ok := ac.Deployment["roles"].([]mdbv1.MongoDBRole)
298+
assert.False(t, ok)
299+
assert.Empty(t, roles)
300+
}
301+
302+
func TestRoleRefsAreAdded(t *testing.T) {
303+
ctx := context.Background()
304+
roleResource := DefaultClusterMongoDBRoleBuilder().Build()
305+
roleRef := mdbv1.MongoDBRoleRef{
306+
Name: roleResource.Name,
307+
Kind: util.ClusterMongoDBRoleKind,
308+
}
309+
rs := DefaultReplicaSetBuilder().SetRoleRefs([]mdbv1.MongoDBRoleRef{roleRef}).Build()
310+
311+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient()
312+
controller := NewReconcileCommonController(ctx, kubeClient)
313+
mockOm, _ := prepareConnection(ctx, controller, omConnectionFactory.GetConnectionFunc, t)
314+
315+
_ = kubeClient.Create(ctx, roleResource)
316+
317+
controller.ensureRoles(ctx, rs.Spec.Security.Roles, rs.Spec.Security.RoleRefs, mockOm, kube.ObjectKeyFromApiObject(rs), &zap.SugaredLogger{})
318+
319+
ac, err := mockOm.ReadAutomationConfig()
320+
assert.NoError(t, err)
321+
roles, ok := ac.Deployment["roles"].([]mdbv1.MongoDBRole)
322+
assert.True(t, ok)
323+
assert.NotNil(t, roles[0].Privileges)
324+
assert.Len(t, roles, 1)
325+
}
326+
327+
func TestErrorWhenRoleDoesNotExist(t *testing.T) {
328+
ctx := context.Background()
329+
roleResource := DefaultClusterMongoDBRoleBuilder().Build()
330+
roleRef := mdbv1.MongoDBRoleRef{
331+
Name: roleResource.Name,
332+
Kind: "WrongMongoDBRoleReference",
333+
}
334+
rs := DefaultReplicaSetBuilder().SetRoleRefs([]mdbv1.MongoDBRoleRef{roleRef}).Build()
335+
336+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient()
337+
controller := NewReconcileCommonController(ctx, kubeClient)
338+
mockOm, _ := prepareConnection(ctx, controller, omConnectionFactory.GetConnectionFunc, t)
339+
340+
_ = kubeClient.Create(ctx, roleResource)
341+
342+
result := controller.ensureRoles(ctx, rs.Spec.Security.Roles, rs.Spec.Security.RoleRefs, mockOm, kube.ObjectKeyFromApiObject(rs), &zap.SugaredLogger{})
343+
assert.False(t, result.IsOK())
344+
assert.Equal(t, status.PhaseFailed, result.Phase())
345+
346+
ac, err := mockOm.ReadAutomationConfig()
347+
assert.NoError(t, err)
348+
roles, ok := ac.Deployment["roles"].([]mdbv1.MongoDBRole)
349+
assert.False(t, ok)
350+
assert.Empty(t, roles)
351+
}
352+
353+
func TestErrorWhenRoleRefIsWrong(t *testing.T) {
354+
ctx := context.Background()
355+
roleResource := DefaultClusterMongoDBRoleBuilder().Build()
356+
roleRef := mdbv1.MongoDBRoleRef{
357+
Name: roleResource.Name,
358+
Kind: util.ClusterMongoDBRoleKind,
359+
}
360+
rs := DefaultReplicaSetBuilder().SetRoleRefs([]mdbv1.MongoDBRoleRef{roleRef}).Build()
361+
362+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient()
363+
controller := NewReconcileCommonController(ctx, kubeClient)
364+
mockOm, _ := prepareConnection(ctx, controller, omConnectionFactory.GetConnectionFunc, t)
365+
366+
result := controller.ensureRoles(ctx, rs.Spec.Security.Roles, rs.Spec.Security.RoleRefs, mockOm, kube.ObjectKeyFromApiObject(rs), &zap.SugaredLogger{})
367+
assert.False(t, result.IsOK())
368+
assert.Equal(t, status.PhaseFailed, result.Phase())
369+
370+
ac, err := mockOm.ReadAutomationConfig()
371+
assert.NoError(t, err)
372+
roles, ok := ac.Deployment["roles"].([]mdbv1.MongoDBRole)
373+
assert.False(t, ok)
374+
assert.Empty(t, roles)
375+
}
376+
268377
func TestDontSendNilPrivileges(t *testing.T) {
269378
ctx := context.Background()
270379
customRole := mdbv1.MongoDBRole{

controllers/operator/mongodbreplicaset_controller_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,14 @@ func (b *ReplicaSetBuilder) SetRoles(roles []mdbv1.MongoDBRole) *ReplicaSetBuild
10811081
return b
10821082
}
10831083

1084+
func (b *ReplicaSetBuilder) SetRoleRefs(roleRefs []mdbv1.MongoDBRoleRef) *ReplicaSetBuilder {
1085+
if b.Spec.Security == nil {
1086+
b.Spec.Security = &mdbv1.Security{}
1087+
}
1088+
b.Spec.Security.RoleRefs = roleRefs
1089+
return b
1090+
}
1091+
10841092
func (b *ReplicaSetBuilder) EnableAuth() *ReplicaSetBuilder {
10851093
b.Spec.Security.Authentication.Enabled = true
10861094
return b

controllers/operator/mongodbuser_controller_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package operator
22

33
import (
44
"context"
5+
apiErrors "k8s.io/apimachinery/pkg/api/errors"
56
"testing"
67
"time"
78

@@ -497,7 +498,8 @@ func TestFinalizerIsRemoved_WhenUserIsDeleted(t *testing.T) {
497498
assert.Nil(t, err, "there should be no error on successful reconciliation")
498499
assert.Equal(t, newExpected, newResult, "there should be a successful reconciliation if the password is a valid reference")
499500

500-
assert.Empty(t, user.GetFinalizers())
501+
err = client.Get(ctx, kube.ObjectKey(user.Namespace, user.Name), user)
502+
assert.True(t, apiErrors.IsNotFound(err), "the user should not exist")
501503
}
502504

503505
// BuildAuthenticationEnabledReplicaSet returns a AutomationConfig after creating a Replica Set with a set of

0 commit comments

Comments
 (0)