Skip to content

Commit f494d7f

Browse files
add operator-test
Signed-off-by: Takeshi Yoshimura <[email protected]>
1 parent 52a8101 commit f494d7f

5 files changed

+660
-5
lines changed

Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ vet: ## Run go vet against code.
107107
.PHONY: operator-test
108108
operator-test: manifests generate fmt vet envtest ## Run tests.
109109
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./controllers/... -coverprofile operator-cover.out
110+
go tool cover -html=operator-cover.out -o operator-cover.html
110111

111112
##@ Build
112113

@@ -279,6 +280,6 @@ uploader-push: uploader-cbuild
279280
docker push $(UPLOADER_IMAGE_TAG_BASE):$(VERSION)
280281

281282
.PHONY: uploader-test
282-
uploader-test: fmt vet envtest ## Run tests.
283-
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./cmd/... -coverprofile uploader-cover.out
283+
uploader-test: fmt vet ## Run tests.
284+
go test ./cmd/... -coverprofile uploader-cover.out
284285
go tool cover -html=uploader-cover.out -o uploader-cover.html

config/crd/bases/charts.ibm.com_coredumphandlers.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ spec:
596596
type: object
597597
type: array
598598
uploaderImage:
599-
default: ghcr.io/ibm/core-dump-operator/core-dump-uploader:0.0.1
599+
default: ghcr.io/ibm/core-dump-operator/core-dump-uploader:v0.0.1
600600
description: UploaderImage is the image for core-dump-uploader to
601601
upload zip files generated by handlerImage containers
602602
type: string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
chartsv1alpha1 "github.com/IBM/core-dump-operator/api/v1alpha1"
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
securityv1 "github.com/openshift/api/security/v1"
11+
appsv1 "k8s.io/api/apps/v1"
12+
corev1 "k8s.io/api/core/v1"
13+
"k8s.io/apimachinery/pkg/api/errors"
14+
"k8s.io/apimachinery/pkg/api/resource"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"k8s.io/apimachinery/pkg/types"
17+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
18+
)
19+
20+
func createCoreDumpHandler(ctx context.Context, cdhName string, namespaceName string, openShift bool) error {
21+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
22+
err := k8sClient.Get(ctx, typedNamespaceName, &chartsv1alpha1.CoreDumpHandler{})
23+
if err != nil && errors.IsNotFound(err) {
24+
// Let's mock our custom resource at the same way that we would
25+
// apply on the cluster the manifest under config/samples
26+
cdh := &chartsv1alpha1.CoreDumpHandler{
27+
ObjectMeta: metav1.ObjectMeta{
28+
Name: typedNamespaceName.Name,
29+
Namespace: typedNamespaceName.Namespace,
30+
},
31+
Spec: chartsv1alpha1.CoreDumpHandlerSpec{
32+
OpenShift: openShift,
33+
ImagePullSecret: "secret",
34+
ServiceAccount: "sa",
35+
NodeSelector: map[string]string{"node": "selector"},
36+
Tolerations: []corev1.Toleration{{Key: "key", Operator: "Exists", Effect: "NoSchedule"}},
37+
Affinity: &chartsv1alpha1.AffinityApplyConfiguration{},
38+
NamespaceLabelSelector: map[string]string{"cdh": "enabled"},
39+
Resource: &corev1.ResourceRequirements{
40+
Limits: corev1.ResourceList{"cpu": *resource.NewQuantity(1, resource.DecimalSI)},
41+
Requests: corev1.ResourceList{"cpu": *resource.NewQuantity(1, resource.DecimalSI)},
42+
},
43+
},
44+
}
45+
46+
err = k8sClient.Create(ctx, cdh)
47+
}
48+
return err
49+
}
50+
51+
func deleteCoreDumpHandler(ctx context.Context, cdhName string, namespaceName string) error {
52+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
53+
err := k8sClient.Get(ctx, typedNamespaceName, &chartsv1alpha1.CoreDumpHandler{})
54+
if err == nil {
55+
cdh := &chartsv1alpha1.CoreDumpHandler{
56+
ObjectMeta: metav1.ObjectMeta{
57+
Name: typedNamespaceName.Name,
58+
Namespace: typedNamespaceName.Namespace,
59+
},
60+
}
61+
err = k8sClient.Delete(ctx, cdh)
62+
}
63+
return err
64+
}
65+
66+
func testCreateDeleteCoreDumpHandler(cdhName string, namespaceName string, openShift bool) {
67+
It("should successfully reconcile creating and deleting a custom resource for CoreDumpHandler", func() {
68+
By("Creating the custom resource for the Kind CoreDumpHandler")
69+
ctx := context.Background()
70+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
71+
err := createCoreDumpHandler(ctx, cdhName, namespaceName, openShift)
72+
Expect(err).To(Not(HaveOccurred()))
73+
74+
By("Checking if the custom resource was successfully created")
75+
Eventually(func() error {
76+
found := &chartsv1alpha1.CoreDumpHandler{}
77+
return k8sClient.Get(ctx, typedNamespaceName, found)
78+
}, time.Minute, time.Second).Should(Succeed())
79+
80+
By("Reconciling the custom resource created")
81+
cdhReconciler := &CoreDumpHandlerReconciler{
82+
Client: k8sClient, Scheme: k8sClient.Scheme(),
83+
}
84+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
85+
NamespacedName: typedNamespaceName,
86+
})
87+
Expect(err).To(Not(HaveOccurred()))
88+
89+
By("Checking if DaemonSet was successfully created in the reconciliation")
90+
Eventually(func() error {
91+
found := &appsv1.DaemonSet{}
92+
return k8sClient.Get(ctx, typedNamespaceName, found)
93+
}, time.Minute, time.Second).Should(Succeed())
94+
95+
if openShift {
96+
By("Checking if SCC was successfully created in the reconciliation")
97+
Eventually(func() error {
98+
found := &securityv1.SecurityContextConstraints{}
99+
return k8sClient.Get(ctx, typedNamespaceName, found)
100+
}, time.Minute, time.Second).Should(Succeed())
101+
}
102+
103+
By("Removing the custom ressource for the Kind CoreDumpHandler")
104+
Eventually(func() error {
105+
return deleteCoreDumpHandler(ctx, cdhName, namespaceName)
106+
}, time.Minute, time.Second).Should(Succeed())
107+
108+
By("Reconciling the custom resource deleted")
109+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
110+
NamespacedName: typedNamespaceName,
111+
})
112+
Expect(err).To(Not(HaveOccurred()))
113+
114+
By("Checking if DaemonSet was successfully deleted in the reconciliation")
115+
Eventually(func() error {
116+
found := &appsv1.DaemonSet{}
117+
return k8sClient.Get(ctx, typedNamespaceName, found)
118+
}, time.Minute, time.Second).ShouldNot(Succeed())
119+
120+
By("Checking if SCC was successfully deleted in the reconciliation")
121+
Eventually(func() error {
122+
found := &securityv1.SecurityContextConstraints{}
123+
return k8sClient.Get(ctx, typedNamespaceName, found)
124+
}, time.Minute, time.Second).ShouldNot(Succeed())
125+
})
126+
}
127+
128+
func testDeleteAfterOperatorRestart() {
129+
It("should successfully reconcile deleting a custom resource for CoreDumpHandler at operator restart", func() {
130+
By("Creating the custom resource for the Kind CoreDumpHandler")
131+
ctx := context.Background()
132+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
133+
err := createCoreDumpHandler(ctx, cdhName, namespaceName, true)
134+
Expect(err).To(Not(HaveOccurred()))
135+
136+
By("Reconciling the custom resource created")
137+
cdhReconciler := &CoreDumpHandlerReconciler{
138+
Client: k8sClient, Scheme: k8sClient.Scheme(),
139+
}
140+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
141+
NamespacedName: typedNamespaceName,
142+
})
143+
Expect(err).To(Not(HaveOccurred()))
144+
145+
By("Reconciling the custom resource created second time")
146+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
147+
NamespacedName: typedNamespaceName,
148+
})
149+
Expect(err).To(Not(HaveOccurred()))
150+
151+
By("Removing the Daemonset manually")
152+
Eventually(func() error {
153+
return k8sClient.Delete(ctx, &appsv1.DaemonSet{ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName}})
154+
}, time.Minute, time.Second).Should(Succeed())
155+
156+
By("Removing the SCC manually")
157+
Eventually(func() error {
158+
return k8sClient.Delete(ctx, &securityv1.SecurityContextConstraints{ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName}})
159+
}, time.Minute, time.Second).Should(Succeed())
160+
161+
By("Removing the custom ressource for the Kind CoreDumpHandler")
162+
Eventually(func() error {
163+
return deleteCoreDumpHandler(ctx, cdhName, namespaceName)
164+
}, time.Minute, time.Second).Should(Succeed())
165+
166+
By("Reconciling the custom resource deleted")
167+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
168+
NamespacedName: typedNamespaceName,
169+
})
170+
Expect(err).To(Not(HaveOccurred()))
171+
172+
By("Checking if DaemonSet was successfully deleted in the reconciliation")
173+
Eventually(func() error {
174+
found := &appsv1.DaemonSet{}
175+
return k8sClient.Get(ctx, typedNamespaceName, found)
176+
}, time.Minute, time.Second).ShouldNot(Succeed())
177+
178+
By("Checking if SCC was successfully deleted in the reconciliation")
179+
Eventually(func() error {
180+
found := &securityv1.SecurityContextConstraints{}
181+
return k8sClient.Get(ctx, typedNamespaceName, found)
182+
}, time.Minute, time.Second).ShouldNot(Succeed())
183+
})
184+
}
185+
186+
func testCreateOnUserDelete() {
187+
It("should successfully reconcile creating a custom resource for CoreDumpHandler at random user deletion", func() {
188+
By("Creating the custom resource for the Kind CoreDumpHandler")
189+
ctx := context.Background()
190+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
191+
err := createCoreDumpHandler(ctx, cdhName, namespaceName, true)
192+
Expect(err).To(Not(HaveOccurred()))
193+
194+
By("Reconciling the custom resource created")
195+
cdhReconciler := &CoreDumpHandlerReconciler{
196+
Client: k8sClient, Scheme: k8sClient.Scheme(),
197+
}
198+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
199+
NamespacedName: typedNamespaceName,
200+
})
201+
Expect(err).To(Not(HaveOccurred()))
202+
203+
err = k8sClient.Delete(ctx, &appsv1.DaemonSet{ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName}})
204+
Expect(err).To(Not(HaveOccurred()))
205+
206+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
207+
NamespacedName: typedNamespaceName,
208+
})
209+
Expect(err).To(Not(HaveOccurred()))
210+
211+
By("Checking if DaemonSet was successfully created in the reconciliation")
212+
Eventually(func() error {
213+
found := &appsv1.DaemonSet{}
214+
return k8sClient.Get(ctx, typedNamespaceName, found)
215+
}, time.Minute, time.Second).Should(Succeed())
216+
217+
By("Checking if SCC was successfully created in the reconciliation")
218+
Eventually(func() error {
219+
found := &securityv1.SecurityContextConstraints{}
220+
return k8sClient.Get(ctx, typedNamespaceName, found)
221+
}, time.Minute, time.Second).Should(Succeed())
222+
223+
err = k8sClient.Delete(ctx, &securityv1.SecurityContextConstraints{ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName}})
224+
Expect(err).To(Not(HaveOccurred()))
225+
226+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
227+
NamespacedName: typedNamespaceName,
228+
})
229+
Expect(err).To(Not(HaveOccurred()))
230+
231+
By("Checking if DaemonSet was successfully created in the reconciliation")
232+
Eventually(func() error {
233+
found := &appsv1.DaemonSet{}
234+
return k8sClient.Get(ctx, typedNamespaceName, found)
235+
}, time.Minute, time.Second).Should(Succeed())
236+
237+
By("Checking if SCC was successfully created in the reconciliation")
238+
Eventually(func() error {
239+
found := &securityv1.SecurityContextConstraints{}
240+
return k8sClient.Get(ctx, typedNamespaceName, found)
241+
}, time.Minute, time.Second).Should(Succeed())
242+
243+
By("Removing the custom ressource for the Kind CoreDumpHandler")
244+
Eventually(func() error {
245+
return deleteCoreDumpHandler(ctx, cdhName, namespaceName)
246+
}, time.Minute, time.Second).Should(Succeed())
247+
248+
By("Reconciling the custom resource deleted")
249+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
250+
NamespacedName: typedNamespaceName,
251+
})
252+
Expect(err).To(Not(HaveOccurred()))
253+
})
254+
}
255+
256+
func testCreateOnUserModify() {
257+
It("should successfully reconcile creating a custom resource for CoreDumpHandler at random user modify", func() {
258+
ctx := context.Background()
259+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
260+
261+
By("Creating the Daemonset manually")
262+
err := k8sClient.Create(ctx, &appsv1.DaemonSet{
263+
ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName},
264+
Spec: appsv1.DaemonSetSpec{
265+
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "core-dump-handler", "cluster": "test-cdh"}},
266+
Template: corev1.PodTemplateSpec{
267+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"app": "core-dump-handler", "cluster": "test-cdh"}},
268+
Spec: corev1.PodSpec{Containers: []corev1.Container{
269+
{Name: "test", Image: "image:latest"},
270+
}},
271+
},
272+
},
273+
})
274+
Expect(err).To(Not(HaveOccurred()))
275+
276+
By("Creating the SCC manually")
277+
err = k8sClient.Create(ctx, &securityv1.SecurityContextConstraints{
278+
ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName},
279+
})
280+
Expect(err).To(Not(HaveOccurred()))
281+
282+
By("Creating the custom resource for the Kind CoreDumpHandler")
283+
err = createCoreDumpHandler(ctx, cdhName, namespaceName, true)
284+
Expect(err).To(Not(HaveOccurred()))
285+
286+
By("Reconciling the custom resource created")
287+
cdhReconciler := &CoreDumpHandlerReconciler{
288+
Client: k8sClient, Scheme: k8sClient.Scheme(),
289+
}
290+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
291+
NamespacedName: typedNamespaceName,
292+
})
293+
Expect(err).To(Not(HaveOccurred()))
294+
295+
err = k8sClient.Delete(ctx, &appsv1.DaemonSet{ObjectMeta: metav1.ObjectMeta{Name: cdhName, Namespace: namespaceName}})
296+
Expect(err).To(Not(HaveOccurred()))
297+
298+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
299+
NamespacedName: typedNamespaceName,
300+
})
301+
Expect(err).To(Not(HaveOccurred()))
302+
303+
By("Checking if DaemonSet was successfully created in the reconciliation")
304+
Eventually(func() error {
305+
found := &appsv1.DaemonSet{}
306+
return k8sClient.Get(ctx, typedNamespaceName, found)
307+
}, time.Minute, time.Second).Should(Succeed())
308+
309+
By("Checking if SCC was successfully created in the reconciliation")
310+
Eventually(func() error {
311+
found := &securityv1.SecurityContextConstraints{}
312+
return k8sClient.Get(ctx, typedNamespaceName, found)
313+
}, time.Minute, time.Second).Should(Succeed())
314+
315+
By("Removing the custom ressource for the Kind CoreDumpHandler")
316+
Eventually(func() error {
317+
return deleteCoreDumpHandler(ctx, cdhName, namespaceName)
318+
}, time.Minute, time.Second).Should(Succeed())
319+
320+
By("Reconciling the custom resource deleted")
321+
_, err = cdhReconciler.Reconcile(ctx, reconcile.Request{
322+
NamespacedName: typedNamespaceName,
323+
})
324+
Expect(err).To(Not(HaveOccurred()))
325+
})
326+
}
327+
328+
func testEmptyRequest() {
329+
It("should successfully reconcile empty requests by ignoring them", func() {
330+
ctx := context.Background()
331+
typedNamespaceName := types.NamespacedName{Name: cdhName, Namespace: namespaceName}
332+
333+
By("Reconciling the custom resource for empty (race condition?)")
334+
cdhReconciler := &CoreDumpHandlerReconciler{
335+
Client: k8sClient, Scheme: k8sClient.Scheme(),
336+
}
337+
338+
_, err := cdhReconciler.Reconcile(ctx, reconcile.Request{
339+
NamespacedName: typedNamespaceName,
340+
})
341+
Expect(err).To(Not(HaveOccurred()))
342+
})
343+
}
344+
345+
var _ = Describe("CoreDumpHandler controller", func() {
346+
Context("CoreDumpHandler controller test", func() {
347+
testCreateDeleteCoreDumpHandler(cdhName, namespaceName, true)
348+
testCreateDeleteCoreDumpHandler(cdhName, namespaceName, false)
349+
testCreateOnUserDelete()
350+
testDeleteAfterOperatorRestart()
351+
testCreateOnUserModify()
352+
testEmptyRequest()
353+
})
354+
})

0 commit comments

Comments
 (0)