sigs.k8s.io/controller-runtime@v0.18.2/pkg/controller/controller_integration_test.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controller_test 18 19 import ( 20 "context" 21 22 appsv1 "k8s.io/api/apps/v1" 23 corev1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/runtime/schema" 26 "k8s.io/apimachinery/pkg/types" 27 "sigs.k8s.io/controller-runtime/pkg/cache" 28 "sigs.k8s.io/controller-runtime/pkg/controller" 29 "sigs.k8s.io/controller-runtime/pkg/controller/controllertest" 30 "sigs.k8s.io/controller-runtime/pkg/handler" 31 "sigs.k8s.io/controller-runtime/pkg/reconcile" 32 "sigs.k8s.io/controller-runtime/pkg/source" 33 34 . "github.com/onsi/ginkgo/v2" 35 . "github.com/onsi/gomega" 36 "sigs.k8s.io/controller-runtime/pkg/manager" 37 ) 38 39 var _ = Describe("controller", func() { 40 var reconciled chan reconcile.Request 41 ctx := context.Background() 42 43 BeforeEach(func() { 44 reconciled = make(chan reconcile.Request) 45 Expect(cfg).NotTo(BeNil()) 46 }) 47 48 Describe("controller", func() { 49 // TODO(directxman12): write a whole suite of controller-client interaction tests 50 51 It("should reconcile", func() { 52 By("Creating the Manager") 53 cm, err := manager.New(cfg, manager.Options{}) 54 Expect(err).NotTo(HaveOccurred()) 55 56 By("Creating the Controller") 57 instance, err := controller.New("foo-controller", cm, controller.Options{ 58 Reconciler: reconcile.Func( 59 func(_ context.Context, request reconcile.Request) (reconcile.Result, error) { 60 reconciled <- request 61 return reconcile.Result{}, nil 62 }), 63 }) 64 Expect(err).NotTo(HaveOccurred()) 65 66 By("Watching Resources") 67 err = instance.Watch( 68 source.Kind(cm.GetCache(), &appsv1.ReplicaSet{}, 69 handler.TypedEnqueueRequestForOwner[*appsv1.ReplicaSet](cm.GetScheme(), cm.GetRESTMapper(), &appsv1.Deployment{}), 70 ), 71 ) 72 Expect(err).NotTo(HaveOccurred()) 73 74 err = instance.Watch(source.Kind(cm.GetCache(), &appsv1.Deployment{}, &handler.TypedEnqueueRequestForObject[*appsv1.Deployment]{})) 75 Expect(err).NotTo(HaveOccurred()) 76 77 err = cm.GetClient().Get(ctx, types.NamespacedName{Name: "foo"}, &corev1.Namespace{}) 78 Expect(err).To(Equal(&cache.ErrCacheNotStarted{})) 79 err = cm.GetClient().List(ctx, &corev1.NamespaceList{}) 80 Expect(err).To(Equal(&cache.ErrCacheNotStarted{})) 81 82 By("Starting the Manager") 83 ctx, cancel := context.WithCancel(context.Background()) 84 defer cancel() 85 go func() { 86 defer GinkgoRecover() 87 Expect(cm.Start(ctx)).NotTo(HaveOccurred()) 88 }() 89 90 deployment := &appsv1.Deployment{ 91 ObjectMeta: metav1.ObjectMeta{Name: "deployment-name"}, 92 Spec: appsv1.DeploymentSpec{ 93 Selector: &metav1.LabelSelector{ 94 MatchLabels: map[string]string{"foo": "bar"}, 95 }, 96 Template: corev1.PodTemplateSpec{ 97 ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}}, 98 Spec: corev1.PodSpec{ 99 Containers: []corev1.Container{ 100 { 101 Name: "nginx", 102 Image: "nginx", 103 SecurityContext: &corev1.SecurityContext{ 104 Privileged: truePtr(), 105 }, 106 }, 107 }, 108 }, 109 }, 110 }, 111 } 112 expectedReconcileRequest := reconcile.Request{NamespacedName: types.NamespacedName{ 113 Namespace: "default", 114 Name: "deployment-name", 115 }} 116 117 By("Invoking Reconciling for Create") 118 deployment, err = clientset.AppsV1().Deployments("default").Create(ctx, deployment, metav1.CreateOptions{}) 119 Expect(err).NotTo(HaveOccurred()) 120 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 121 122 By("Invoking Reconciling for Update") 123 newDeployment := deployment.DeepCopy() 124 newDeployment.Labels = map[string]string{"foo": "bar"} 125 _, err = clientset.AppsV1().Deployments("default").Update(ctx, newDeployment, metav1.UpdateOptions{}) 126 Expect(err).NotTo(HaveOccurred()) 127 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 128 129 By("Invoking Reconciling for an OwnedObject when it is created") 130 replicaset := &appsv1.ReplicaSet{ 131 ObjectMeta: metav1.ObjectMeta{ 132 Name: "rs-name", 133 OwnerReferences: []metav1.OwnerReference{ 134 *metav1.NewControllerRef(deployment, schema.GroupVersionKind{ 135 Group: "apps", 136 Version: "v1", 137 Kind: "Deployment", 138 }), 139 }, 140 }, 141 Spec: appsv1.ReplicaSetSpec{ 142 Selector: &metav1.LabelSelector{ 143 MatchLabels: map[string]string{"foo": "bar"}, 144 }, 145 Template: deployment.Spec.Template, 146 }, 147 } 148 replicaset, err = clientset.AppsV1().ReplicaSets("default").Create(ctx, replicaset, metav1.CreateOptions{}) 149 Expect(err).NotTo(HaveOccurred()) 150 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 151 152 By("Invoking Reconciling for an OwnedObject when it is updated") 153 newReplicaset := replicaset.DeepCopy() 154 newReplicaset.Labels = map[string]string{"foo": "bar"} 155 _, err = clientset.AppsV1().ReplicaSets("default").Update(ctx, newReplicaset, metav1.UpdateOptions{}) 156 Expect(err).NotTo(HaveOccurred()) 157 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 158 159 By("Invoking Reconciling for an OwnedObject when it is deleted") 160 err = clientset.AppsV1().ReplicaSets("default").Delete(ctx, replicaset.Name, metav1.DeleteOptions{}) 161 Expect(err).NotTo(HaveOccurred()) 162 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 163 164 By("Invoking Reconciling for Delete") 165 err = clientset.AppsV1().Deployments("default"). 166 Delete(ctx, "deployment-name", metav1.DeleteOptions{}) 167 Expect(err).NotTo(HaveOccurred()) 168 Expect(<-reconciled).To(Equal(expectedReconcileRequest)) 169 170 By("Listing a type with a slice of pointers as items field") 171 err = cm.GetClient(). 172 List(context.Background(), &controllertest.UnconventionalListTypeList{}) 173 Expect(err).NotTo(HaveOccurred()) 174 }) 175 }) 176 }) 177 178 func truePtr() *bool { 179 t := true 180 return &t 181 }