Skip to content

Commit 8366804

Browse files
committed
Some unit tests for the annotations
1 parent d5bdd18 commit 8366804

File tree

1 file changed

+139
-0
lines changed

1 file changed

+139
-0
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package operator
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
11+
mdbv1 "github.com/mongodb/mongodb-kubernetes/api/v1/mdb"
12+
"github.com/mongodb/mongodb-kubernetes/api/v1/status"
13+
"github.com/mongodb/mongodb-kubernetes/controllers/operator/mock"
14+
"github.com/mongodb/mongodb-kubernetes/pkg/util"
15+
)
16+
17+
// ===== Test for state and vault annotations handling in replicaset controller =====
18+
19+
// TestReplicaSetAnnotations_WrittenOnSuccess verifies that lastAchievedSpec annotation is written after successful
20+
// reconciliation.
21+
func TestReplicaSetAnnotations_WrittenOnSuccess(t *testing.T) {
22+
ctx := context.Background()
23+
rs := DefaultReplicaSetBuilder().Build()
24+
25+
reconciler, client, _ := defaultReplicaSetReconciler(ctx, nil, "", "", rs)
26+
27+
checkReconcileSuccessful(ctx, t, reconciler, rs, client)
28+
29+
err := client.Get(ctx, rs.ObjectKey(), rs)
30+
require.NoError(t, err)
31+
32+
require.Contains(t, rs.Annotations, util.LastAchievedSpec,
33+
"lastAchievedSpec annotation should be written on successful reconciliation")
34+
35+
var lastSpec mdbv1.MongoDbSpec
36+
err = json.Unmarshal([]byte(rs.Annotations[util.LastAchievedSpec]), &lastSpec)
37+
require.NoError(t, err)
38+
assert.Equal(t, 3, lastSpec.Members)
39+
assert.Equal(t, "4.0.0", lastSpec.Version)
40+
}
41+
42+
// TestReplicaSetAnnotations_NotWrittenOnFailure verifies that lastAchievedSpec annotation
43+
// is NOT written when reconciliation fails.
44+
func TestReplicaSetAnnotations_NotWrittenOnFailure(t *testing.T) {
45+
ctx := context.Background()
46+
rs := DefaultReplicaSetBuilder().Build()
47+
48+
// Setup without credentials secret to cause failure
49+
kubeClient := mock.NewEmptyFakeClientBuilder().
50+
WithObjects(rs).
51+
WithObjects(mock.GetProjectConfigMap(mock.TestProjectConfigMapName, "testProject", "testOrg")).
52+
Build()
53+
54+
reconciler := newReplicaSetReconciler(ctx, kubeClient, nil, "", "", false, false, nil)
55+
56+
_, err := reconciler.Reconcile(ctx, requestFromObject(rs))
57+
require.NoError(t, err, "Reconcile should not return error (error captured in status)")
58+
59+
err = kubeClient.Get(ctx, rs.ObjectKey(), rs)
60+
require.NoError(t, err)
61+
62+
assert.NotEqual(t, status.PhaseRunning, rs.Status.Phase)
63+
64+
assert.NotContains(t, rs.Annotations, util.LastAchievedSpec,
65+
"lastAchievedSpec should NOT be written when reconciliation fails")
66+
}
67+
68+
// TestReplicaSetAnnotations_PreservedOnSubsequentFailure verifies that annotations from a previous successful
69+
// reconciliation are preserved when a later reconciliation fails.
70+
func TestReplicaSetAnnotations_PreservedOnSubsequentFailure(t *testing.T) {
71+
ctx := context.Background()
72+
rs := DefaultReplicaSetBuilder().Build()
73+
74+
kubeClient, omConnectionFactory := mock.NewDefaultFakeClient(rs)
75+
reconciler := newReplicaSetReconciler(ctx, kubeClient, nil, "", "", false, false, omConnectionFactory.GetConnectionFunc)
76+
77+
_, err := reconciler.Reconcile(ctx, requestFromObject(rs))
78+
require.NoError(t, err)
79+
80+
err = kubeClient.Get(ctx, rs.ObjectKey(), rs)
81+
require.NoError(t, err)
82+
require.Contains(t, rs.Annotations, util.LastAchievedSpec)
83+
84+
originalLastAchievedSpec := rs.Annotations[util.LastAchievedSpec]
85+
86+
// Delete credentials to cause failure
87+
credentialsSecret := mock.GetCredentialsSecret("testUser", "testApiKey")
88+
err = kubeClient.Delete(ctx, credentialsSecret)
89+
require.NoError(t, err)
90+
91+
rs.Spec.Members = 5
92+
err = kubeClient.Update(ctx, rs)
93+
require.NoError(t, err)
94+
95+
_, err = reconciler.Reconcile(ctx, requestFromObject(rs))
96+
require.NoError(t, err)
97+
98+
err = kubeClient.Get(ctx, rs.ObjectKey(), rs)
99+
require.NoError(t, err)
100+
101+
assert.Contains(t, rs.Annotations, util.LastAchievedSpec)
102+
assert.NotEqual(t, status.PhaseRunning, rs.Status.Phase)
103+
assert.Equal(t, originalLastAchievedSpec, rs.Annotations[util.LastAchievedSpec],
104+
"lastAchievedSpec should remain unchanged when reconciliation fails")
105+
106+
var lastSpec mdbv1.MongoDbSpec
107+
err = json.Unmarshal([]byte(rs.Annotations[util.LastAchievedSpec]), &lastSpec)
108+
require.NoError(t, err)
109+
assert.Equal(t, 3, lastSpec.Members,
110+
"Should still reflect previous successful state (3 members, not 5)")
111+
}
112+
113+
// TestVaultAnnotations_NotWrittenWhenDisabled verifies that vault annotations are NOT
114+
// written when vault backend is disabled.
115+
func TestVaultAnnotations_NotWrittenWhenDisabled(t *testing.T) {
116+
ctx := context.Background()
117+
rs := DefaultReplicaSetBuilder().Build()
118+
119+
t.Setenv("SECRET_BACKEND", "K8S_SECRET_BACKEND")
120+
121+
reconciler, client, _ := defaultReplicaSetReconciler(ctx, nil, "", "", rs)
122+
123+
checkReconcileSuccessful(ctx, t, reconciler, rs, client)
124+
125+
err := client.Get(ctx, rs.ObjectKey(), rs)
126+
require.NoError(t, err)
127+
128+
require.Contains(t, rs.Annotations, util.LastAchievedSpec,
129+
"lastAchievedSpec should be written even when vault is disabled")
130+
131+
// Vault annotations would be simple secret names like "my-secret": "5"
132+
for key := range rs.Annotations {
133+
if key == util.LastAchievedSpec {
134+
continue
135+
}
136+
assert.NotRegexp(t, "^[a-z0-9-]+$", key,
137+
"Should not have simple secret name annotations when vault disabled - found: %s", key)
138+
}
139+
}

0 commit comments

Comments
 (0)