Skip to content

Commit 6ef2eec

Browse files
authored
Migrate pkg/controllers/v1alpha1/dataload tests to Ginkgo/Gomega (#5707)
* test(dataload): migrate controller tests to Ginkgo v2 Signed-off-by: Harsh <harshmastic@gmail.com> * test(dataload): assert running status is preserved Signed-off-by: Harsh <harshmastic@gmail.com> * test(dataload): tighten review follow-up assertions Signed-off-by: Harsh <harshmastic@gmail.com> * test(dataload): extract repeated test literals Signed-off-by: Harsh <harshmastic@gmail.com> * test(dataload): cover generated status fields Signed-off-by: Harsh <harshmastic@gmail.com> * test(dataload): extract repeated node name literal Signed-off-by: Harsh <harshmastic@gmail.com> --------- Signed-off-by: Harsh <harshmastic@gmail.com>
1 parent 14d0ee1 commit 6ef2eec

4 files changed

Lines changed: 690 additions & 253 deletions

File tree

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
/*
2+
Copyright 2026 The Fluid Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package dataload
18+
19+
import (
20+
"context"
21+
22+
"github.com/agiledragon/gomonkey/v2"
23+
. "github.com/onsi/ginkgo/v2"
24+
. "github.com/onsi/gomega"
25+
corev1 "k8s.io/api/core/v1"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/runtime"
28+
"k8s.io/apimachinery/pkg/types"
29+
"k8s.io/client-go/tools/record"
30+
ctrl "sigs.k8s.io/controller-runtime"
31+
32+
datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
33+
"github.com/fluid-cloudnative/fluid/pkg/common"
34+
"github.com/fluid-cloudnative/fluid/pkg/dataoperation"
35+
cruntime "github.com/fluid-cloudnative/fluid/pkg/runtime"
36+
"github.com/fluid-cloudnative/fluid/pkg/utils/compatibility"
37+
"github.com/fluid-cloudnative/fluid/pkg/utils/fake"
38+
)
39+
40+
func newTestDataLoadOperation(dataLoad *datav1alpha1.DataLoad, objs ...runtime.Object) *dataLoadOperation {
41+
testScheme := runtime.NewScheme()
42+
if err := datav1alpha1.AddToScheme(testScheme); err != nil {
43+
panic(err)
44+
}
45+
allObjs := append([]runtime.Object{dataLoad}, objs...)
46+
c := fake.NewFakeClientWithScheme(testScheme, allObjs...)
47+
return &dataLoadOperation{
48+
Client: c,
49+
Log: fake.NullLogger(),
50+
Recorder: record.NewFakeRecorder(32),
51+
dataLoad: dataLoad,
52+
}
53+
}
54+
55+
var _ = Describe("dataLoadOperation", func() {
56+
var mockDataLoad *datav1alpha1.DataLoad
57+
58+
BeforeEach(func() {
59+
mockDataLoad = &datav1alpha1.DataLoad{
60+
ObjectMeta: metav1.ObjectMeta{
61+
Name: "test-dataload",
62+
Namespace: "default",
63+
},
64+
Spec: datav1alpha1.DataLoadSpec{
65+
Dataset: datav1alpha1.TargetDataset{
66+
Name: "hadoop",
67+
Namespace: "default",
68+
},
69+
},
70+
}
71+
})
72+
73+
Describe("GetOperationObject", func() {
74+
It("returns the dataLoad object", func() {
75+
op := newTestDataLoadOperation(mockDataLoad)
76+
Expect(op.GetOperationObject()).To(Equal(mockDataLoad))
77+
})
78+
})
79+
80+
Describe("HasPrecedingOperation", func() {
81+
It("returns false when RunAfter is nil", func() {
82+
op := newTestDataLoadOperation(mockDataLoad)
83+
Expect(op.HasPrecedingOperation()).To(BeFalse())
84+
})
85+
86+
It("returns true when RunAfter is set", func() {
87+
mockDataLoad.Spec.RunAfter = &datav1alpha1.OperationRef{}
88+
op := newTestDataLoadOperation(mockDataLoad)
89+
Expect(op.HasPrecedingOperation()).To(BeTrue())
90+
})
91+
})
92+
93+
Describe("GetPossibleTargetDatasetNamespacedNames", func() {
94+
It("returns the dataset namespaced name", func() {
95+
op := newTestDataLoadOperation(mockDataLoad)
96+
names := op.GetPossibleTargetDatasetNamespacedNames()
97+
Expect(names).To(HaveLen(1))
98+
Expect(names[0]).To(Equal(types.NamespacedName{Namespace: "default", Name: "hadoop"}))
99+
})
100+
})
101+
102+
Describe("GetReleaseNameSpacedName", func() {
103+
It("returns the release namespaced name", func() {
104+
op := newTestDataLoadOperation(mockDataLoad)
105+
nn := op.GetReleaseNameSpacedName()
106+
Expect(nn.Namespace).To(Equal("default"))
107+
Expect(nn.Name).NotTo(BeEmpty())
108+
})
109+
})
110+
111+
Describe("GetChartsDirectory", func() {
112+
It("returns a non-empty charts directory", func() {
113+
op := newTestDataLoadOperation(mockDataLoad)
114+
Expect(op.GetChartsDirectory()).NotTo(BeEmpty())
115+
})
116+
})
117+
118+
Describe("GetOperationType", func() {
119+
It("returns DataLoadType", func() {
120+
op := newTestDataLoadOperation(mockDataLoad)
121+
Expect(op.GetOperationType()).To(Equal(dataoperation.DataLoadType))
122+
})
123+
})
124+
125+
Describe("UpdateStatusInfoForCompleted", func() {
126+
It("returns nil (no-op)", func() {
127+
op := newTestDataLoadOperation(mockDataLoad)
128+
Expect(op.UpdateStatusInfoForCompleted(nil)).To(Succeed())
129+
})
130+
})
131+
132+
Describe("SetTargetDatasetStatusInProgress and RemoveTargetDatasetStatusInProgress", func() {
133+
It("are no-ops and do not panic", func() {
134+
op := newTestDataLoadOperation(mockDataLoad)
135+
dataset := &datav1alpha1.Dataset{}
136+
Expect(func() { op.SetTargetDatasetStatusInProgress(dataset) }).NotTo(Panic())
137+
Expect(func() { op.RemoveTargetDatasetStatusInProgress(dataset) }).NotTo(Panic())
138+
})
139+
})
140+
141+
Describe("GetTargetDataset", func() {
142+
It("returns dataset when it exists", func() {
143+
dataset := &datav1alpha1.Dataset{
144+
ObjectMeta: metav1.ObjectMeta{Name: "hadoop", Namespace: "default"},
145+
}
146+
op := newTestDataLoadOperation(mockDataLoad, dataset)
147+
ds, err := op.GetTargetDataset()
148+
Expect(err).NotTo(HaveOccurred())
149+
Expect(ds.Name).To(Equal("hadoop"))
150+
})
151+
})
152+
153+
Describe("UpdateOperationApiStatus", func() {
154+
It("succeeds when dataload exists in fake client", func() {
155+
op := newTestDataLoadOperation(mockDataLoad)
156+
opStatus := mockDataLoad.Status.DeepCopy()
157+
// fake client supports Status().Update when the object exists
158+
err := op.UpdateOperationApiStatus(opStatus)
159+
// expect no error — fake client handles status update
160+
Expect(err).NotTo(HaveOccurred())
161+
})
162+
})
163+
164+
Describe("GetParallelTaskNumber", func() {
165+
It("returns 1", func() {
166+
op := newTestDataLoadOperation(mockDataLoad)
167+
Expect(op.GetParallelTaskNumber()).To(Equal(int32(1)))
168+
})
169+
})
170+
171+
Describe("GetStatusHandler", func() {
172+
It("returns OnceStatusHandler for Once policy", func() {
173+
mockDataLoad.Spec.Policy = datav1alpha1.Once
174+
op := newTestDataLoadOperation(mockDataLoad)
175+
Expect(op.GetStatusHandler()).To(BeAssignableToTypeOf(&OnceStatusHandler{}))
176+
})
177+
178+
It("returns CronStatusHandler for Cron policy", func() {
179+
mockDataLoad.Spec.Policy = datav1alpha1.Cron
180+
op := newTestDataLoadOperation(mockDataLoad)
181+
Expect(op.GetStatusHandler()).To(BeAssignableToTypeOf(&CronStatusHandler{}))
182+
})
183+
184+
It("returns OnEventStatusHandler for OnEvent policy", func() {
185+
mockDataLoad.Spec.Policy = datav1alpha1.OnEvent
186+
op := newTestDataLoadOperation(mockDataLoad)
187+
Expect(op.GetStatusHandler()).To(BeAssignableToTypeOf(&OnEventStatusHandler{}))
188+
})
189+
190+
It("returns nil for unknown policy", func() {
191+
mockDataLoad.Spec.Policy = "Unknown"
192+
op := newTestDataLoadOperation(mockDataLoad)
193+
Expect(op.GetStatusHandler()).To(BeNil())
194+
})
195+
})
196+
197+
Describe("GetTTL", func() {
198+
It("returns nil TTL for Once policy with no TTL set", func() {
199+
mockDataLoad.Spec.Policy = datav1alpha1.Once
200+
op := newTestDataLoadOperation(mockDataLoad)
201+
ttl, err := op.GetTTL()
202+
Expect(err).NotTo(HaveOccurred())
203+
Expect(ttl).To(BeNil())
204+
})
205+
206+
It("returns TTL for Once policy with TTL set", func() {
207+
ttlVal := int32(300)
208+
mockDataLoad.Spec.Policy = datav1alpha1.Once
209+
mockDataLoad.Spec.TTLSecondsAfterFinished = &ttlVal
210+
op := newTestDataLoadOperation(mockDataLoad)
211+
ttl, err := op.GetTTL()
212+
Expect(err).NotTo(HaveOccurred())
213+
Expect(ttl).NotTo(BeNil())
214+
Expect(*ttl).To(Equal(int32(300)))
215+
})
216+
217+
It("returns nil TTL for Cron policy", func() {
218+
mockDataLoad.Spec.Policy = datav1alpha1.Cron
219+
op := newTestDataLoadOperation(mockDataLoad)
220+
ttl, err := op.GetTTL()
221+
Expect(err).NotTo(HaveOccurred())
222+
Expect(ttl).To(BeNil())
223+
})
224+
225+
It("returns nil TTL for OnEvent policy", func() {
226+
mockDataLoad.Spec.Policy = datav1alpha1.OnEvent
227+
op := newTestDataLoadOperation(mockDataLoad)
228+
ttl, err := op.GetTTL()
229+
Expect(err).NotTo(HaveOccurred())
230+
Expect(ttl).To(BeNil())
231+
})
232+
233+
It("returns error for unknown policy", func() {
234+
mockDataLoad.Spec.Policy = "Unknown"
235+
op := newTestDataLoadOperation(mockDataLoad)
236+
_, err := op.GetTTL()
237+
Expect(err).To(HaveOccurred())
238+
})
239+
})
240+
241+
Describe("Validate", func() {
242+
It("returns nil when namespace matches dataset namespace", func() {
243+
op := newTestDataLoadOperation(mockDataLoad)
244+
ctx := cruntime.ReconcileRequestContext{Log: fake.NullLogger()}
245+
conditions, err := op.Validate(ctx)
246+
Expect(err).NotTo(HaveOccurred())
247+
Expect(conditions).To(BeNil())
248+
})
249+
250+
It("returns error when namespace does not match dataset namespace", func() {
251+
mockDataLoad.Namespace = "other"
252+
mockDataLoad.Spec.Dataset.Namespace = "default"
253+
op := newTestDataLoadOperation(mockDataLoad)
254+
ctx := cruntime.ReconcileRequestContext{Log: fake.NullLogger()}
255+
conditions, err := op.Validate(ctx)
256+
Expect(err).To(HaveOccurred())
257+
Expect(conditions).To(HaveLen(1))
258+
Expect(conditions[0].Type).To(Equal(common.Failed))
259+
})
260+
})
261+
})
262+
263+
var _ = Describe("DataLoadReconciler", func() {
264+
var patches *gomonkey.Patches
265+
266+
BeforeEach(func() {
267+
patches = gomonkey.ApplyFunc(compatibility.IsBatchV1CronJobSupported, func() bool {
268+
return true
269+
})
270+
})
271+
272+
AfterEach(func() {
273+
patches.Reset()
274+
})
275+
276+
Describe("Build", func() {
277+
It("returns dataLoadOperation for a DataLoad object", func() {
278+
testScheme := runtime.NewScheme()
279+
Expect(datav1alpha1.AddToScheme(testScheme)).To(Succeed())
280+
c := fake.NewFakeClientWithScheme(testScheme)
281+
r := NewDataLoadReconciler(c, fake.NullLogger(), testScheme, record.NewFakeRecorder(32))
282+
283+
dl := &datav1alpha1.DataLoad{
284+
ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"},
285+
}
286+
op, err := r.Build(dl)
287+
Expect(err).NotTo(HaveOccurred())
288+
Expect(op).NotTo(BeNil())
289+
})
290+
291+
It("returns error for a non-DataLoad object", func() {
292+
testScheme := runtime.NewScheme()
293+
c := fake.NewFakeClientWithScheme(testScheme)
294+
r := NewDataLoadReconciler(c, fake.NullLogger(), testScheme, record.NewFakeRecorder(32))
295+
296+
pod := &corev1.Pod{}
297+
_, err := r.Build(pod)
298+
Expect(err).To(HaveOccurred())
299+
})
300+
})
301+
302+
Describe("ControllerName", func() {
303+
It("returns DataLoadReconciler", func() {
304+
testScheme := runtime.NewScheme()
305+
c := fake.NewFakeClientWithScheme(testScheme)
306+
r := NewDataLoadReconciler(c, fake.NullLogger(), testScheme, record.NewFakeRecorder(32))
307+
Expect(r.ControllerName()).To(Equal("DataLoadReconciler"))
308+
})
309+
})
310+
311+
Describe("Reconcile", func() {
312+
It("returns no-requeue when DataLoad not found", func() {
313+
testScheme := runtime.NewScheme()
314+
Expect(datav1alpha1.AddToScheme(testScheme)).To(Succeed())
315+
c := fake.NewFakeClientWithScheme(testScheme)
316+
r := NewDataLoadReconciler(c, fake.NullLogger(), testScheme, record.NewFakeRecorder(32))
317+
318+
result, err := r.Reconcile(context.Background(), ctrl.Request{
319+
NamespacedName: types.NamespacedName{Name: "missing", Namespace: "default"},
320+
})
321+
Expect(err).NotTo(HaveOccurred())
322+
Expect(result.Requeue).To(BeFalse())
323+
})
324+
})
325+
})

0 commit comments

Comments
 (0)