Skip to content

Commit 80a4e6e

Browse files
committed
synchronous postgres cluster tests
1 parent b5bed4d commit 80a4e6e

2 files changed

Lines changed: 80 additions & 113 deletions

File tree

internal/controller/postgrescluster_controller_test.go

Lines changed: 80 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ package controller
1919
import (
2020
"context"
2121
"fmt"
22-
"strconv"
23-
"time"
2422

2523
apierrors "k8s.io/apimachinery/pkg/api/errors"
2624
"k8s.io/apimachinery/pkg/api/meta"
@@ -79,6 +77,13 @@ var _ = Describe("PostgresCluster Controller", func() {
7977
req reconcile.Request
8078
)
8179

80+
reconcileNTimes := func(times int) {
81+
for i := 0; i < times; i++ {
82+
_, err := reconciler.Reconcile(ctx, req)
83+
Expect(err).NotTo(HaveOccurred())
84+
}
85+
}
86+
8287
BeforeEach(func() {
8388
nameSuffix := fmt.Sprintf("%d-%d-%d",
8489
GinkgoParallelProcess(),
@@ -177,82 +182,59 @@ var _ = Describe("PostgresCluster Controller", func() {
177182
// PC-02
178183
It("adds finalizer on reconcile", func() {
179184
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
185+
reconcileNTimes(1)
180186

181-
Eventually(func() bool {
182-
pc := &enterprisev4.PostgresCluster{}
183-
if err := k8sClient.Get(ctx, pgClusterKey, pc); err != nil {
184-
return false
185-
}
186-
return controllerutil.ContainsFinalizer(pc, core.PostgresClusterFinalizerName)
187-
}, "10s", "250ms").Should(BeTrue())
187+
pc := &enterprisev4.PostgresCluster{}
188+
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
189+
Expect(controllerutil.ContainsFinalizer(pc, core.PostgresClusterFinalizerName)).To(BeTrue())
188190
})
189191

190192
// PC-01
191193
It("creates managed resources and status refs", func() {
192194
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
195+
// pass 1: add finalizer; pass 2: create CNPG cluster/secret/status.
196+
reconcileNTimes(2)
193197

194-
Eventually(func(g Gomega) {
195-
pc := &enterprisev4.PostgresCluster{}
196-
g.Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
197-
198-
cond := meta.FindStatusCondition(pc.Status.Conditions, "ClusterReady")
199-
g.Expect(cond).NotTo(BeNil())
200-
g.Expect(cond.Status).To(Equal(metav1.ConditionFalse))
201-
g.Expect(cond.Reason).To(Equal("CNPGClusterProvisioning"))
202-
}, "20s", "250ms").Should(Succeed())
198+
pc := &enterprisev4.PostgresCluster{}
199+
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
200+
cond := meta.FindStatusCondition(pc.Status.Conditions, "ClusterReady")
201+
Expect(cond).NotTo(BeNil())
202+
Expect(cond.Status).To(Equal(metav1.ConditionFalse))
203+
Expect(cond.Reason).To(Equal("ClusterBuildSucceeded"))
203204

204205
// Simulate external CNPG controller status progression.
205-
Eventually(func() error {
206-
cnpg := &cnpgv1.Cluster{}
207-
if err := k8sClient.Get(ctx, pgClusterKey, cnpg); err != nil {
208-
return err
209-
}
210-
cnpg.Status.Phase = cnpgv1.PhaseHealthy
211-
return k8sClient.Status().Update(ctx, cnpg) // update event
212-
}, "10s", "250ms").Should(Succeed())
206+
cnpg := &cnpgv1.Cluster{}
207+
Expect(k8sClient.Get(ctx, pgClusterKey, cnpg)).To(Succeed())
208+
cnpg.Status.Phase = cnpgv1.PhaseHealthy
209+
Expect(k8sClient.Status().Update(ctx, cnpg)).To(Succeed())
210+
reconcileNTimes(1)
213211

214212
// Expect cnpg status progression propagation
215-
Eventually(func(g Gomega) {
216-
pc := &enterprisev4.PostgresCluster{}
217-
g.Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
218-
219-
cond := meta.FindStatusCondition(pc.Status.Conditions, "ClusterReady")
220-
g.Expect(cond).NotTo(BeNil())
221-
g.Expect(cond.Status).To(Equal(metav1.ConditionTrue))
222-
g.Expect(cond.Reason).To(Equal("CNPGClusterHealthy"))
223-
}, "20s", "250ms").Should(Succeed())
224-
225-
Eventually(func(g Gomega) {
226-
pc := &enterprisev4.PostgresCluster{}
227-
g.Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
228-
g.Expect(pc.Status.Resources).NotTo(BeNil())
229-
g.Expect(pc.Status.Resources.SuperUserSecretRef).NotTo(BeNil())
230-
g.Expect(pc.Status.Resources.ConfigMapRef).NotTo(BeNil())
231-
}, "20s", "250ms").Should(Succeed())
213+
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
214+
cond = meta.FindStatusCondition(pc.Status.Conditions, "ClusterReady")
215+
Expect(cond).NotTo(BeNil())
216+
Expect(cond.Status).To(Equal(metav1.ConditionTrue))
217+
Expect(cond.Reason).To(Equal("CNPGClusterHealthy"))
218+
Expect(pc.Status.Resources).NotTo(BeNil())
219+
Expect(pc.Status.Resources.SuperUserSecretRef).NotTo(BeNil())
220+
Expect(pc.Status.Resources.ConfigMapRef).NotTo(BeNil())
232221
})
233222

234223
// PC-07
235224
It("is idempotent across repeated reconciles", func() {
236225
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
226+
reconcileNTimes(2)
227+
reconcileNTimes(3)
237228

238-
// Trigger extra update events that should not change desired state semantics.
239-
Eventually(func() error {
240-
pc := &enterprisev4.PostgresCluster{}
241-
if err := k8sClient.Get(ctx, pgClusterKey, pc); err != nil {
242-
return err
243-
}
244-
if pc.Annotations == nil {
245-
pc.Annotations = map[string]string{}
246-
}
247-
pc.Annotations["test.bump"] = strconv.FormatInt(time.Now().UnixNano(), 10)
248-
return k8sClient.Update(ctx, pc) // update event
249-
}, "10s", "250ms").Should(Succeed())
250-
251-
Eventually(func(g Gomega) {
252-
cnpg := &cnpgv1.Cluster{}
253-
g.Expect(k8sClient.Get(ctx, pgClusterKey, cnpg)).To(Succeed())
254-
g.Expect(cnpg.Spec.Instances).To(Equal(int(clusterMemberCount)))
255-
}, "20s", "250ms").Should(Succeed())
229+
cnpg := &cnpgv1.Cluster{}
230+
Expect(k8sClient.Get(ctx, pgClusterKey, cnpg)).To(Succeed())
231+
Expect(cnpg.Spec.Instances).To(Equal(int(clusterMemberCount)))
232+
233+
pc := &enterprisev4.PostgresCluster{}
234+
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
235+
cond := meta.FindStatusCondition(pc.Status.Conditions, "ClusterReady")
236+
Expect(cond).NotTo(BeNil())
237+
Expect(cond.ObservedGeneration).To(Equal(pc.Generation))
256238
})
257239
})
258240
})
@@ -262,14 +244,19 @@ var _ = Describe("PostgresCluster Controller", func() {
262244
Context("and clusterDeletionPolicy is set to Delete", func() {
263245
It("removes children and finalizer", func() {
264246
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
247+
reconcileNTimes(2)
265248

266249
pc := &enterprisev4.PostgresCluster{}
267250
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
268-
Expect(k8sClient.Delete(ctx, pc)).To(Succeed()) // delete event
251+
Expect(k8sClient.Delete(ctx, pc)).To(Succeed())
269252

270253
Eventually(func() bool {
271-
err := k8sClient.Get(ctx, pgClusterKey, &enterprisev4.PostgresCluster{})
272-
return apierrors.IsNotFound(err)
254+
_, err := reconciler.Reconcile(ctx, req)
255+
if err != nil {
256+
return false
257+
}
258+
getErr := k8sClient.Get(ctx, pgClusterKey, &enterprisev4.PostgresCluster{})
259+
return apierrors.IsNotFound(getErr)
273260
}, "30s", "250ms").Should(BeTrue())
274261
})
275262
})
@@ -278,26 +265,20 @@ var _ = Describe("PostgresCluster Controller", func() {
278265
Context("when clusterDeletionPolicy is set to Retain", func() {
279266
It("preserves retained resources and removes owner refs", func() {
280267
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
281-
282-
// Trigger update event: switch policy to Retain before delete.
283-
Eventually(func() error {
284-
pc := &enterprisev4.PostgresCluster{}
285-
if err := k8sClient.Get(ctx, pgClusterKey, pc); err != nil {
286-
return err
287-
}
288-
pc.Spec.ClusterDeletionPolicy = &[]string{retainPolicy}[0]
289-
return k8sClient.Update(ctx, pc)
290-
}, "10s", "250ms").Should(Succeed())
268+
reconcileNTimes(2)
291269

292270
pc := &enterprisev4.PostgresCluster{}
293271
Expect(k8sClient.Get(ctx, pgClusterKey, pc)).To(Succeed())
294-
Expect(k8sClient.Delete(ctx, pc)).To(Succeed()) // delete event
272+
Expect(k8sClient.Delete(ctx, pc)).To(Succeed())
295273

296274
Eventually(func() bool {
297-
err := k8sClient.Get(ctx, pgClusterKey, &enterprisev4.PostgresCluster{})
298-
return apierrors.IsNotFound(err)
275+
_, err := reconciler.Reconcile(ctx, req)
276+
if err != nil {
277+
return false
278+
}
279+
getErr := k8sClient.Get(ctx, pgClusterKey, &enterprisev4.PostgresCluster{})
280+
return apierrors.IsNotFound(getErr)
299281
}, "30s", "250ms").Should(BeTrue())
300-
301282
})
302283
})
303284
})
@@ -306,18 +287,25 @@ var _ = Describe("PostgresCluster Controller", func() {
306287
// PC-05
307288
Context("when referenced class does not exist", func() {
308289
It("fails with class-not-found condition", func() {
309-
clusterName = "bad-" + clusterName
310-
className = "missing-class"
290+
badName := "bad-" + clusterName
291+
badKey := types.NamespacedName{Name: badName, Namespace: namespace}
311292

312293
bad := &enterprisev4.PostgresCluster{
313-
ObjectMeta: metav1.ObjectMeta{Name: clusterName, Namespace: namespace},
314-
Spec: enterprisev4.PostgresClusterSpec{Class: className},
294+
ObjectMeta: metav1.ObjectMeta{Name: badName, Namespace: namespace},
295+
Spec: enterprisev4.PostgresClusterSpec{Class: "missing-class"},
315296
}
316-
Expect(k8sClient.Create(ctx, bad)).To(Succeed()) // create event
297+
Expect(k8sClient.Create(ctx, bad)).To(Succeed())
298+
DeferCleanup(func() { _ = k8sClient.Delete(ctx, bad) })
299+
300+
// pass 1 adds finalizer, pass 2 reaches class lookup and sets failure condition.
301+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: badKey})
302+
Expect(err).NotTo(HaveOccurred())
303+
_, err = reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: badKey})
304+
Expect(err).To(HaveOccurred())
317305

318306
Eventually(func() bool {
319307
current := &enterprisev4.PostgresCluster{}
320-
if err := k8sClient.Get(ctx, types.NamespacedName{Name: bad.Name, Namespace: namespace}, current); err != nil {
308+
if err := k8sClient.Get(ctx, badKey, current); err != nil {
321309
return false
322310
}
323311
cond := meta.FindStatusCondition(current.Status.Conditions, "ClusterReady")
@@ -330,31 +318,16 @@ var _ = Describe("PostgresCluster Controller", func() {
330318
Context("when managed child spec drifts from desired state", func() {
331319
It("restores drifted managed spec", func() {
332320
Expect(k8sClient.Create(ctx, pgCluster)).To(Succeed())
321+
reconcileNTimes(2)
333322

334-
Eventually(func() error {
335-
return k8sClient.Get(ctx, pgClusterKey, &cnpgv1.Cluster{})
336-
}, "20s", "250ms").Should(Succeed())
337-
338-
Eventually(func() error {
339-
pc := &enterprisev4.PostgresCluster{}
340-
if err := k8sClient.Get(ctx, pgClusterKey, pc); err != nil {
341-
return err
342-
}
343-
if pc.Annotations == nil {
344-
pc.Annotations = map[string]string{}
345-
}
346-
pc.Annotations["drift-trigger"] = strconv.FormatInt(time.Now().UnixNano(), 10)
347-
pc.Spec.Instances = &[]int32{8}[0]
348-
return k8sClient.Update(ctx, pc)
349-
}, "10s", "250ms").Should(Succeed())
323+
cnpg := &cnpgv1.Cluster{}
324+
Expect(k8sClient.Get(ctx, pgClusterKey, cnpg)).To(Succeed())
325+
cnpg.Spec.Instances = 8
326+
Expect(k8sClient.Update(ctx, cnpg)).To(Succeed())
350327

351-
Eventually(func() bool {
352-
cnpg := &cnpgv1.Cluster{}
353-
if err := k8sClient.Get(ctx, pgClusterKey, cnpg); err != nil {
354-
return false
355-
}
356-
return cnpg.Spec.Instances == int(clusterMemberCount)
357-
}, "20s", "250ms").Should(BeTrue())
328+
reconcileNTimes(2)
329+
Expect(k8sClient.Get(ctx, pgClusterKey, cnpg)).To(Succeed())
330+
Expect(cnpg.Spec.Instances).To(Equal(int(clusterMemberCount)))
358331
})
359332
})
360333
})

internal/controller/suite_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,6 @@ var _ = BeforeSuite(func(ctx context.Context) {
166166
}).SetupWithManager(k8sManager); err != nil {
167167
Expect(err).NotTo(HaveOccurred())
168168
}
169-
if err := (&PostgresClusterReconciler{
170-
Client: k8sManager.GetClient(),
171-
Scheme: k8sManager.GetScheme(),
172-
}).SetupWithManager(k8sManager); err != nil {
173-
Expect(err).NotTo(HaveOccurred())
174-
}
175169

176170
go func() {
177171
err = k8sManager.Start(ctrl.SetupSignalHandler())

0 commit comments

Comments
 (0)