Skip to content

Commit 5b7f608

Browse files
bryan-coxclaude
andcommitted
test: Add unit tests for v2 infrastructure controller packages
Add behavior-driven unit tests for the assets and feature gate v2 controller packages covering manifest loading, deserialization, iteration, and feature gate job adaptation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 23bb050 commit 5b7f608

3 files changed

Lines changed: 623 additions & 0 deletions

File tree

Lines changed: 385 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,385 @@
1+
package assets
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/onsi/gomega"
7+
8+
appsv1 "k8s.io/api/apps/v1"
9+
batchv1 "k8s.io/api/batch/v1"
10+
corev1 "k8s.io/api/core/v1"
11+
"k8s.io/apimachinery/pkg/runtime/schema"
12+
13+
"sigs.k8s.io/controller-runtime/pkg/client"
14+
)
15+
16+
func TestLoadDeploymentManifest(t *testing.T) {
17+
t.Parallel()
18+
19+
testCases := []struct {
20+
name string
21+
componentName string
22+
validate func(g Gomega, deployment *appsv1.Deployment, err error)
23+
}{
24+
{
25+
name: "When loading a valid deployment manifest, it should decode successfully",
26+
componentName: "aws-cloud-controller-manager",
27+
validate: func(g Gomega, deployment *appsv1.Deployment, err error) {
28+
g.Expect(err).ToNot(HaveOccurred())
29+
g.Expect(deployment).ToNot(BeNil())
30+
g.Expect(deployment.Kind).To(Equal("Deployment"))
31+
g.Expect(deployment.Name).To(Equal("cloud-controller-manager"))
32+
},
33+
},
34+
{
35+
name: "When component name does not exist, it should return an error",
36+
componentName: "nonexistent-component",
37+
validate: func(g Gomega, deployment *appsv1.Deployment, err error) {
38+
g.Expect(err).To(HaveOccurred())
39+
g.Expect(deployment).To(BeNil())
40+
},
41+
},
42+
}
43+
44+
for _, tc := range testCases {
45+
t.Run(tc.name, func(t *testing.T) {
46+
t.Parallel()
47+
g := NewWithT(t)
48+
49+
deployment, err := LoadDeploymentManifest(tc.componentName)
50+
tc.validate(g, deployment, err)
51+
})
52+
}
53+
}
54+
55+
func TestLoadStatefulSetManifest(t *testing.T) {
56+
t.Parallel()
57+
58+
testCases := []struct {
59+
name string
60+
componentName string
61+
validate func(g Gomega, sts *appsv1.StatefulSet, err error)
62+
}{
63+
{
64+
name: "When loading a valid statefulset manifest, it should decode successfully",
65+
componentName: "etcd",
66+
validate: func(g Gomega, sts *appsv1.StatefulSet, err error) {
67+
g.Expect(err).ToNot(HaveOccurred())
68+
g.Expect(sts).ToNot(BeNil())
69+
g.Expect(sts.Kind).To(Equal("StatefulSet"))
70+
g.Expect(sts.Name).To(Equal("etcd"))
71+
},
72+
},
73+
{
74+
name: "When component name does not exist, it should return an error",
75+
componentName: "nonexistent-component",
76+
validate: func(g Gomega, sts *appsv1.StatefulSet, err error) {
77+
g.Expect(err).To(HaveOccurred())
78+
g.Expect(sts).To(BeNil())
79+
},
80+
},
81+
}
82+
83+
for _, tc := range testCases {
84+
t.Run(tc.name, func(t *testing.T) {
85+
t.Parallel()
86+
g := NewWithT(t)
87+
88+
sts, err := LoadStatefulSetManifest(tc.componentName)
89+
tc.validate(g, sts, err)
90+
})
91+
}
92+
}
93+
94+
func TestLoadCronJobManifest(t *testing.T) {
95+
t.Parallel()
96+
97+
testCases := []struct {
98+
name string
99+
componentName string
100+
validate func(g Gomega, cronJob *batchv1.CronJob, err error)
101+
}{
102+
{
103+
name: "When loading a valid cronjob manifest, it should decode successfully",
104+
componentName: "olm-collect-profiles",
105+
validate: func(g Gomega, cronJob *batchv1.CronJob, err error) {
106+
g.Expect(err).ToNot(HaveOccurred())
107+
g.Expect(cronJob).ToNot(BeNil())
108+
g.Expect(cronJob.Kind).To(Equal("CronJob"))
109+
g.Expect(cronJob.Name).To(Equal("olm-collect-profiles"))
110+
},
111+
},
112+
{
113+
name: "When component name does not exist, it should return an error",
114+
componentName: "nonexistent-component",
115+
validate: func(g Gomega, cronJob *batchv1.CronJob, err error) {
116+
g.Expect(err).To(HaveOccurred())
117+
g.Expect(cronJob).To(BeNil())
118+
},
119+
},
120+
}
121+
122+
for _, tc := range testCases {
123+
t.Run(tc.name, func(t *testing.T) {
124+
t.Parallel()
125+
g := NewWithT(t)
126+
127+
cronJob, err := LoadCronJobManifest(tc.componentName)
128+
tc.validate(g, cronJob, err)
129+
})
130+
}
131+
}
132+
133+
func TestLoadJobManifest(t *testing.T) {
134+
t.Parallel()
135+
136+
testCases := []struct {
137+
name string
138+
componentName string
139+
validate func(g Gomega, job *batchv1.Job, err error)
140+
}{
141+
{
142+
name: "When loading a valid job manifest, it should decode successfully",
143+
componentName: "featuregate-generator",
144+
validate: func(g Gomega, job *batchv1.Job, err error) {
145+
g.Expect(err).ToNot(HaveOccurred())
146+
g.Expect(job).ToNot(BeNil())
147+
g.Expect(job.Kind).To(Equal("Job"))
148+
g.Expect(job.Name).To(Equal("featuregate-generator"))
149+
},
150+
},
151+
{
152+
name: "When component name does not exist, it should return an error",
153+
componentName: "nonexistent-component",
154+
validate: func(g Gomega, job *batchv1.Job, err error) {
155+
g.Expect(err).To(HaveOccurred())
156+
g.Expect(job).To(BeNil())
157+
},
158+
},
159+
}
160+
161+
for _, tc := range testCases {
162+
t.Run(tc.name, func(t *testing.T) {
163+
t.Parallel()
164+
g := NewWithT(t)
165+
166+
job, err := LoadJobManifest(tc.componentName)
167+
tc.validate(g, job, err)
168+
})
169+
}
170+
}
171+
172+
func TestLoadManifest(t *testing.T) {
173+
t.Parallel()
174+
175+
testCases := []struct {
176+
name string
177+
componentName string
178+
fileName string
179+
validate func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error)
180+
}{
181+
{
182+
name: "When loading a service manifest, it should decode successfully",
183+
componentName: "cluster-autoscaler",
184+
fileName: "serviceaccount.yaml",
185+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
186+
g.Expect(err).ToNot(HaveOccurred())
187+
g.Expect(obj).ToNot(BeNil())
188+
g.Expect(gvk).ToNot(BeNil())
189+
g.Expect(gvk.Kind).To(Equal("ServiceAccount"))
190+
sa, ok := obj.(*corev1.ServiceAccount)
191+
g.Expect(ok).To(BeTrue())
192+
g.Expect(sa.Name).To(Equal("cluster-autoscaler"))
193+
},
194+
},
195+
{
196+
name: "When loading a role manifest, it should decode successfully",
197+
componentName: "cluster-autoscaler",
198+
fileName: "role.yaml",
199+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
200+
g.Expect(err).ToNot(HaveOccurred())
201+
g.Expect(obj).ToNot(BeNil())
202+
g.Expect(gvk).ToNot(BeNil())
203+
g.Expect(gvk.Kind).To(Equal("Role"))
204+
},
205+
},
206+
{
207+
name: "When file does not exist, it should return an error",
208+
componentName: "cluster-autoscaler",
209+
fileName: "nonexistent.yaml",
210+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
211+
g.Expect(err).To(HaveOccurred())
212+
g.Expect(obj).To(BeNil())
213+
g.Expect(gvk).To(BeNil())
214+
},
215+
},
216+
}
217+
218+
for _, tc := range testCases {
219+
t.Run(tc.name, func(t *testing.T) {
220+
t.Parallel()
221+
g := NewWithT(t)
222+
223+
obj, gvk, err := LoadManifest(tc.componentName, tc.fileName)
224+
tc.validate(g, obj, gvk, err)
225+
})
226+
}
227+
}
228+
229+
func TestLoadManifestInto(t *testing.T) {
230+
t.Parallel()
231+
232+
testCases := []struct {
233+
name string
234+
componentName string
235+
fileName string
236+
into client.Object
237+
validate func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error)
238+
}{
239+
{
240+
name: "When loading into a pre-allocated ServiceAccount, it should populate the object",
241+
componentName: "cluster-autoscaler",
242+
fileName: "serviceaccount.yaml",
243+
into: &corev1.ServiceAccount{},
244+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
245+
g.Expect(err).ToNot(HaveOccurred())
246+
g.Expect(obj).ToNot(BeNil())
247+
g.Expect(gvk).ToNot(BeNil())
248+
g.Expect(gvk.Kind).To(Equal("ServiceAccount"))
249+
sa, ok := obj.(*corev1.ServiceAccount)
250+
g.Expect(ok).To(BeTrue())
251+
g.Expect(sa.Name).To(Equal("cluster-autoscaler"))
252+
},
253+
},
254+
{
255+
name: "When loading into nil, it should create a new object",
256+
componentName: "cluster-autoscaler",
257+
fileName: "serviceaccount.yaml",
258+
into: nil,
259+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
260+
g.Expect(err).ToNot(HaveOccurred())
261+
g.Expect(obj).ToNot(BeNil())
262+
g.Expect(gvk).ToNot(BeNil())
263+
g.Expect(gvk.Kind).To(Equal("ServiceAccount"))
264+
},
265+
},
266+
{
267+
name: "When file does not exist, it should return an error",
268+
componentName: "cluster-autoscaler",
269+
fileName: "nonexistent.yaml",
270+
into: &corev1.ServiceAccount{},
271+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
272+
g.Expect(err).To(HaveOccurred())
273+
},
274+
},
275+
}
276+
277+
for _, tc := range testCases {
278+
t.Run(tc.name, func(t *testing.T) {
279+
t.Parallel()
280+
g := NewWithT(t)
281+
282+
obj, gvk, err := LoadManifestInto(tc.componentName, tc.fileName, tc.into)
283+
tc.validate(g, obj, gvk, err)
284+
})
285+
}
286+
}
287+
288+
func TestForEachManifest(t *testing.T) {
289+
t.Parallel()
290+
291+
testCases := []struct {
292+
name string
293+
componentName string
294+
validate func(g Gomega, manifestNames []string, err error)
295+
}{
296+
{
297+
name: "When iterating over cluster-autoscaler manifests, it should skip deployment and call action for others",
298+
componentName: "cluster-autoscaler",
299+
validate: func(g Gomega, manifestNames []string, err error) {
300+
g.Expect(err).ToNot(HaveOccurred())
301+
g.Expect(manifestNames).To(ContainElement("serviceaccount.yaml"))
302+
g.Expect(manifestNames).To(ContainElement("role.yaml"))
303+
g.Expect(manifestNames).To(ContainElement("rolebinding.yaml"))
304+
g.Expect(manifestNames).To(ContainElement("podmonitor.yaml"))
305+
g.Expect(manifestNames).ToNot(ContainElement("deployment.yaml"))
306+
},
307+
},
308+
{
309+
name: "When iterating over etcd manifests, it should skip statefulset and call action for others",
310+
componentName: "etcd",
311+
validate: func(g Gomega, manifestNames []string, err error) {
312+
g.Expect(err).ToNot(HaveOccurred())
313+
g.Expect(manifestNames).To(ContainElement("service.yaml"))
314+
g.Expect(manifestNames).To(ContainElement("discovery-service.yaml"))
315+
g.Expect(manifestNames).ToNot(ContainElement("statefulset.yaml"))
316+
},
317+
},
318+
{
319+
name: "When iterating over openshift-controller-manager manifests, it should skip deployment and call action for others",
320+
componentName: "openshift-controller-manager",
321+
validate: func(g Gomega, manifestNames []string, err error) {
322+
g.Expect(err).ToNot(HaveOccurred())
323+
g.Expect(manifestNames).To(ContainElement("config.yaml"))
324+
g.Expect(manifestNames).To(ContainElement("service.yaml"))
325+
g.Expect(manifestNames).ToNot(ContainElement("deployment.yaml"))
326+
},
327+
},
328+
{
329+
name: "When iterating over featuregate-generator manifests, it should skip job and call action for others",
330+
componentName: "featuregate-generator",
331+
validate: func(g Gomega, manifestNames []string, err error) {
332+
g.Expect(err).ToNot(HaveOccurred())
333+
// featuregate-generator only has job.yaml, so no other manifests
334+
g.Expect(manifestNames).To(BeEmpty())
335+
},
336+
},
337+
{
338+
name: "When component does not exist, it should return an error",
339+
componentName: "nonexistent-component",
340+
validate: func(g Gomega, manifestNames []string, err error) {
341+
g.Expect(err).To(HaveOccurred())
342+
},
343+
},
344+
}
345+
346+
for _, tc := range testCases {
347+
t.Run(tc.name, func(t *testing.T) {
348+
t.Parallel()
349+
g := NewWithT(t)
350+
351+
var manifestNames []string
352+
err := ForEachManifest(tc.componentName, func(manifestName string) error {
353+
manifestNames = append(manifestNames, manifestName)
354+
return nil
355+
})
356+
357+
tc.validate(g, manifestNames, err)
358+
})
359+
}
360+
}
361+
362+
func TestForEachManifestWithActionError(t *testing.T) {
363+
t.Parallel()
364+
g := NewWithT(t)
365+
366+
expectedErr := &testError{msg: "action failed"}
367+
368+
err := ForEachManifest("cluster-autoscaler", func(manifestName string) error {
369+
if manifestName == "role.yaml" {
370+
return expectedErr
371+
}
372+
return nil
373+
})
374+
375+
g.Expect(err).To(HaveOccurred())
376+
g.Expect(err).To(Equal(expectedErr))
377+
}
378+
379+
type testError struct {
380+
msg string
381+
}
382+
383+
func (e *testError) Error() string {
384+
return e.msg
385+
}

0 commit comments

Comments
 (0)