Skip to content

Commit b8205d9

Browse files
committed
First test correctly failing
1 parent cc67732 commit b8205d9

File tree

3 files changed

+118
-22
lines changed

3 files changed

+118
-22
lines changed

api/v1/mdb/mongodb_validation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ func additionalMongodConfig(ms MongoDbSpec) v1.ValidationResult {
327327
}
328328

329329
func replicasetMemberIsSpecified(ms MongoDbSpec) v1.ValidationResult {
330-
if ms.ResourceType == ReplicaSet && ms.Members == 0 {
330+
if ms.ResourceType == ReplicaSet && !ms.IsMultiCluster() && ms.Members == 0 {
331331
return v1.ValidationError("'spec.members' must be specified if type of MongoDB is %s", ms.ResourceType)
332332
}
333333
return v1.ValidationSuccess()

api/v1/mdb/mongodbbuilder.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,16 @@ func NewDefaultReplicaSetBuilder() *MongoDBBuilder {
2424
}
2525

2626
func NewDefaultMultiReplicaSetBuilder() *MongoDBBuilder {
27-
return defaultMongoDB(ReplicaSet).
28-
SetMultiClusterTopology().
29-
SetDefaultClusterSpecList()
27+
b := defaultMongoDB(ReplicaSet).
28+
SetMultiClusterTopology()
29+
30+
// Set test OpsManager config and credentials (matching multi-cluster test fixtures)
31+
b.mdb.Spec.OpsManagerConfig = &PrivateCloudConfig{
32+
ConfigMapRef: ConfigMapRef{Name: "my-project"},
33+
}
34+
b.mdb.Spec.Credentials = "my-credentials"
35+
36+
return b
3037
}
3138

3239
func NewDefaultShardedClusterBuilder() *MongoDBBuilder {
@@ -288,6 +295,16 @@ func (b *MongoDBBuilder) SetDefaultClusterSpecList() *MongoDBBuilder {
288295
return b
289296
}
290297

298+
func (b *MongoDBBuilder) SetClusterSpectList(clusters []string) *MongoDBBuilder {
299+
for _, e := range clusters {
300+
b.mdb.Spec.ClusterSpecList = append(b.mdb.Spec.ClusterSpecList, ClusterSpecItem{
301+
ClusterName: e,
302+
Members: 1, // number of cluster members b/w 1 to 5
303+
})
304+
}
305+
return b
306+
}
307+
291308
func (b *MongoDBBuilder) SetAllClusterSpecLists(clusterSpecList ClusterSpecList) *MongoDBBuilder {
292309
b.mdb.Spec.ShardSpec.ClusterSpecList = clusterSpecList
293310
b.mdb.Spec.ConfigSrvSpec.ClusterSpecList = clusterSpecList
@@ -314,7 +331,7 @@ func defaultMongoDB(resourceType ResourceType) *MongoDBBuilder {
314331
ResourceType: resourceType,
315332
},
316333
}
317-
mdb := &MongoDB{Spec: spec, ObjectMeta: metav1.ObjectMeta{Name: "test-mdb", Namespace: "testNS"}}
334+
mdb := &MongoDB{Spec: spec, ObjectMeta: metav1.ObjectMeta{Name: "test-mdb", Namespace: "my-namespace"}}
318335
mdb.InitDefaults()
319336
return &MongoDBBuilder{mdb}
320337
}

controllers/operator/mongodbreplicaset_controller_multi_test.go

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,136 @@ package operator
22

33
import (
44
"context"
5+
"fmt"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
"go.uber.org/zap"
11+
"sigs.k8s.io/controller-runtime/pkg/client"
12+
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
13+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
14+
15+
appsv1 "k8s.io/api/apps/v1"
16+
517
mdbv1 "github.com/mongodb/mongodb-kubernetes/api/v1/mdb"
618
"github.com/mongodb/mongodb-kubernetes/controllers/om"
719
"github.com/mongodb/mongodb-kubernetes/controllers/operator/mock"
820
kubernetesClient "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/kube/client"
921
"github.com/mongodb/mongodb-kubernetes/pkg/images"
1022
"github.com/mongodb/mongodb-kubernetes/pkg/kube"
1123
"github.com/mongodb/mongodb-kubernetes/pkg/util"
12-
"github.com/stretchr/testify/assert"
13-
"sigs.k8s.io/controller-runtime/pkg/client"
14-
"sigs.k8s.io/controller-runtime/pkg/reconcile"
15-
"testing"
1624
)
1725

18-
// NedDefaultMultiReplicaSetBuilder
26+
func init() {
27+
logger, _ := zap.NewDevelopment()
28+
zap.ReplaceGlobals(logger)
29+
}
30+
31+
var multiClusters = []string{"api1.kube.com", "api2.kube.com", "api3.kube.com"}
1932

2033
func TestCreateMultiClusterReplicaSet(t *testing.T) {
2134
ctx := context.Background()
22-
rs := mdbv1.NewDefaultMultiReplicaSetBuilder().Build()
2335

24-
reconciler, client, _, _ := defaultMultiClusterReplicaSetReconciler(ctx, nil, "", "", mrs)
25-
checkMultiReplicaSetReconcileSuccessful(ctx, t, reconciler, rs, client, false)
36+
rs := mdbv1.NewDefaultMultiReplicaSetBuilder().
37+
SetClusterSpectList(multiClusters).
38+
Build()
39+
40+
reconciler, kubeClient, memberClients, omConnectionFactory := defaultMultiClusterReplicaSetReconciler(ctx, nil, "", "", rs)
41+
checkMultiReplicaSetReconcileSuccessful(ctx, t, reconciler, rs, kubeClient, false)
42+
43+
// Verify StatefulSets exist in each member cluster
44+
for i, clusterName := range multiClusters {
45+
memberClient := memberClients[clusterName]
46+
sts := appsv1.StatefulSet{}
47+
stsName := fmt.Sprintf("%s-%d", rs.Name, i)
48+
err := memberClient.Get(ctx, kube.ObjectKey(rs.Namespace, stsName), &sts)
49+
require.NoError(t, err, "StatefulSet should exist in cluster %s", clusterName)
50+
assert.Equal(t, int32(1), *sts.Spec.Replicas, "Replicas in %s", clusterName)
51+
}
52+
53+
// Verify OM automation config has all processes
54+
processes := omConnectionFactory.GetConnection().(*om.MockedOmConnection).GetProcesses()
55+
assert.Len(t, processes, 3)
2656
}
2757

28-
func checkMultiReplicaSetReconcileSuccessful(ctx context.Context, t *testing.T, reconciler reconcile.Reconciler, m *mdbv1.MongoDB, client client.Client, shouldRequeue bool) {
58+
// Helper functions below
59+
60+
func checkMultiReplicaSetReconcileSuccessful(
61+
ctx context.Context,
62+
t *testing.T,
63+
reconciler reconcile.Reconciler,
64+
m *mdbv1.MongoDB,
65+
client client.Client,
66+
shouldRequeue bool,
67+
) {
2968
err := client.Update(ctx, m)
3069
assert.NoError(t, err)
3170

3271
result, e := reconciler.Reconcile(ctx, requestFromObject(m))
3372
assert.NoError(t, e)
73+
3474
if shouldRequeue {
3575
assert.True(t, result.Requeue || result.RequeueAfter > 0)
3676
} else {
3777
assert.Equal(t, reconcile.Result{RequeueAfter: util.TWENTY_FOUR_HOURS}, result)
3878
}
3979

40-
// fetch the last updates as the reconciliation loop can update the mdb resource.
4180
err = client.Get(ctx, kube.ObjectKey(m.Namespace, m.Name), m)
4281
assert.NoError(t, err)
4382
}
4483

45-
func multiClusterReplicaSetReconciler(ctx context.Context, imageUrls images.ImageUrls, initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion string, m *mdbv1.MongoDB) (*ReconcileMongoDbReplicaSet, kubernetesClient.Client, map[string]client.Client, *om.CachedOMConnectionFactory) {
46-
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient(m)
47-
memberClusterMap := getFakeMultiClusterMap(omConnectionFactory)
48-
return newReplicaSetReconciler(ctx, kubeClient, imageUrls, initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion, false, false, memberClusterMap, omConnectionFactory.GetConnectionFunc), kubeClient, memberClusterMap, omConnectionFactory
84+
func multiClusterReplicaSetReconciler(
85+
ctx context.Context,
86+
imageUrls images.ImageUrls,
87+
initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion string,
88+
rs *mdbv1.MongoDB,
89+
) (*ReconcileMongoDbReplicaSet, kubernetesClient.Client, map[string]client.Client, *om.CachedOMConnectionFactory) {
90+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient(rs)
91+
memberClusterMap := getMockMultiClusterMap(omConnectionFactory)
92+
93+
return newReplicaSetReconciler(
94+
ctx,
95+
kubeClient,
96+
imageUrls,
97+
initDatabaseNonStaticImageVersion,
98+
databaseNonStaticImageVersion,
99+
false,
100+
false,
101+
memberClusterMap,
102+
omConnectionFactory.GetConnectionFunc,
103+
), kubeClient, memberClusterMap, omConnectionFactory
49104
}
50105

51-
func defaultMultiClusterReplicaSetReconciler(ctx context.Context, imageUrls images.ImageUrls, initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion string, rs *mdbv1.MongoDB) (*ReconcileMongoDbReplicaSet, kubernetesClient.Client, map[string]client.Client, *om.CachedOMConnectionFactory) {
52-
multiReplicaSetController, client, clusterMap, omConnectionFactory := multiClusterReplicaSetReconciler(ctx, imageUrls, initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion, rs)
106+
func defaultMultiClusterReplicaSetReconciler(
107+
ctx context.Context,
108+
imageUrls images.ImageUrls,
109+
initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion string,
110+
rs *mdbv1.MongoDB,
111+
) (*ReconcileMongoDbReplicaSet, kubernetesClient.Client, map[string]client.Client, *om.CachedOMConnectionFactory) {
112+
multiReplicaSetController, client, clusterMap, omConnectionFactory := multiClusterReplicaSetReconciler(
113+
ctx, imageUrls, initDatabaseNonStaticImageVersion, databaseNonStaticImageVersion, rs,
114+
)
115+
53116
omConnectionFactory.SetPostCreateHook(func(connection om.Connection) {
54-
connection.(*om.MockedOmConnection).Hostnames = calculateHostNamesForExternalDomains(rs)
117+
connection.(*om.MockedOmConnection).Hostnames = nil
55118
})
56119

57120
return multiReplicaSetController, client, clusterMap, omConnectionFactory
58121
}
122+
123+
// getMockMultiClusterMap simulates multiple K8s clusters using fake clients
124+
func getMockMultiClusterMap(omConnectionFactory *om.CachedOMConnectionFactory) map[string]client.Client {
125+
clientMap := make(map[string]client.Client)
126+
127+
for _, clusterName := range multiClusters {
128+
fakeClientBuilder := mock.NewEmptyFakeClientBuilder()
129+
fakeClientBuilder.WithInterceptorFuncs(interceptor.Funcs{
130+
Get: mock.GetFakeClientInterceptorGetFunc(omConnectionFactory, true, true),
131+
})
132+
133+
clientMap[clusterName] = kubernetesClient.NewClient(fakeClientBuilder.Build())
134+
}
135+
136+
return clientMap
137+
}

0 commit comments

Comments
 (0)