Skip to content

Commit f4b530e

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 b48c4b2 commit f4b530e

3 files changed

Lines changed: 631 additions & 0 deletions

File tree

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
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+
},
213+
},
214+
}
215+
216+
for _, tc := range testCases {
217+
t.Run(tc.name, func(t *testing.T) {
218+
t.Parallel()
219+
g := NewWithT(t)
220+
221+
obj, gvk, err := LoadManifest(tc.componentName, tc.fileName)
222+
tc.validate(g, obj, gvk, err)
223+
})
224+
}
225+
}
226+
227+
func TestLoadManifestInto(t *testing.T) {
228+
t.Parallel()
229+
230+
testCases := []struct {
231+
name string
232+
componentName string
233+
fileName string
234+
into client.Object
235+
validate func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error)
236+
}{
237+
{
238+
name: "When loading into a pre-allocated ServiceAccount, it should populate the object",
239+
componentName: "cluster-autoscaler",
240+
fileName: "serviceaccount.yaml",
241+
into: &corev1.ServiceAccount{},
242+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
243+
g.Expect(err).ToNot(HaveOccurred())
244+
g.Expect(obj).ToNot(BeNil())
245+
g.Expect(gvk).ToNot(BeNil())
246+
g.Expect(gvk.Kind).To(Equal("ServiceAccount"))
247+
sa, ok := obj.(*corev1.ServiceAccount)
248+
g.Expect(ok).To(BeTrue())
249+
g.Expect(sa.Name).To(Equal("cluster-autoscaler"))
250+
},
251+
},
252+
{
253+
name: "When loading into nil, it should create a new object",
254+
componentName: "cluster-autoscaler",
255+
fileName: "serviceaccount.yaml",
256+
into: nil,
257+
validate: func(g Gomega, obj client.Object, gvk *schema.GroupVersionKind, err error) {
258+
g.Expect(err).ToNot(HaveOccurred())
259+
g.Expect(obj).ToNot(BeNil())
260+
g.Expect(gvk).ToNot(BeNil())
261+
g.Expect(gvk.Kind).To(Equal("ServiceAccount"))
262+
},
263+
},
264+
}
265+
266+
for _, tc := range testCases {
267+
t.Run(tc.name, func(t *testing.T) {
268+
t.Parallel()
269+
g := NewWithT(t)
270+
271+
obj, gvk, err := LoadManifestInto(tc.componentName, tc.fileName, tc.into)
272+
tc.validate(g, obj, gvk, err)
273+
})
274+
}
275+
}
276+
277+
func TestForEachManifest(t *testing.T) {
278+
t.Parallel()
279+
280+
testCases := []struct {
281+
name string
282+
componentName string
283+
validate func(g Gomega, manifestNames []string, err error)
284+
}{
285+
{
286+
name: "When iterating over cluster-autoscaler manifests, it should skip deployment and call action for others",
287+
componentName: "cluster-autoscaler",
288+
validate: func(g Gomega, manifestNames []string, err error) {
289+
g.Expect(err).ToNot(HaveOccurred())
290+
g.Expect(manifestNames).To(ContainElement("serviceaccount.yaml"))
291+
g.Expect(manifestNames).To(ContainElement("role.yaml"))
292+
g.Expect(manifestNames).To(ContainElement("rolebinding.yaml"))
293+
g.Expect(manifestNames).To(ContainElement("podmonitor.yaml"))
294+
g.Expect(manifestNames).ToNot(ContainElement("deployment.yaml"))
295+
},
296+
},
297+
{
298+
name: "When iterating over etcd manifests, it should skip statefulset and call action for others",
299+
componentName: "etcd",
300+
validate: func(g Gomega, manifestNames []string, err error) {
301+
g.Expect(err).ToNot(HaveOccurred())
302+
g.Expect(manifestNames).To(ContainElement("service.yaml"))
303+
g.Expect(manifestNames).To(ContainElement("discovery-service.yaml"))
304+
g.Expect(manifestNames).ToNot(ContainElement("statefulset.yaml"))
305+
},
306+
},
307+
{
308+
name: "When iterating over openshift-controller-manager manifests, it should skip deployment and call action for others",
309+
componentName: "openshift-controller-manager",
310+
validate: func(g Gomega, manifestNames []string, err error) {
311+
g.Expect(err).ToNot(HaveOccurred())
312+
g.Expect(manifestNames).To(ContainElement("config.yaml"))
313+
g.Expect(manifestNames).To(ContainElement("service.yaml"))
314+
g.Expect(manifestNames).ToNot(ContainElement("deployment.yaml"))
315+
},
316+
},
317+
{
318+
name: "When iterating over featuregate-generator manifests, it should skip job and call action for others",
319+
componentName: "featuregate-generator",
320+
validate: func(g Gomega, manifestNames []string, err error) {
321+
g.Expect(err).ToNot(HaveOccurred())
322+
// featuregate-generator only has job.yaml, so no other manifests
323+
g.Expect(manifestNames).To(BeEmpty())
324+
},
325+
},
326+
{
327+
name: "When component does not exist, it should return an error",
328+
componentName: "nonexistent-component",
329+
validate: func(g Gomega, manifestNames []string, err error) {
330+
g.Expect(err).To(HaveOccurred())
331+
},
332+
},
333+
}
334+
335+
for _, tc := range testCases {
336+
t.Run(tc.name, func(t *testing.T) {
337+
t.Parallel()
338+
g := NewWithT(t)
339+
340+
var manifestNames []string
341+
err := ForEachManifest(tc.componentName, func(manifestName string) error {
342+
manifestNames = append(manifestNames, manifestName)
343+
return nil
344+
})
345+
346+
tc.validate(g, manifestNames, err)
347+
})
348+
}
349+
}
350+
351+
func TestForEachManifestWithActionError(t *testing.T) {
352+
t.Parallel()
353+
g := NewWithT(t)
354+
355+
expectedErr := &testError{msg: "action failed"}
356+
357+
err := ForEachManifest("cluster-autoscaler", func(manifestName string) error {
358+
if manifestName == "role.yaml" {
359+
return expectedErr
360+
}
361+
return nil
362+
})
363+
364+
g.Expect(err).To(HaveOccurred())
365+
g.Expect(err).To(Equal(expectedErr))
366+
}
367+
368+
type testError struct {
369+
msg string
370+
}
371+
372+
func (e *testError) Error() string {
373+
return e.msg
374+
}

0 commit comments

Comments
 (0)