Skip to content

Commit 7ca748b

Browse files
authored
fix(testcoverage): increase test converage to 60+ (#84)
* fix(testcoverage): increase test converage to 60+ * fix linting and tests
1 parent 3b820ff commit 7ca748b

4 files changed

Lines changed: 1902 additions & 30 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,6 @@ charts/**/*.tgz
3838
/dist
3939
.helm-charts
4040
CLAUDE.md
41-
CLAUDE.local.md
41+
CLAUDE.local.md
42+
/convo
43+
coverage.html

.testcoverage.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ exclude:
88
threshold:
99
# (optional; default 0)
1010
# Minimum coverage percentage required for individual files.
11-
file: 20
11+
file: 60
1212

1313
# (optional; default 0)
1414
# Minimum coverage percentage required for each package.
15-
package: 20
15+
package: 60
1616

1717
# (optional; default 0)
1818
# Minimum overall project coverage percentage required.
19-
total: 20
19+
total: 60

internal/controller/httpbin_controller_test.go

Lines changed: 228 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,67 +18,282 @@ package controller
1818

1919
import (
2020
"context"
21+
"time"
2122

2223
. "github.com/onsi/ginkgo/v2"
2324
. "github.com/onsi/gomega"
2425
"k8s.io/apimachinery/pkg/api/errors"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2527
"k8s.io/apimachinery/pkg/types"
2628
"sigs.k8s.io/controller-runtime/pkg/reconcile"
2729

28-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29-
3030
orchestratev1alpha1 "http-operator/api/v1alpha1"
3131
)
3232

3333
var _ = Describe("HttpBin Controller", func() {
34+
const (
35+
timeout = time.Second * 10
36+
interval = time.Millisecond * 250
37+
)
38+
3439
Context("When reconciling a resource", func() {
35-
const resourceName = "test-resource"
40+
const resourceName = "test-httpbin"
3641

3742
ctx := context.Background()
3843

3944
typeNamespacedName := types.NamespacedName{
4045
Name: resourceName,
41-
Namespace: "default", // TODO(user):Modify as needed
46+
Namespace: "default",
4247
}
43-
httpbin := &orchestratev1alpha1.HttpBin{}
4448

4549
BeforeEach(func() {
4650
By("creating the custom resource for the Kind HttpBin")
51+
httpbin := &orchestratev1alpha1.HttpBin{}
4752
err := k8sClient.Get(ctx, typeNamespacedName, httpbin)
4853
if err != nil && errors.IsNotFound(err) {
4954
resource := &orchestratev1alpha1.HttpBin{
5055
ObjectMeta: metav1.ObjectMeta{
5156
Name: resourceName,
5257
Namespace: "default",
5358
},
54-
// TODO(user): Specify other spec details if needed.
59+
Spec: orchestratev1alpha1.HttpBinSpec{
60+
EnableHTTPS: false,
61+
Region: "us-east-1",
62+
},
5563
}
5664
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
5765
}
5866
})
5967

6068
AfterEach(func() {
61-
// TODO(user): Cleanup logic after each test, like removing the resource instance.
6269
resource := &orchestratev1alpha1.HttpBin{}
6370
err := k8sClient.Get(ctx, typeNamespacedName, resource)
71+
if err == nil {
72+
By("Cleanup the specific resource instance HttpBin")
73+
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
74+
}
75+
// Also cleanup any HttpBinDeployment that was created
76+
deployment := &orchestratev1alpha1.HttpBinDeployment{}
77+
err = k8sClient.Get(ctx, typeNamespacedName, deployment)
78+
if err == nil {
79+
Expect(k8sClient.Delete(ctx, deployment)).To(Succeed())
80+
}
81+
})
82+
83+
It("should successfully reconcile and create HttpBinDeployment", func() {
84+
By("Reconciling the created resource")
85+
controllerReconciler := &HttpBinReconciler{
86+
RemoteClient: k8sClient,
87+
Scheme: k8sClient.Scheme(),
88+
}
89+
90+
result, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
91+
NamespacedName: typeNamespacedName,
92+
})
6493
Expect(err).NotTo(HaveOccurred())
94+
// Check that reconciliation requests a requeue
95+
Expect(result).NotTo(Equal(reconcile.Result{}))
96+
97+
By("Verifying HttpBinDeployment was created")
98+
httpBinDeployment := &orchestratev1alpha1.HttpBinDeployment{}
99+
Eventually(func() error {
100+
return k8sClient.Get(ctx, typeNamespacedName, httpBinDeployment)
101+
}, timeout, interval).Should(Succeed())
65102

66-
By("Cleanup the specific resource instance HttpBin")
67-
Expect(k8sClient.Delete(ctx, resource)).To(Succeed())
103+
Expect(httpBinDeployment.Spec.Service.Port).To(Equal(int32(443)))
68104
})
69-
It("should successfully reconcile the resource", func() {
70-
By("Reconciling the created resource")
105+
106+
It("should set correct port when EnableHTTPS is true", func() {
107+
By("Creating HttpBin with EnableHTTPS=true")
108+
httpsResourceName := "test-httpbin-https"
109+
httpsNamespacedName := types.NamespacedName{
110+
Name: httpsResourceName,
111+
Namespace: "default",
112+
}
113+
114+
resource := &orchestratev1alpha1.HttpBin{
115+
ObjectMeta: metav1.ObjectMeta{
116+
Name: httpsResourceName,
117+
Namespace: "default",
118+
},
119+
Spec: orchestratev1alpha1.HttpBinSpec{
120+
EnableHTTPS: true,
121+
},
122+
}
123+
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
124+
125+
defer func() {
126+
// Cleanup
127+
_ = k8sClient.Delete(ctx, resource)
128+
deployment := &orchestratev1alpha1.HttpBinDeployment{}
129+
_ = k8sClient.Get(ctx, httpsNamespacedName, deployment)
130+
_ = k8sClient.Delete(ctx, deployment)
131+
}()
132+
133+
By("Reconciling the resource")
134+
controllerReconciler := &HttpBinReconciler{
135+
RemoteClient: k8sClient,
136+
Scheme: k8sClient.Scheme(),
137+
}
138+
139+
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
140+
NamespacedName: httpsNamespacedName,
141+
})
142+
Expect(err).NotTo(HaveOccurred())
143+
144+
By("Verifying HttpBinDeployment has HTTPS port")
145+
httpBinDeployment := &orchestratev1alpha1.HttpBinDeployment{}
146+
Eventually(func() error {
147+
return k8sClient.Get(ctx, httpsNamespacedName, httpBinDeployment)
148+
}, timeout, interval).Should(Succeed())
149+
150+
Expect(httpBinDeployment.Spec.Service.Port).To(Equal(int32(8443)))
151+
})
152+
153+
It("should handle not found resource gracefully", func() {
154+
By("Reconciling a non-existent resource")
155+
controllerReconciler := &HttpBinReconciler{
156+
RemoteClient: k8sClient,
157+
Scheme: k8sClient.Scheme(),
158+
}
159+
160+
result, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
161+
NamespacedName: types.NamespacedName{
162+
Name: "non-existent",
163+
Namespace: "default",
164+
},
165+
})
166+
Expect(err).NotTo(HaveOccurred())
167+
Expect(result).To(Equal(reconcile.Result{}))
168+
})
169+
170+
It("should propagate status from HttpBinDeployment to HttpBin", func() {
171+
By("Creating HttpBin and HttpBinDeployment with status")
71172
controllerReconciler := &HttpBinReconciler{
72173
RemoteClient: k8sClient,
73174
Scheme: k8sClient.Scheme(),
74175
}
75176

177+
// First reconcile to create HttpBinDeployment
76178
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
77179
NamespacedName: typeNamespacedName,
78180
})
79181
Expect(err).NotTo(HaveOccurred())
80-
// TODO(user): Add more specific assertions depending on your controller's reconciliation logic.
81-
// Example: If you expect a certain status condition after reconciliation, verify it here.
182+
183+
By("Updating HttpBinDeployment status")
184+
httpBinDeployment := &orchestratev1alpha1.HttpBinDeployment{}
185+
Eventually(func() error {
186+
return k8sClient.Get(ctx, typeNamespacedName, httpBinDeployment)
187+
}, timeout, interval).Should(Succeed())
188+
189+
httpBinDeployment.Status.URL = "https://test.example.com"
190+
httpBinDeployment.Status.IsDeploymentReady = true
191+
Expect(k8sClient.Status().Update(ctx, httpBinDeployment)).To(Succeed())
192+
193+
By("Reconciling again to propagate status")
194+
_, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
195+
NamespacedName: typeNamespacedName,
196+
})
197+
Expect(err).NotTo(HaveOccurred())
198+
199+
By("Verifying HttpBin status was updated")
200+
httpBin := &orchestratev1alpha1.HttpBin{}
201+
Expect(k8sClient.Get(ctx, typeNamespacedName, httpBin)).To(Succeed())
202+
Expect(httpBin.Status.URL).To(Equal("https://test.example.com"))
203+
Expect(httpBin.Status.Ready).To(BeTrue())
204+
})
205+
206+
It("should copy labels from HttpBin to HttpBinDeployment", func() {
207+
By("Creating HttpBin with labels")
208+
labeledResourceName := "test-httpbin-labels"
209+
labeledNamespacedName := types.NamespacedName{
210+
Name: labeledResourceName,
211+
Namespace: "default",
212+
}
213+
214+
resource := &orchestratev1alpha1.HttpBin{
215+
ObjectMeta: metav1.ObjectMeta{
216+
Name: labeledResourceName,
217+
Namespace: "default",
218+
Labels: map[string]string{
219+
"custom-label": "custom-value",
220+
"environment": "test",
221+
},
222+
},
223+
}
224+
Expect(k8sClient.Create(ctx, resource)).To(Succeed())
225+
226+
defer func() {
227+
_ = k8sClient.Delete(ctx, resource)
228+
deployment := &orchestratev1alpha1.HttpBinDeployment{}
229+
_ = k8sClient.Get(ctx, labeledNamespacedName, deployment)
230+
_ = k8sClient.Delete(ctx, deployment)
231+
}()
232+
233+
By("Reconciling the resource")
234+
controllerReconciler := &HttpBinReconciler{
235+
RemoteClient: k8sClient,
236+
Scheme: k8sClient.Scheme(),
237+
}
238+
239+
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
240+
NamespacedName: labeledNamespacedName,
241+
})
242+
Expect(err).NotTo(HaveOccurred())
243+
244+
By("Verifying HttpBinDeployment has the labels")
245+
httpBinDeployment := &orchestratev1alpha1.HttpBinDeployment{}
246+
Eventually(func() error {
247+
return k8sClient.Get(ctx, labeledNamespacedName, httpBinDeployment)
248+
}, timeout, interval).Should(Succeed())
249+
250+
Expect(httpBinDeployment.Labels).To(HaveKeyWithValue("custom-label", "custom-value"))
251+
Expect(httpBinDeployment.Labels).To(HaveKeyWithValue("environment", "test"))
252+
})
253+
254+
It("should set condition when deployment is not ready", func() {
255+
By("Reconciling to create HttpBinDeployment")
256+
controllerReconciler := &HttpBinReconciler{
257+
RemoteClient: k8sClient,
258+
Scheme: k8sClient.Scheme(),
259+
}
260+
261+
_, err := controllerReconciler.Reconcile(ctx, reconcile.Request{
262+
NamespacedName: typeNamespacedName,
263+
})
264+
Expect(err).NotTo(HaveOccurred())
265+
266+
By("Setting HttpBinDeployment status to not ready")
267+
httpBinDeployment := &orchestratev1alpha1.HttpBinDeployment{}
268+
Eventually(func() error {
269+
return k8sClient.Get(ctx, typeNamespacedName, httpBinDeployment)
270+
}, timeout, interval).Should(Succeed())
271+
272+
httpBinDeployment.Status.URL = "https://test.example.com"
273+
httpBinDeployment.Status.IsDeploymentReady = false
274+
Expect(k8sClient.Status().Update(ctx, httpBinDeployment)).To(Succeed())
275+
276+
By("Reconciling again")
277+
_, err = controllerReconciler.Reconcile(ctx, reconcile.Request{
278+
NamespacedName: typeNamespacedName,
279+
})
280+
Expect(err).NotTo(HaveOccurred())
281+
282+
By("Verifying HttpBin has progressing condition")
283+
httpBin := &orchestratev1alpha1.HttpBin{}
284+
Expect(k8sClient.Get(ctx, typeNamespacedName, httpBin)).To(Succeed())
285+
Expect(httpBin.Status.Ready).To(BeFalse())
286+
287+
// Check condition exists
288+
found := false
289+
for _, condition := range httpBin.Status.Conditions {
290+
if condition.Type == orchestratev1alpha1.HttpBinConditionTypeReady {
291+
found = true
292+
Expect(condition.Status).To(Equal(metav1.ConditionFalse))
293+
Expect(condition.Reason).To(Equal(orchestratev1alpha1.HttpBinConditionReasonDeploymentProgressing))
294+
}
295+
}
296+
Expect(found).To(BeTrue())
82297
})
83298
})
84299
})

0 commit comments

Comments
 (0)