Skip to content

Commit a3dc13b

Browse files
committed
Add warmup to manager and controller integration tests.
1 parent de4232d commit a3dc13b

File tree

2 files changed

+79
-25
lines changed

2 files changed

+79
-25
lines changed

pkg/controller/controller_integration_test.go

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,21 @@ package controller_test
1818

1919
import (
2020
"context"
21+
"fmt"
22+
"strconv"
2123

2224
appsv1 "k8s.io/api/apps/v1"
2325
corev1 "k8s.io/api/core/v1"
2426
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2527
"k8s.io/apimachinery/pkg/runtime/schema"
2628
"k8s.io/apimachinery/pkg/types"
29+
"k8s.io/utils/ptr"
2730
"sigs.k8s.io/controller-runtime/pkg/cache"
31+
"sigs.k8s.io/controller-runtime/pkg/client"
2832
"sigs.k8s.io/controller-runtime/pkg/controller"
2933
"sigs.k8s.io/controller-runtime/pkg/controller/controllertest"
3034
"sigs.k8s.io/controller-runtime/pkg/handler"
35+
"sigs.k8s.io/controller-runtime/pkg/predicate"
3136
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3237
"sigs.k8s.io/controller-runtime/pkg/source"
3338

@@ -48,30 +53,46 @@ var _ = Describe("controller", func() {
4853
Describe("controller", func() {
4954
// TODO(directxman12): write a whole suite of controller-client interaction tests
5055

51-
It("should reconcile", func() {
56+
// Since all tests are run in parallel and share the same testenv, we namespace the objects
57+
// created by using a namespace per entry, and adding a watch predicate that filters by
58+
// namespace.
59+
DescribeTable("should reconcile", func(enableWarmup bool) {
5260
By("Creating the Manager")
5361
cm, err := manager.New(cfg, manager.Options{})
5462
Expect(err).NotTo(HaveOccurred())
5563

5664
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-
})
65+
instance, err := controller.New(
66+
fmt.Sprintf("foo-controller-%t", enableWarmup),
67+
cm,
68+
controller.Options{
69+
Reconciler: reconcile.Func(
70+
func(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
71+
reconciled <- request
72+
return reconcile.Result{}, nil
73+
}),
74+
EnableWarmup: ptr.To(enableWarmup),
75+
},
76+
)
6477
Expect(err).NotTo(HaveOccurred())
6578

79+
testNamespace := strconv.FormatBool(enableWarmup)
80+
6681
By("Watching Resources")
6782
err = instance.Watch(
6883
source.Kind(cm.GetCache(), &appsv1.ReplicaSet{},
6984
handler.TypedEnqueueRequestForOwner[*appsv1.ReplicaSet](cm.GetScheme(), cm.GetRESTMapper(), &appsv1.Deployment{}),
85+
makeNamespacePredicate[*appsv1.ReplicaSet](testNamespace),
7086
),
7187
)
7288
Expect(err).NotTo(HaveOccurred())
7389

74-
err = instance.Watch(source.Kind(cm.GetCache(), &appsv1.Deployment{}, &handler.TypedEnqueueRequestForObject[*appsv1.Deployment]{}))
90+
err = instance.Watch(
91+
source.Kind(cm.GetCache(), &appsv1.Deployment{},
92+
&handler.TypedEnqueueRequestForObject[*appsv1.Deployment]{},
93+
makeNamespacePredicate[*appsv1.Deployment](testNamespace),
94+
),
95+
)
7596
Expect(err).NotTo(HaveOccurred())
7697

7798
err = cm.GetClient().Get(ctx, types.NamespacedName{Name: "foo"}, &corev1.Namespace{})
@@ -110,19 +131,25 @@ var _ = Describe("controller", func() {
110131
},
111132
}
112133
expectedReconcileRequest := reconcile.Request{NamespacedName: types.NamespacedName{
113-
Namespace: "default",
134+
Namespace: testNamespace,
114135
Name: "deployment-name",
115136
}}
116137

138+
By("Creating the test namespace")
139+
_, err = clientset.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{
140+
ObjectMeta: metav1.ObjectMeta{ Name: testNamespace },
141+
}, metav1.CreateOptions{})
142+
Expect(err).NotTo(HaveOccurred())
143+
117144
By("Invoking Reconciling for Create")
118-
deployment, err = clientset.AppsV1().Deployments("default").Create(ctx, deployment, metav1.CreateOptions{})
145+
deployment, err = clientset.AppsV1().Deployments(testNamespace).Create(ctx, deployment, metav1.CreateOptions{})
119146
Expect(err).NotTo(HaveOccurred())
120147
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
121148

122149
By("Invoking Reconciling for Update")
123150
newDeployment := deployment.DeepCopy()
124151
newDeployment.Labels = map[string]string{"foo": "bar"}
125-
_, err = clientset.AppsV1().Deployments("default").Update(ctx, newDeployment, metav1.UpdateOptions{})
152+
_, err = clientset.AppsV1().Deployments(testNamespace).Update(ctx, newDeployment, metav1.UpdateOptions{})
126153
Expect(err).NotTo(HaveOccurred())
127154
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
128155

@@ -145,24 +172,24 @@ var _ = Describe("controller", func() {
145172
Template: deployment.Spec.Template,
146173
},
147174
}
148-
replicaset, err = clientset.AppsV1().ReplicaSets("default").Create(ctx, replicaset, metav1.CreateOptions{})
175+
replicaset, err = clientset.AppsV1().ReplicaSets(testNamespace).Create(ctx, replicaset, metav1.CreateOptions{})
149176
Expect(err).NotTo(HaveOccurred())
150177
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
151178

152179
By("Invoking Reconciling for an OwnedObject when it is updated")
153180
newReplicaset := replicaset.DeepCopy()
154181
newReplicaset.Labels = map[string]string{"foo": "bar"}
155-
_, err = clientset.AppsV1().ReplicaSets("default").Update(ctx, newReplicaset, metav1.UpdateOptions{})
182+
_, err = clientset.AppsV1().ReplicaSets(testNamespace).Update(ctx, newReplicaset, metav1.UpdateOptions{})
156183
Expect(err).NotTo(HaveOccurred())
157184
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
158185

159186
By("Invoking Reconciling for an OwnedObject when it is deleted")
160-
err = clientset.AppsV1().ReplicaSets("default").Delete(ctx, replicaset.Name, metav1.DeleteOptions{})
187+
err = clientset.AppsV1().ReplicaSets(testNamespace).Delete(ctx, replicaset.Name, metav1.DeleteOptions{})
161188
Expect(err).NotTo(HaveOccurred())
162189
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
163190

164191
By("Invoking Reconciling for Delete")
165-
err = clientset.AppsV1().Deployments("default").
192+
err = clientset.AppsV1().Deployments(testNamespace).
166193
Delete(ctx, "deployment-name", metav1.DeleteOptions{})
167194
Expect(err).NotTo(HaveOccurred())
168195
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
@@ -174,7 +201,12 @@ var _ = Describe("controller", func() {
174201

175202
By("Invoking Reconciling for a pod when it is created when adding watcher dynamically")
176203
// Add new watcher dynamically
177-
err = instance.Watch(source.Kind(cm.GetCache(), &corev1.Pod{}, &handler.TypedEnqueueRequestForObject[*corev1.Pod]{}))
204+
err = instance.Watch(
205+
source.Kind(cm.GetCache(), &corev1.Pod{},
206+
&handler.TypedEnqueueRequestForObject[*corev1.Pod]{},
207+
makeNamespacePredicate[*corev1.Pod](testNamespace),
208+
),
209+
)
178210
Expect(err).NotTo(HaveOccurred())
179211

180212
pod := &corev1.Pod{
@@ -194,16 +226,27 @@ var _ = Describe("controller", func() {
194226
},
195227
}
196228
expectedReconcileRequest = reconcile.Request{NamespacedName: types.NamespacedName{
197-
Namespace: "default",
229+
Namespace: testNamespace,
198230
Name: "pod-name",
199231
}}
200-
_, err = clientset.CoreV1().Pods("default").Create(ctx, pod, metav1.CreateOptions{})
232+
_, err = clientset.CoreV1().Pods(testNamespace).Create(ctx, pod, metav1.CreateOptions{})
201233
Expect(err).NotTo(HaveOccurred())
202234
Expect(<-reconciled).To(Equal(expectedReconcileRequest))
203-
})
235+
},
236+
Entry("with controller warmup enabled", true),
237+
Entry("with controller warmup not enabled", false),
238+
)
204239
})
205240
})
206241

242+
// makeNamespacePredicate returns a predicate that filters out all objects not in the passed in
243+
// namespace.
244+
func makeNamespacePredicate[object client.Object](namespace string) predicate.TypedPredicate[object] {
245+
return predicate.NewTypedPredicateFuncs[object](func(obj object) bool {
246+
return obj.GetNamespace() == namespace
247+
})
248+
}
249+
207250
func truePtr() *bool {
208251
t := true
209252
return &t

pkg/manager/internal/integration/manager_test.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ import (
3434
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3535
"k8s.io/apimachinery/pkg/runtime"
3636
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
37+
"k8s.io/utils/ptr"
3738
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
3839

3940
ctrl "sigs.k8s.io/controller-runtime"
4041
"sigs.k8s.io/controller-runtime/pkg/client"
42+
"sigs.k8s.io/controller-runtime/pkg/controller"
4143
"sigs.k8s.io/controller-runtime/pkg/envtest"
4244
logf "sigs.k8s.io/controller-runtime/pkg/log"
4345
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -90,6 +92,8 @@ var (
9092
},
9193
},
9294
}
95+
96+
ctx = ctrl.SetupSignalHandler()
9397
)
9498

9599
var _ = Describe("manger.Manager Start", func() {
@@ -107,9 +111,7 @@ var _ = Describe("manger.Manager Start", func() {
107111
// * Add an index on v2 Driver to ensure we start and wait for an informer during cache.Start (as part of manager.Start)
108112
// * Note: cache.Start would fail if the conversion webhook doesn't work (which in turn depends on the readiness probe)
109113
// * Note: Adding the index for v2 ensures the Driver list call during Informer sync goes through conversion.
110-
It("should start all components without deadlock", func() {
111-
ctx := ctrl.SetupSignalHandler()
112-
114+
DescribeTable("should start all components without deadlock", func(warmupEnabled bool) {
113115
// Set up schema.
114116
Expect(clientgoscheme.AddToScheme(scheme)).To(Succeed())
115117
Expect(apiextensionsv1.AddToScheme(scheme)).To(Succeed())
@@ -163,7 +165,13 @@ var _ = Describe("manger.Manager Start", func() {
163165
driverReconciler := &DriverReconciler{
164166
Client: mgr.GetClient(),
165167
}
166-
Expect(ctrl.NewControllerManagedBy(mgr).For(&crewv2.Driver{}).Complete(driverReconciler)).To(Succeed())
168+
Expect(
169+
ctrl.NewControllerManagedBy(mgr).
170+
For(&crewv2.Driver{}).
171+
Named(fmt.Sprintf("driver_warmup_%t", warmupEnabled)).
172+
WithOptions(controller.Options{EnableWarmup: ptr.To(warmupEnabled)}).
173+
Complete(driverReconciler),
174+
).To(Succeed())
167175

168176
// Set up a conversion webhook.
169177
conversionWebhook := createConversionWebhook(mgr)
@@ -211,7 +219,10 @@ var _ = Describe("manger.Manager Start", func() {
211219

212220
// Shutdown the server
213221
cancel()
214-
})
222+
},
223+
Entry("controller warmup enabled", true),
224+
Entry("controller warmup not enabled", false),
225+
)
215226
})
216227

217228
type DriverReconciler struct {

0 commit comments

Comments
 (0)