Skip to content

Commit 16e1d78

Browse files
authored
CLOUDP-312879: Add search reconciler test (#232)
# Summary This pull request adds unit tests for the `MongoDBSearchReconciler` in the `operator` package. These tests cover various reconciliation scenarios, including success cases, failure cases, and edge cases. Additionally, helper functions and mock setups are added. ### Unit Tests for `MongoDBSearchReconciler`: * **Basic Reconciliation Scenarios:** - Added tests for successful reconciliation (`TestMongoDBSearchReconcile_Success`) and scenarios where the `MongoDBSearch` resource or its source is missing (`TestMongoDBSearchReconcile_NotFound`, `TestMongoDBSearchReconcile_MissingSource`). * **Failure Cases:** - Implemented tests to validate failure conditions, such as unsupported MongoDB versions (`TestMongoDBSearchReconcile_InvalidVersion`), TLS-enabled configurations (`TestMongoDBSearchReconcile_TLSNotSupported`), and multiple `MongoDBSearch` resources referencing the same MongoDB instance (`TestMongoDBSearchReconcile_MultipleSearchResources`). ### Helper Functions and Mock Setup: * **Helper Functions:** - Added helper functions to create mock `MongoDBCommunity` and `MongoDBSearch` resources (`newMongoDBCommunity`, `newMongoDBSearch`) and build expected configurations (`buildExpectedMongotConfig`). ## Proof of Work Tests Pass ## Checklist - [x] Have you linked a jira ticket and/or is the ticket in the title? - [x] Have you checked whether your jira ticket required DOCSP changes? - [x] Have you checked for release_note changes?
1 parent 4aca390 commit 16e1d78

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed
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+
"fmt"
6+
"testing"
7+
8+
"github.com/ghodss/yaml"
9+
"github.com/stretchr/testify/assert"
10+
"k8s.io/apimachinery/pkg/types"
11+
"k8s.io/client-go/util/workqueue"
12+
"sigs.k8s.io/controller-runtime/pkg/client"
13+
"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
14+
"sigs.k8s.io/controller-runtime/pkg/event"
15+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
16+
17+
appsv1 "k8s.io/api/apps/v1"
18+
corev1 "k8s.io/api/core/v1"
19+
apiErrors "k8s.io/apimachinery/pkg/api/errors"
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
22+
searchv1 "github.com/mongodb/mongodb-kubernetes/api/v1/search"
23+
"github.com/mongodb/mongodb-kubernetes/api/v1/status"
24+
userv1 "github.com/mongodb/mongodb-kubernetes/api/v1/user"
25+
"github.com/mongodb/mongodb-kubernetes/controllers/operator/mock"
26+
"github.com/mongodb/mongodb-kubernetes/controllers/operator/workflow"
27+
"github.com/mongodb/mongodb-kubernetes/controllers/search_controller"
28+
mdbcv1 "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/api/v1"
29+
"github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/mongot"
30+
)
31+
32+
func newMongoDBCommunity(name, namespace string) *mdbcv1.MongoDBCommunity {
33+
return &mdbcv1.MongoDBCommunity{
34+
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace},
35+
Spec: mdbcv1.MongoDBCommunitySpec{
36+
Type: mdbcv1.ReplicaSet,
37+
Members: 1,
38+
Version: "8.0",
39+
},
40+
}
41+
}
42+
43+
func newMongoDBSearch(name, namespace, mdbcName string) *searchv1.MongoDBSearch {
44+
return &searchv1.MongoDBSearch{
45+
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace},
46+
Spec: searchv1.MongoDBSearchSpec{
47+
Source: &searchv1.MongoDBSource{
48+
MongoDBResourceRef: &userv1.MongoDBResourceRef{Name: mdbcName},
49+
},
50+
},
51+
}
52+
}
53+
54+
func newSearchReconciler(
55+
mdbc *mdbcv1.MongoDBCommunity,
56+
searches ...*searchv1.MongoDBSearch,
57+
) (*MongoDBSearchReconciler, client.Client) {
58+
builder := mock.NewEmptyFakeClientBuilder()
59+
builder.WithIndex(&searchv1.MongoDBSearch{}, search_controller.MongoDBSearchIndexFieldName, mdbcSearchIndexBuilder)
60+
61+
if mdbc != nil {
62+
builder.WithObjects(mdbc)
63+
}
64+
65+
for _, search := range searches {
66+
if search != nil {
67+
builder.WithObjects(search)
68+
}
69+
}
70+
71+
fakeClient := builder.Build()
72+
return newMongoDBSearchReconciler(fakeClient, search_controller.OperatorSearchConfig{}), fakeClient
73+
}
74+
75+
func buildExpectedMongotConfig(search *searchv1.MongoDBSearch, mdbc *mdbcv1.MongoDBCommunity) mongot.Config {
76+
return mongot.Config{CommunityPrivatePreview: mongot.CommunityPrivatePreview{
77+
MongodHostAndPort: fmt.Sprintf(
78+
"%s.%s.svc.cluster.local:%d",
79+
mdbc.ServiceName(), mdbc.Namespace,
80+
mdbc.GetMongodConfiguration().GetDBPort(),
81+
),
82+
QueryServerAddress: fmt.Sprintf("localhost:%d", search.GetMongotPort()),
83+
KeyFilePath: "/mongot/keyfile/keyfile",
84+
DataPath: "/mongot/data/config.yml",
85+
Metrics: mongot.Metrics{
86+
Enabled: true,
87+
Address: fmt.Sprintf("localhost:%d", search.GetMongotMetricsPort()),
88+
},
89+
Logging: mongot.Logging{Verbosity: "DEBUG"},
90+
}}
91+
}
92+
93+
func TestMongoDBSearchReconcile_NotFound(t *testing.T) {
94+
ctx := context.Background()
95+
reconciler, _ := newSearchReconciler(nil, nil)
96+
97+
res, err := reconciler.Reconcile(
98+
ctx,
99+
reconcile.Request{NamespacedName: types.NamespacedName{Name: "missing", Namespace: "test"}},
100+
)
101+
102+
assert.Error(t, err)
103+
assert.True(t, apiErrors.IsNotFound(err))
104+
assert.Equal(t, reconcile.Result{}, res)
105+
}
106+
107+
func TestMongoDBSearchReconcile_MissingSource(t *testing.T) {
108+
ctx := context.Background()
109+
search := newMongoDBSearch("search", mock.TestNamespace, "source")
110+
reconciler, _ := newSearchReconciler(nil, search)
111+
112+
res, err := reconciler.Reconcile(
113+
ctx,
114+
reconcile.Request{NamespacedName: types.NamespacedName{Name: search.Name, Namespace: search.Namespace}},
115+
)
116+
117+
assert.Error(t, err)
118+
assert.True(t, res.RequeueAfter > 0)
119+
}
120+
121+
func TestMongoDBSearchReconcile_Success(t *testing.T) {
122+
ctx := context.Background()
123+
search := newMongoDBSearch("search", mock.TestNamespace, "mdb")
124+
mdbc := newMongoDBCommunity("mdb", mock.TestNamespace)
125+
reconciler, c := newSearchReconciler(mdbc, search)
126+
127+
res, err := reconciler.Reconcile(
128+
ctx,
129+
reconcile.Request{NamespacedName: types.NamespacedName{Name: search.Name, Namespace: search.Namespace}},
130+
)
131+
expected, _ := workflow.OK().ReconcileResult()
132+
assert.NoError(t, err)
133+
assert.Equal(t, expected, res)
134+
135+
svc := &corev1.Service{}
136+
err = c.Get(ctx, search.SearchServiceNamespacedName(), svc)
137+
assert.NoError(t, err)
138+
139+
cm := &corev1.ConfigMap{}
140+
err = c.Get(ctx, search.MongotConfigConfigMapNamespacedName(), cm)
141+
assert.NoError(t, err)
142+
expectedConfig := buildExpectedMongotConfig(search, mdbc)
143+
configYaml, err := yaml.Marshal(expectedConfig)
144+
assert.NoError(t, err)
145+
assert.Equal(t, string(configYaml), cm.Data["config.yml"])
146+
147+
sts := &appsv1.StatefulSet{}
148+
err = c.Get(ctx, search.StatefulSetNamespacedName(), sts)
149+
assert.NoError(t, err)
150+
151+
queue := controllertest.Queue{Interface: workqueue.New()}
152+
reconciler.mdbcWatcher.Create(ctx, event.CreateEvent{Object: mdbc}, &queue)
153+
assert.Equal(t, 1, queue.Len())
154+
}
155+
156+
func checkSearchReconcileFailed(
157+
ctx context.Context,
158+
t *testing.T,
159+
reconciler *MongoDBSearchReconciler,
160+
c client.Client,
161+
search *searchv1.MongoDBSearch,
162+
expectedMsg string,
163+
) {
164+
res, err := reconciler.Reconcile(
165+
ctx,
166+
reconcile.Request{NamespacedName: types.NamespacedName{Name: search.Name, Namespace: search.Namespace}},
167+
)
168+
assert.NoError(t, err)
169+
assert.True(t, res.RequeueAfter > 0)
170+
171+
updated := &searchv1.MongoDBSearch{}
172+
assert.NoError(t, c.Get(ctx, types.NamespacedName{Name: search.Name, Namespace: search.Namespace}, updated))
173+
assert.Equal(t, status.PhaseFailed, updated.Status.Phase)
174+
assert.Contains(t, updated.Status.Message, expectedMsg)
175+
}
176+
177+
func TestMongoDBSearchReconcile_InvalidVersion(t *testing.T) {
178+
ctx := context.Background()
179+
search := newMongoDBSearch("search", mock.TestNamespace, "mdb")
180+
mdbc := newMongoDBCommunity("mdb", mock.TestNamespace)
181+
mdbc.Spec.Version = "6.0"
182+
reconciler, c := newSearchReconciler(mdbc, search)
183+
184+
checkSearchReconcileFailed(ctx, t, reconciler, c, search, "MongoDB version")
185+
}
186+
187+
func TestMongoDBSearchReconcile_TLSNotSupported(t *testing.T) {
188+
ctx := context.Background()
189+
search := newMongoDBSearch("search", mock.TestNamespace, "mdb")
190+
mdbc := newMongoDBCommunity("mdb", mock.TestNamespace)
191+
mdbc.Spec.Security.TLS.Enabled = true
192+
reconciler, c := newSearchReconciler(mdbc, search)
193+
194+
checkSearchReconcileFailed(ctx, t, reconciler, c, search, "TLS-enabled")
195+
}
196+
197+
func TestMongoDBSearchReconcile_MultipleSearchResources(t *testing.T) {
198+
ctx := context.Background()
199+
search1 := newMongoDBSearch("search1", mock.TestNamespace, "mdb")
200+
search2 := newMongoDBSearch("search2", mock.TestNamespace, "mdb")
201+
mdbc := newMongoDBCommunity("mdb", mock.TestNamespace)
202+
reconciler, c := newSearchReconciler(mdbc, search1, search2)
203+
204+
checkSearchReconcileFailed(ctx, t, reconciler, c, search1, "multiple MongoDBSearch")
205+
}

0 commit comments

Comments
 (0)