@@ -22,6 +22,8 @@ import (
2222 "errors"
2323 "fmt"
2424 "strconv"
25+ "strings"
26+ "sync"
2527 "time"
2628
2729 . "github.com/onsi/ginkgo/v2"
@@ -49,6 +51,7 @@ import (
4951 "sigs.k8s.io/controller-runtime/pkg/client/fake"
5052 "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
5153 "sigs.k8s.io/controller-runtime/pkg/config"
54+ "sigs.k8s.io/controller-runtime/pkg/controller"
5255 "sigs.k8s.io/controller-runtime/pkg/event"
5356 "sigs.k8s.io/controller-runtime/pkg/log/zap"
5457 "sigs.k8s.io/controller-runtime/pkg/manager"
@@ -1492,45 +1495,6 @@ var _ = Describe("Reconciler", func() {
14921495 })
14931496 })
14941497 })
1495- When ("label selector set" , func () {
1496- It ("reconcile only matching CR" , func () {
1497- By ("adding selector to the reconciler" , func () {
1498- selectorFoo := metav1.LabelSelector {MatchLabels : map [string ]string {"app" : "foo" }}
1499- Expect (WithSelector (selectorFoo )(r )).To (Succeed ())
1500- })
1501-
1502- By ("adding not matching label to the CR" , func () {
1503- Expect (mgr .GetClient ().Get (ctx , objKey , obj )).To (Succeed ())
1504- obj .SetLabels (map [string ]string {"app" : "bar" })
1505- Expect (mgr .GetClient ().Update (ctx , obj )).To (Succeed ())
1506- })
1507-
1508- By ("reconciling skipped and no actions for the release" , func () {
1509- res , err := r .Reconcile (ctx , req )
1510- Expect (res ).To (Equal (reconcile.Result {}))
1511- Expect (err ).ToNot (HaveOccurred ())
1512- })
1513-
1514- By ("verifying the release has not changed" , func () {
1515- rel , err := ac .Get (obj .GetName ())
1516- Expect (err ).ToNot (HaveOccurred ())
1517- Expect (rel ).NotTo (BeNil ())
1518- Expect (* rel ).To (Equal (* currentRelease ))
1519- })
1520-
1521- By ("adding matching label to the CR" , func () {
1522- Expect (mgr .GetClient ().Get (ctx , objKey , obj )).To (Succeed ())
1523- obj .SetLabels (map [string ]string {"app" : "foo" })
1524- Expect (mgr .GetClient ().Update (ctx , obj )).To (Succeed ())
1525- })
1526-
1527- By ("successfully reconciling with correct labels" , func () {
1528- res , err := r .Reconcile (ctx , req )
1529- Expect (res ).To (Equal (reconcile.Result {}))
1530- Expect (err ).ToNot (HaveOccurred ())
1531- })
1532- })
1533- })
15341498 })
15351499 })
15361500 })
@@ -1545,6 +1509,141 @@ var _ = Describe("Reconciler", func() {
15451509 })
15461510 })
15471511
1512+ _ = Describe ("WithSelector integration test" , func () {
1513+ var (
1514+ mgr manager.Manager
1515+ ctx context.Context
1516+ cancel context.CancelFunc
1517+ reconciledCRs []string
1518+ reconciledCRsMutex sync.Mutex
1519+ labeledObj * unstructured.Unstructured
1520+ unlabeledObj * unstructured.Unstructured
1521+ labeledObjKey types.NamespacedName
1522+ unlabeledObjKey types.NamespacedName
1523+ )
1524+
1525+ BeforeEach (func () {
1526+ reconciledCRs = []string {}
1527+ mgr = getManagerOrFail ()
1528+ matchingLabels := map [string ]string {"app" : "foo" }
1529+
1530+ r , err := New (
1531+ WithGroupVersionKind (gvk ),
1532+ WithChart (chrt ),
1533+ WithSelector (metav1.LabelSelector {MatchLabels : matchingLabels }),
1534+ )
1535+ Expect (err ).ToNot (HaveOccurred ())
1536+
1537+ originalReconciler := r
1538+ wrappedReconciler := & Reconciler {}
1539+ * wrappedReconciler = * originalReconciler
1540+ wrappedReconciler .client = mgr .GetClient ()
1541+
1542+ // Override Reconcile to track reconciliations
1543+ reconciler := reconcile .Func (func (ctx context.Context , req reconcile.Request ) (reconcile.Result , error ) {
1544+ reconciledCRsMutex .Lock ()
1545+ reconciledCRs = append (reconciledCRs , req .NamespacedName .String ())
1546+ reconciledCRsMutex .Unlock ()
1547+ return wrappedReconciler .Reconcile (ctx , req )
1548+ })
1549+
1550+ controllerName := fmt .Sprintf ("%v-controller" , strings .ToLower (gvk .Kind ))
1551+ Expect (wrappedReconciler .addDefaults (mgr , controllerName )).To (Succeed ())
1552+ wrappedReconciler .setupScheme (mgr )
1553+
1554+ c , err := controller .New (controllerName , mgr , controller.Options {
1555+ Reconciler : reconciler ,
1556+ MaxConcurrentReconciles : 1 ,
1557+ })
1558+ Expect (err ).ToNot (HaveOccurred ())
1559+ Expect (wrappedReconciler .setupWatches (mgr , c )).To (Succeed ())
1560+
1561+ labeledObj = testutil .BuildTestCR (gvk )
1562+ labeledObj .SetName ("labeled-cr" )
1563+ labeledObj .SetLabels (matchingLabels )
1564+ labeledObjKey = types.NamespacedName {Namespace : labeledObj .GetNamespace (), Name : labeledObj .GetName ()}
1565+
1566+ unlabeledObj = testutil .BuildTestCR (gvk )
1567+ unlabeledObj .SetName ("unlabeled-cr" )
1568+ unlabeledObjKey = types.NamespacedName {Namespace : unlabeledObj .GetNamespace (), Name : unlabeledObj .GetName ()}
1569+
1570+ ctx , cancel = context .WithCancel (context .Background ())
1571+ go func () {
1572+ Expect (mgr .Start (ctx )).To (Succeed ())
1573+ }()
1574+ Expect (mgr .GetCache ().WaitForCacheSync (ctx )).To (BeTrue ())
1575+ })
1576+
1577+ AfterEach (func () {
1578+ By ("ensuring the labeled CR is deleted" , func () {
1579+ err := mgr .GetAPIReader ().Get (ctx , labeledObjKey , labeledObj )
1580+ if ! apierrors .IsNotFound (err ) {
1581+ Expect (err ).ToNot (HaveOccurred ())
1582+ labeledObj .SetFinalizers ([]string {})
1583+ Expect (mgr .GetClient ().Update (ctx , labeledObj )).To (Succeed ())
1584+ Expect (mgr .GetClient ().Delete (ctx , labeledObj )).To (Succeed ())
1585+ }
1586+ })
1587+
1588+ By ("ensuring the unlabeled CR is deleted" , func () {
1589+ err := mgr .GetAPIReader ().Get (ctx , unlabeledObjKey , unlabeledObj )
1590+ if ! apierrors .IsNotFound (err ) {
1591+ Expect (err ).ToNot (HaveOccurred ())
1592+ unlabeledObj .SetFinalizers ([]string {})
1593+ Expect (mgr .GetClient ().Update (ctx , unlabeledObj )).To (Succeed ())
1594+ Expect (mgr .GetClient ().Delete (ctx , unlabeledObj )).To (Succeed ())
1595+ }
1596+ })
1597+
1598+ cancel ()
1599+ })
1600+
1601+ It ("should only reconcile CRs matching the label selector" , func () {
1602+ By ("creating a CR with matching labels" , func () {
1603+ Expect (mgr .GetClient ().Create (ctx , labeledObj )).To (Succeed ())
1604+ })
1605+
1606+ By ("creating a CR without matching labels" , func () {
1607+ Expect (mgr .GetClient ().Create (ctx , unlabeledObj )).To (Succeed ())
1608+ })
1609+
1610+ By ("waiting for reconciliations to complete" , func () {
1611+ Eventually (func () []string {
1612+ reconciledCRsMutex .Lock ()
1613+ defer reconciledCRsMutex .Unlock ()
1614+ return reconciledCRs
1615+ }, "5s" , "100ms" ).Should (ContainElement (labeledObjKey .String ()))
1616+ })
1617+
1618+ By ("verifying only the labeled CR was reconciled" , func () {
1619+ reconciledCRsMutex .Lock ()
1620+ defer reconciledCRsMutex .Unlock ()
1621+ Expect (reconciledCRs ).To (ContainElement (labeledObjKey .String ()))
1622+ Expect (reconciledCRs ).NotTo (ContainElement (unlabeledObjKey .String ()))
1623+ })
1624+
1625+ By ("updating the unlabeled CR to have matching labels" , func () {
1626+ Expect (mgr .GetClient ().Get (ctx , unlabeledObjKey , unlabeledObj )).To (Succeed ())
1627+ unlabeledObj .SetLabels (map [string ]string {"app" : "foo" })
1628+ Expect (mgr .GetClient ().Update (ctx , unlabeledObj )).To (Succeed ())
1629+ })
1630+
1631+ By ("waiting for the previously unlabeled CR to be reconciled" , func () {
1632+ Eventually (func () []string {
1633+ reconciledCRsMutex .Lock ()
1634+ defer reconciledCRsMutex .Unlock ()
1635+ return reconciledCRs
1636+ }, "5s" , "100ms" ).Should (ContainElement (unlabeledObjKey .String ()))
1637+ })
1638+
1639+ By ("verifying the previously unlabeled CR was reconciled after label change" , func () {
1640+ reconciledCRsMutex .Lock ()
1641+ defer reconciledCRsMutex .Unlock ()
1642+ Expect (reconciledCRs ).To (ContainElement (unlabeledObjKey .String ()))
1643+ })
1644+ })
1645+ })
1646+
15481647 _ = Describe ("Test custom controller setup" , func () {
15491648 var (
15501649 mgr manager.Manager
0 commit comments