Skip to content

Commit 3860105

Browse files
committed
test(alluxio): migrate suite to Ginkgo v2 and add unit tests for controller and implement
- Update suite_test.go: remove Ginkgo v1 Done channel and timeout arg - Add implement_test.go: tests for getRuntime, RemoveEngine, GetOrCreateEngine - Add alluxio_runtime_controller_test.go: tests for NewRuntimeReconciler, ControllerName, Reconcile Coverage: 89.7% (gate: >75%), 9/9 specs pass
1 parent a69c888 commit 3860105

3 files changed

Lines changed: 272 additions & 9 deletions

File tree

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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 alluxio
18+
19+
import (
20+
"context"
21+
22+
. "github.com/onsi/ginkgo/v2"
23+
. "github.com/onsi/gomega"
24+
25+
datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
26+
"github.com/fluid-cloudnative/fluid/pkg/utils/fake"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/apimachinery/pkg/types"
30+
"k8s.io/client-go/tools/record"
31+
ctrl "sigs.k8s.io/controller-runtime"
32+
)
33+
34+
var _ = Describe("AlluxioRuntimeController", func() {
35+
const (
36+
testName = "alluxio-test"
37+
testNamespace = "default"
38+
)
39+
40+
var (
41+
s *runtime.Scheme
42+
)
43+
44+
BeforeEach(func() {
45+
s = runtime.NewScheme()
46+
Expect(datav1alpha1.AddToScheme(s)).To(Succeed())
47+
})
48+
49+
Describe("NewRuntimeReconciler", func() {
50+
It("creates a RuntimeReconciler with expected fields", func() {
51+
c := fake.NewFakeClientWithScheme(s)
52+
recorder := record.NewFakeRecorder(10)
53+
r := NewRuntimeReconciler(c, fake.NullLogger(), s, recorder)
54+
55+
Expect(r).ToNot(BeNil())
56+
Expect(r.Scheme).To(Equal(s))
57+
Expect(r.engines).ToNot(BeNil())
58+
Expect(r.mutex).ToNot(BeNil())
59+
Expect(r.RuntimeReconciler).ToNot(BeNil())
60+
})
61+
})
62+
63+
Describe("ControllerName", func() {
64+
It("returns the expected controller name", func() {
65+
c := fake.NewFakeClientWithScheme(s)
66+
recorder := record.NewFakeRecorder(10)
67+
r := NewRuntimeReconciler(c, fake.NullLogger(), s, recorder)
68+
69+
Expect(r.ControllerName()).To(Equal(controllerName))
70+
})
71+
})
72+
73+
Describe("Reconcile", func() {
74+
It("returns empty result when the AlluxioRuntime is not found", func() {
75+
c := fake.NewFakeClientWithScheme(s)
76+
recorder := record.NewFakeRecorder(10)
77+
r := NewRuntimeReconciler(c, fake.NullLogger(), s, recorder)
78+
79+
req := ctrl.Request{
80+
NamespacedName: types.NamespacedName{
81+
Name: "nonexistent",
82+
Namespace: testNamespace,
83+
},
84+
}
85+
result, err := r.Reconcile(context.TODO(), req)
86+
Expect(err).ToNot(HaveOccurred())
87+
Expect(result).To(Equal(ctrl.Result{}))
88+
})
89+
90+
It("proceeds past getRuntime when the AlluxioRuntime exists", func() {
91+
rt := &datav1alpha1.AlluxioRuntime{
92+
ObjectMeta: metav1.ObjectMeta{
93+
Name: testName,
94+
Namespace: testNamespace,
95+
},
96+
}
97+
c := fake.NewFakeClientWithScheme(s, rt)
98+
recorder := record.NewFakeRecorder(10)
99+
r := NewRuntimeReconciler(c, fake.NullLogger(), s, recorder)
100+
101+
req := ctrl.Request{
102+
NamespacedName: types.NamespacedName{
103+
Name: testName,
104+
Namespace: testNamespace,
105+
},
106+
}
107+
// Reconcile will call ReconcileInternal which may requeue; we only assert
108+
// that getRuntime succeeded (no not-found error) and that Reconcile did not
109+
// return a bare not-found error.
110+
_, err := r.Reconcile(context.TODO(), req)
111+
// err may be non-nil if ReconcileInternal encounters further issues
112+
// (e.g. missing Dataset), but it should NOT be a not-found error.
113+
if err != nil {
114+
Expect(err.Error()).ToNot(ContainSubstring("not found"))
115+
}
116+
})
117+
})
118+
})
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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 alluxio
18+
19+
import (
20+
"context"
21+
"sync"
22+
23+
. "github.com/onsi/ginkgo/v2"
24+
. "github.com/onsi/gomega"
25+
26+
datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
27+
"github.com/fluid-cloudnative/fluid/pkg/controllers"
28+
"github.com/fluid-cloudnative/fluid/pkg/ddc"
29+
"github.com/fluid-cloudnative/fluid/pkg/ddc/base"
30+
cruntime "github.com/fluid-cloudnative/fluid/pkg/runtime"
31+
"github.com/fluid-cloudnative/fluid/pkg/utils/fake"
32+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+
"k8s.io/apimachinery/pkg/runtime"
34+
"k8s.io/apimachinery/pkg/types"
35+
"k8s.io/client-go/tools/record"
36+
)
37+
38+
// makeReconciler creates a RuntimeReconciler with a fake client for unit tests.
39+
func makeReconciler(s *runtime.Scheme, objs ...runtime.Object) *RuntimeReconciler {
40+
c := fake.NewFakeClientWithScheme(s, objs...)
41+
r := &RuntimeReconciler{
42+
Scheme: s,
43+
mutex: &sync.Mutex{},
44+
engines: map[string]base.Engine{},
45+
}
46+
r.RuntimeReconciler = controllers.NewRuntimeReconciler(r, c, fake.NullLogger(), record.NewFakeRecorder(10))
47+
return r
48+
}
49+
50+
var _ = Describe("implement", func() {
51+
const (
52+
rtName = "test-alluxio"
53+
rtNamespace = "default"
54+
)
55+
56+
var (
57+
s *runtime.Scheme
58+
)
59+
60+
BeforeEach(func() {
61+
s = runtime.NewScheme()
62+
Expect(datav1alpha1.AddToScheme(s)).To(Succeed())
63+
})
64+
65+
Describe("getRuntime", func() {
66+
It("returns the AlluxioRuntime when it exists", func() {
67+
rt := &datav1alpha1.AlluxioRuntime{
68+
ObjectMeta: metav1.ObjectMeta{
69+
Name: rtName,
70+
Namespace: rtNamespace,
71+
},
72+
}
73+
r := makeReconciler(s, rt)
74+
ctx := cruntime.ReconcileRequestContext{
75+
Context: context.TODO(),
76+
NamespacedName: types.NamespacedName{Name: rtName, Namespace: rtNamespace},
77+
Log: fake.NullLogger(),
78+
Client: r.Client,
79+
}
80+
81+
got, err := r.getRuntime(ctx)
82+
Expect(err).ToNot(HaveOccurred())
83+
Expect(got).ToNot(BeNil())
84+
Expect(got.Name).To(Equal(rtName))
85+
Expect(got.Namespace).To(Equal(rtNamespace))
86+
})
87+
88+
It("returns an error when the AlluxioRuntime does not exist", func() {
89+
r := makeReconciler(s)
90+
ctx := cruntime.ReconcileRequestContext{
91+
Context: context.TODO(),
92+
NamespacedName: types.NamespacedName{Name: "missing", Namespace: rtNamespace},
93+
Log: fake.NullLogger(),
94+
Client: r.Client,
95+
}
96+
97+
_, err := r.getRuntime(ctx)
98+
Expect(err).To(HaveOccurred())
99+
})
100+
})
101+
102+
Describe("RemoveEngine", func() {
103+
It("removes an engine entry from the engines map", func() {
104+
r := makeReconciler(s)
105+
nsn := types.NamespacedName{Name: rtName, Namespace: rtNamespace}
106+
id := ddc.GenerateEngineID(nsn)
107+
108+
// Inject a sentinel value directly so we can verify removal.
109+
r.mutex.Lock()
110+
r.engines[id] = nil
111+
r.mutex.Unlock()
112+
113+
ctx := cruntime.ReconcileRequestContext{
114+
Context: context.TODO(),
115+
NamespacedName: nsn,
116+
Log: fake.NullLogger(),
117+
}
118+
r.RemoveEngine(ctx)
119+
120+
r.mutex.Lock()
121+
_, exists := r.engines[id]
122+
r.mutex.Unlock()
123+
Expect(exists).To(BeFalse())
124+
})
125+
126+
It("is a no-op when no engine exists for the id", func() {
127+
r := makeReconciler(s)
128+
ctx := cruntime.ReconcileRequestContext{
129+
Context: context.TODO(),
130+
NamespacedName: types.NamespacedName{Name: "no-such", Namespace: rtNamespace},
131+
Log: fake.NullLogger(),
132+
}
133+
// Must not panic.
134+
Expect(func() { r.RemoveEngine(ctx) }).ToNot(Panic())
135+
})
136+
})
137+
138+
Describe("GetOrCreateEngine", func() {
139+
It("returns an error when no matching engine builder is registered", func() {
140+
r := makeReconciler(s)
141+
ctx := cruntime.ReconcileRequestContext{
142+
Context: context.TODO(),
143+
NamespacedName: types.NamespacedName{Name: rtName, Namespace: rtNamespace},
144+
Log: fake.NullLogger(),
145+
EngineImpl: "unknown-impl",
146+
Client: r.Client,
147+
}
148+
_, err := r.GetOrCreateEngine(ctx)
149+
Expect(err).To(HaveOccurred())
150+
})
151+
})
152+
})

pkg/controllers/v1alpha1/alluxio/suite_test.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package alluxio
1818

1919
import (
20-
"os"
2120
"path/filepath"
2221
"testing"
2322

@@ -40,7 +39,6 @@ import (
4039
var cfg *rest.Config
4140
var k8sClient client.Client
4241
var testEnv *envtest.Environment
43-
var useExistingCluster = false
4442

4543
func TestAPIs(t *testing.T) {
4644
RegisterFailHandler(Fail)
@@ -49,11 +47,8 @@ func TestAPIs(t *testing.T) {
4947
"Controller Suite")
5048
}
5149

52-
var _ = BeforeSuite(func(done Done) {
50+
var _ = BeforeSuite(func() {
5351
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
54-
if env := os.Getenv("USE_EXISTING_CLUSTER"); env == "true" {
55-
useExistingCluster = true
56-
}
5752

5853
By("bootstrapping test environment")
5954
testEnv = &envtest.Environment{
@@ -73,9 +68,7 @@ var _ = BeforeSuite(func(done Done) {
7368
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
7469
Expect(err).ToNot(HaveOccurred())
7570
Expect(k8sClient).ToNot(BeNil())
76-
77-
close(done)
78-
}, 60)
71+
})
7972

8073
var _ = AfterSuite(func() {
8174
By("tearing down the test environment")

0 commit comments

Comments
 (0)