Skip to content

Commit 072866a

Browse files
committed
Use hooks and add another test with two managers
1 parent 0a43969 commit 072866a

File tree

1 file changed

+125
-85
lines changed

1 file changed

+125
-85
lines changed

pkg/reconciler/reconciler_test.go

Lines changed: 125 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"errors"
2323
"fmt"
2424
"strconv"
25-
"strings"
2625
"sync"
2726
"time"
2827

@@ -51,7 +50,6 @@ import (
5150
"sigs.k8s.io/controller-runtime/pkg/client/fake"
5251
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
5352
"sigs.k8s.io/controller-runtime/pkg/config"
54-
"sigs.k8s.io/controller-runtime/pkg/controller"
5553
"sigs.k8s.io/controller-runtime/pkg/event"
5654
"sigs.k8s.io/controller-runtime/pkg/log/zap"
5755
"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -1511,132 +1509,146 @@ var _ = Describe("Reconciler", func() {
15111509

15121510
_ = Describe("WithSelector", func() {
15131511
var (
1514-
mgr manager.Manager
1515-
ctx context.Context
1516-
cancel context.CancelFunc
1517-
reconciledCRs []string
1518-
matchingLabels map[string]string
1519-
reconciledCRsMutex sync.Mutex
1520-
labeledObj *unstructured.Unstructured
1521-
unlabeledObj *unstructured.Unstructured
1522-
labeledObjKey types.NamespacedName
1523-
unlabeledObjKey types.NamespacedName
1512+
ctx context.Context
1513+
cancel context.CancelFunc
1514+
mgr manager.Manager
1515+
reconciledCRs []string
1516+
anotherReconciledCRs []string
1517+
matchingLabels map[string]string
1518+
anotherMatchingLabels map[string]string
1519+
labeledObj *unstructured.Unstructured
1520+
anotherObj *unstructured.Unstructured
1521+
labeledObjKey types.NamespacedName
1522+
anotherObjKey types.NamespacedName
1523+
mu sync.Mutex
15241524
)
15251525

15261526
BeforeEach(func() {
1527-
reconciledCRs = []string{}
1528-
mgr = getManagerOrFail()
1529-
matchingLabels = map[string]string{"app": "foo"}
1530-
1531-
r, err := New(
1532-
WithGroupVersionKind(gvk),
1533-
WithChart(chrt),
1534-
WithSelector(metav1.LabelSelector{MatchLabels: matchingLabels}),
1535-
)
1536-
Expect(err).ToNot(HaveOccurred())
1527+
ctx, cancel = context.WithCancel(context.Background())
15371528

1538-
reconciler := reconcile.Func(func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
1539-
reconciledCRsMutex.Lock()
1540-
reconciledCRs = append(reconciledCRs, req.NamespacedName.String())
1541-
reconciledCRsMutex.Unlock()
1542-
return r.Reconcile(ctx, req)
1543-
})
1529+
mu.Lock()
1530+
reconciledCRs = nil
1531+
anotherReconciledCRs = nil
1532+
mu.Unlock()
15441533

1545-
controllerName := fmt.Sprintf("%v-controller", strings.ToLower(gvk.Kind))
1546-
Expect(r.addDefaults(mgr, controllerName)).To(Succeed())
1547-
r.setupScheme(mgr)
1534+
matchingLabels = map[string]string{"app": "foo"}
1535+
anotherMatchingLabels = map[string]string{"app": "bar"}
15481536

1549-
c, err := controller.New(controllerName, mgr, controller.Options{
1550-
Reconciler: reconciler,
1551-
MaxConcurrentReconciles: 1,
1537+
trackingHook := hook.PostHookFunc(func(obj *unstructured.Unstructured, rel release.Release, log logr.Logger) error {
1538+
mu.Lock()
1539+
defer mu.Unlock()
1540+
reconciledCRs = append(reconciledCRs, obj.GetName())
1541+
return nil
15521542
})
1553-
Expect(err).ToNot(HaveOccurred())
1554-
Expect(r.setupWatches(mgr, c)).To(Succeed())
1543+
mgr = setupManagerWithPostHook(ctx, trackingHook, matchingLabels)
15551544

15561545
labeledObj = testutil.BuildTestCR(gvk)
15571546
labeledObj.SetName("labeled-cr")
15581547
labeledObj.SetLabels(matchingLabels)
15591548
labeledObjKey = types.NamespacedName{Namespace: labeledObj.GetNamespace(), Name: labeledObj.GetName()}
15601549

1561-
unlabeledObj = testutil.BuildTestCR(gvk)
1562-
unlabeledObj.SetName("unlabeled-cr")
1563-
unlabeledObjKey = types.NamespacedName{Namespace: unlabeledObj.GetNamespace(), Name: unlabeledObj.GetName()}
1564-
1565-
ctx, cancel = context.WithCancel(context.Background())
1566-
go func() {
1567-
Expect(mgr.Start(ctx)).To(Succeed())
1568-
}()
1569-
Expect(mgr.GetCache().WaitForCacheSync(ctx)).To(BeTrue())
1550+
anotherObj = testutil.BuildTestCR(gvk)
1551+
anotherObj.SetName("another-cr")
1552+
anotherObjKey = types.NamespacedName{Namespace: anotherObj.GetNamespace(), Name: anotherObj.GetName()}
15701553
})
15711554

15721555
AfterEach(func() {
15731556
By("ensuring the labeled CR is deleted", func() {
1574-
err := mgr.GetAPIReader().Get(ctx, labeledObjKey, labeledObj)
1575-
if apierrors.IsNotFound(err) {
1576-
return
1577-
}
1578-
Expect(err).ToNot(HaveOccurred())
1579-
labeledObj.SetFinalizers([]string{})
1580-
Expect(mgr.GetClient().Update(ctx, labeledObj)).To(Succeed())
1581-
Expect(mgr.GetClient().Delete(ctx, labeledObj)).To(Succeed())
1557+
ensureDeleteCR(ctx, mgr, labeledObjKey, labeledObj)
15821558
})
15831559

15841560
By("ensuring the unlabeled CR is deleted", func() {
1585-
err := mgr.GetAPIReader().Get(ctx, unlabeledObjKey, unlabeledObj)
1586-
if apierrors.IsNotFound(err) {
1587-
return
1588-
}
1589-
Expect(err).ToNot(HaveOccurred())
1590-
unlabeledObj.SetFinalizers([]string{})
1591-
Expect(mgr.GetClient().Update(ctx, unlabeledObj)).To(Succeed())
1592-
Expect(mgr.GetClient().Delete(ctx, unlabeledObj)).To(Succeed())
1561+
ensureDeleteCR(ctx, mgr, anotherObjKey, anotherObj)
15931562
})
1594-
15951563
cancel()
15961564
})
15971565

15981566
It("should only reconcile CRs matching the label selector", func() {
1567+
By("creating a CR without matching labels", func() {
1568+
Expect(mgr.GetClient().Create(ctx, anotherObj)).To(Succeed())
1569+
})
1570+
1571+
By("verifying that the labeled reconciler does not reconcile CR without labels", func() {
1572+
Consistently(func() []string {
1573+
mu.Lock()
1574+
defer mu.Unlock()
1575+
return reconciledCRs
1576+
}, "2s", "100ms").Should(BeEmpty())
1577+
})
1578+
15991579
By("creating a CR with matching labels", func() {
16001580
Expect(mgr.GetClient().Create(ctx, labeledObj)).To(Succeed())
16011581
})
16021582

1603-
By("creating a CR without matching labels", func() {
1604-
Expect(mgr.GetClient().Create(ctx, unlabeledObj)).To(Succeed())
1583+
By("verifying only the labeled CR was reconciled", func() {
1584+
Eventually(func() []string {
1585+
mu.Lock()
1586+
defer mu.Unlock()
1587+
return reconciledCRs
1588+
}).Should(HaveExactElements(labeledObjKey.Name))
1589+
})
1590+
1591+
By("updating the unlabeled CR to have matching labels", func() {
1592+
Expect(mgr.GetClient().Get(ctx, anotherObjKey, anotherObj)).To(Succeed())
1593+
anotherObj.SetLabels(matchingLabels)
1594+
Expect(mgr.GetClient().Update(ctx, anotherObj)).To(Succeed())
16051595
})
16061596

1607-
By("waiting for reconciliations to complete", func() {
1597+
By("verifying that both CRs were reconciled after setting label to the unlabeled CR", func() {
16081598
Eventually(func() []string {
1609-
reconciledCRsMutex.Lock()
1610-
defer reconciledCRsMutex.Unlock()
1599+
mu.Lock()
1600+
defer mu.Unlock()
16111601
return reconciledCRs
1612-
}, "5s", "100ms").Should(ContainElement(labeledObjKey.String()))
1602+
}, "10s", "100ms").Should(ContainElements(labeledObjKey.Name, anotherObjKey.Name))
16131603
})
1604+
})
16141605

1615-
By("verifying only the labeled CR was reconciled", func() {
1616-
reconciledCRsMutex.Lock()
1617-
defer reconciledCRsMutex.Unlock()
1618-
Expect(reconciledCRs).To(ContainElement(labeledObjKey.String()))
1619-
Expect(reconciledCRs).NotTo(ContainElement(unlabeledObjKey.String()))
1606+
It("should reconcile CRs independently when using two managers with different label selectors", func() {
1607+
By("creating another manager with a different label selector", func() {
1608+
postHook := hook.PostHookFunc(func(obj *unstructured.Unstructured, rel release.Release, log logr.Logger) error {
1609+
mu.Lock()
1610+
defer mu.Unlock()
1611+
anotherReconciledCRs = append(anotherReconciledCRs, obj.GetName())
1612+
return nil
1613+
})
1614+
_ = setupManagerWithPostHook(ctx, postHook, anotherMatchingLabels)
16201615
})
16211616

1622-
By("updating the unlabeled CR to have matching labels", func() {
1623-
Expect(mgr.GetClient().Get(ctx, unlabeledObjKey, unlabeledObj)).To(Succeed())
1624-
unlabeledObj.SetLabels(matchingLabels)
1625-
Expect(mgr.GetClient().Update(ctx, unlabeledObj)).To(Succeed())
1617+
By("creating a CR with matching labels for the first manager", func() {
1618+
Expect(mgr.GetClient().Create(ctx, labeledObj)).To(Succeed())
16261619
})
16271620

1628-
By("waiting for the previously unlabeled CR to be reconciled", func() {
1621+
By("verifying that only the first manager reconciled the CR", func() {
16291622
Eventually(func() []string {
1630-
reconciledCRsMutex.Lock()
1631-
defer reconciledCRsMutex.Unlock()
1623+
mu.Lock()
1624+
defer mu.Unlock()
16321625
return reconciledCRs
1633-
}, "5s", "100ms").Should(ContainElement(unlabeledObjKey.String()))
1626+
}, "10s", "100ms").Should(HaveExactElements(labeledObjKey.Name))
1627+
1628+
Consistently(func() []string {
1629+
mu.Lock()
1630+
defer mu.Unlock()
1631+
return anotherReconciledCRs
1632+
}, "2s", "100ms").Should(BeEmpty())
16341633
})
16351634

1636-
By("verifying the previously unlabeled CR was reconciled after label change", func() {
1637-
reconciledCRsMutex.Lock()
1638-
defer reconciledCRsMutex.Unlock()
1639-
Expect(reconciledCRs).To(ContainElement(unlabeledObjKey.String()))
1635+
By("creating a CR with matching labels for the second manager", func() {
1636+
anotherObj.SetLabels(anotherMatchingLabels)
1637+
Expect(mgr.GetClient().Create(ctx, anotherObj)).To(Succeed())
1638+
})
1639+
1640+
By("verifying that both managers reconcile only matching labels CRs", func() {
1641+
Eventually(func() []string {
1642+
mu.Lock()
1643+
defer mu.Unlock()
1644+
return reconciledCRs
1645+
}, "10s", "100ms").Should(HaveExactElements(labeledObjKey.Name))
1646+
1647+
Eventually(func() []string {
1648+
mu.Lock()
1649+
defer mu.Unlock()
1650+
return anotherReconciledCRs
1651+
}, "10s", "100ms").Should(HaveExactElements(anotherObjKey.Name))
16401652
})
16411653
})
16421654
})
@@ -1839,3 +1851,31 @@ func verifyEvent(ctx context.Context, cl client.Reader, obj metav1.Object, event
18391851
Reason: %q
18401852
Message: %q`, eventType, reason, message))
18411853
}
1854+
1855+
func ensureDeleteCR(ctx context.Context, mgr manager.Manager, crKey types.NamespacedName, cr *unstructured.Unstructured) {
1856+
err := mgr.GetAPIReader().Get(ctx, crKey, cr)
1857+
if apierrors.IsNotFound(err) {
1858+
return
1859+
}
1860+
Expect(err).ToNot(HaveOccurred())
1861+
cr.SetFinalizers([]string{})
1862+
Expect(mgr.GetClient().Update(ctx, cr)).To(Succeed())
1863+
Expect(mgr.GetClient().Delete(ctx, cr)).To(Succeed())
1864+
}
1865+
1866+
func setupManagerWithPostHook(ctx context.Context, postHook hook.PostHook, matchingLabels map[string]string) manager.Manager {
1867+
mgr := getManagerOrFail()
1868+
r, err := New(
1869+
WithGroupVersionKind(gvk),
1870+
WithChart(chrt),
1871+
WithSelector(metav1.LabelSelector{MatchLabels: matchingLabels}),
1872+
WithPostHook(postHook),
1873+
)
1874+
Expect(err).ToNot(HaveOccurred())
1875+
Expect(r.SetupWithManager(mgr)).To(Succeed())
1876+
go func() {
1877+
Expect(mgr.Start(ctx)).To(Succeed())
1878+
}()
1879+
Expect(mgr.GetCache().WaitForCacheSync(ctx)).To(BeTrue())
1880+
return mgr
1881+
}

0 commit comments

Comments
 (0)