-
Notifications
You must be signed in to change notification settings - Fork 1.2k
test(databackup): migrate controller tests to Ginkgo/Gomega #5713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,83 @@ | ||
| /* | ||
| Copyright 2023 The Fluid Authors. | ||
| Copyright 2026 The Fluid Authors. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
|
|
||
| */ | ||
|
|
||
| package databackup | ||
|
|
||
| import ( | ||
| "testing" | ||
| "k8s.io/apimachinery/pkg/runtime" | ||
| "k8s.io/client-go/tools/record" | ||
| ctrl "sigs.k8s.io/controller-runtime" | ||
|
|
||
| . "github.com/onsi/ginkgo/v2" | ||
| . "github.com/onsi/gomega" | ||
|
|
||
| datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1" | ||
| "github.com/fluid-cloudnative/fluid/pkg/utils/fake" | ||
| ) | ||
|
|
||
| func TestAPIs(t *testing.T) { | ||
| var _ = Describe("DataBackupReconciler", func() { | ||
|
|
||
| Describe("ControllerName", func() { | ||
| It("should return the constant controller name", func() { | ||
| r := &DataBackupReconciler{} | ||
| Expect(r.ControllerName()).To(Equal(controllerName)) | ||
| }) | ||
| }) | ||
|
|
||
| Describe("NewDataBackupReconciler", func() { | ||
| It("should initialize reconciler with all required fields set", func() { | ||
| s := runtime.NewScheme() | ||
| _ = datav1alpha1.AddToScheme(s) | ||
| fakeClient := fake.NewFakeClientWithScheme(s) | ||
| log := ctrl.Log.WithName("test") | ||
| recorder := record.NewFakeRecorder(10) | ||
|
|
||
| r := NewDataBackupReconciler(fakeClient, log, s, recorder) | ||
| Expect(r).NotTo(BeNil()) | ||
| Expect(r.Scheme).To(Equal(s)) | ||
| Expect(r.OperationReconciler).NotTo(BeNil()) | ||
| }) | ||
| }) | ||
|
|
||
| Describe("Build", func() { | ||
| It("should return a dataBackupOperation for a valid DataBackup object", func() { | ||
| s := runtime.NewScheme() | ||
| _ = datav1alpha1.AddToScheme(s) | ||
| fakeClient := fake.NewFakeClientWithScheme(s) | ||
| log := ctrl.Log.WithName("test") | ||
| recorder := record.NewFakeRecorder(10) | ||
| r := NewDataBackupReconciler(fakeClient, log, s, recorder) | ||
|
|
||
| dataBackup := &datav1alpha1.DataBackup{} | ||
| op, err := r.Build(dataBackup) | ||
| Expect(err).NotTo(HaveOccurred()) | ||
| Expect(op).NotTo(BeNil()) | ||
| }) | ||
|
|
||
| It("should return an error for a non-DataBackup object", func() { | ||
| s := runtime.NewScheme() | ||
| fakeClient := fake.NewFakeClientWithScheme(s) | ||
| log := ctrl.Log.WithName("test") | ||
| recorder := record.NewFakeRecorder(10) | ||
| r := NewDataBackupReconciler(fakeClient, log, s, recorder) | ||
|
|
||
| } | ||
| dataset := &datav1alpha1.Dataset{} | ||
| op, err := r.Build(dataset) | ||
| Expect(err).To(HaveOccurred()) | ||
| Expect(op).To(BeNil()) | ||
| }) | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,290 @@ | ||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||
| Copyright 2026 The Fluid Authors. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||||||||||||||||||||||||||||||
| you may not use this file except in compliance with the License. | ||||||||||||||||||||||||||||||||
| You may obtain a copy of the License at | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Unless required by applicable law or agreed to in writing, software | ||||||||||||||||||||||||||||||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||||||||||||||||||||||||||||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||||||||||||||||||||||||||||
| See the License for the specific language governing permissions and | ||||||||||||||||||||||||||||||||
| limitations under the License. | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| package databackup | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| import ( | ||||||||||||||||||||||||||||||||
| . "github.com/onsi/ginkgo/v2" | ||||||||||||||||||||||||||||||||
| . "github.com/onsi/gomega" | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1" | ||||||||||||||||||||||||||||||||
| "github.com/fluid-cloudnative/fluid/pkg/common" | ||||||||||||||||||||||||||||||||
| cdatabackup "github.com/fluid-cloudnative/fluid/pkg/databackup" | ||||||||||||||||||||||||||||||||
| "github.com/fluid-cloudnative/fluid/pkg/dataoperation" | ||||||||||||||||||||||||||||||||
| cruntime "github.com/fluid-cloudnative/fluid/pkg/runtime" | ||||||||||||||||||||||||||||||||
| "github.com/fluid-cloudnative/fluid/pkg/utils/fake" | ||||||||||||||||||||||||||||||||
| corev1 "k8s.io/api/core/v1" | ||||||||||||||||||||||||||||||||
| v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||||||||||||||||||||||||||||
| "k8s.io/apimachinery/pkg/runtime" | ||||||||||||||||||||||||||||||||
| "k8s.io/apimachinery/pkg/types" | ||||||||||||||||||||||||||||||||
| "k8s.io/client-go/tools/record" | ||||||||||||||||||||||||||||||||
| ctrl "sigs.k8s.io/controller-runtime" | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| var _ = Describe("dataBackupOperation", func() { | ||||||||||||||||||||||||||||||||
| var ( | ||||||||||||||||||||||||||||||||
| testScheme *runtime.Scheme | ||||||||||||||||||||||||||||||||
| dataBackup *datav1alpha1.DataBackup | ||||||||||||||||||||||||||||||||
| op *dataBackupOperation | ||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| BeforeEach(func() { | ||||||||||||||||||||||||||||||||
| testScheme = runtime.NewScheme() | ||||||||||||||||||||||||||||||||
| _ = datav1alpha1.AddToScheme(testScheme) | ||||||||||||||||||||||||||||||||
| _ = corev1.AddToScheme(testScheme) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| dataBackup = &datav1alpha1.DataBackup{ | ||||||||||||||||||||||||||||||||
| ObjectMeta: v1.ObjectMeta{ | ||||||||||||||||||||||||||||||||
| Name: "test-backup", | ||||||||||||||||||||||||||||||||
| Namespace: "default", | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| Spec: datav1alpha1.DataBackupSpec{ | ||||||||||||||||||||||||||||||||
| Dataset: "test-dataset", | ||||||||||||||||||||||||||||||||
| BackupPath: "pvc://test-pvc/path", | ||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| fakeClient := fake.NewFakeClientWithScheme(testScheme, dataBackup) | ||||||||||||||||||||||||||||||||
| log := ctrl.Log.WithName("test") | ||||||||||||||||||||||||||||||||
| recorder := record.NewFakeRecorder(10) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| op = &dataBackupOperation{ | ||||||||||||||||||||||||||||||||
| Client: fakeClient, | ||||||||||||||||||||||||||||||||
| Log: log, | ||||||||||||||||||||||||||||||||
| Recorder: recorder, | ||||||||||||||||||||||||||||||||
| dataBackup: dataBackup, | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetOperationObject", func() { | ||||||||||||||||||||||||||||||||
| It("should return the dataBackup object", func() { | ||||||||||||||||||||||||||||||||
| obj := op.GetOperationObject() | ||||||||||||||||||||||||||||||||
| Expect(obj).To(Equal(dataBackup)) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetChartsDirectory", func() { | ||||||||||||||||||||||||||||||||
| It("should contain the DatabackupChart constant", func() { | ||||||||||||||||||||||||||||||||
| dir := op.GetChartsDirectory() | ||||||||||||||||||||||||||||||||
| Expect(dir).To(ContainSubstring(cdatabackup.DatabackupChart)) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("HasPrecedingOperation", func() { | ||||||||||||||||||||||||||||||||
| It("should return false when RunAfter is nil", func() { | ||||||||||||||||||||||||||||||||
| dataBackup.Spec.RunAfter = nil | ||||||||||||||||||||||||||||||||
| Expect(op.HasPrecedingOperation()).To(BeFalse()) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| It("should return true when RunAfter is set", func() { | ||||||||||||||||||||||||||||||||
| dataBackup.Spec.RunAfter = &datav1alpha1.OperationRef{} | ||||||||||||||||||||||||||||||||
| Expect(op.HasPrecedingOperation()).To(BeTrue()) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetOperationType", func() { | ||||||||||||||||||||||||||||||||
| It("should return DataBackupType", func() { | ||||||||||||||||||||||||||||||||
| Expect(op.GetOperationType()).To(Equal(dataoperation.DataBackupType)) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetPossibleTargetDatasetNamespacedNames", func() { | ||||||||||||||||||||||||||||||||
| It("should return a single NamespacedName matching the dataBackup", func() { | ||||||||||||||||||||||||||||||||
| names := op.GetPossibleTargetDatasetNamespacedNames() | ||||||||||||||||||||||||||||||||
| Expect(names).To(HaveLen(1)) | ||||||||||||||||||||||||||||||||
| Expect(names[0]).To(Equal(types.NamespacedName{ | ||||||||||||||||||||||||||||||||
| Namespace: "default", | ||||||||||||||||||||||||||||||||
| Name: "test-backup", | ||||||||||||||||||||||||||||||||
| })) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+107
to
+111
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Expect(names[0]).To(Equal(types.NamespacedName{
Namespace: "default",
Name: "test-dataset",
})) |
||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetReleaseNameSpacedName", func() { | ||||||||||||||||||||||||||||||||
| It("should return NamespacedName with the release name derived from the backup name", func() { | ||||||||||||||||||||||||||||||||
| nsn := op.GetReleaseNameSpacedName() | ||||||||||||||||||||||||||||||||
| Expect(nsn.Namespace).To(Equal("default")) | ||||||||||||||||||||||||||||||||
| Expect(nsn.Name).NotTo(BeEmpty()) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| Describe("GetStatusHandler", func() { | ||||||||||||||||||||||||||||||||
| It("should return an OnceHandler", func() { | ||||||||||||||||||||||||||||||||
| handler := op.GetStatusHandler() | ||||||||||||||||||||||||||||||||
| Expect(handler).NotTo(BeNil()) | ||||||||||||||||||||||||||||||||
| _, ok := handler.(*OnceHandler) | ||||||||||||||||||||||||||||||||
| Expect(ok).To(BeTrue()) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+124
to
+128
|
||||||||||||||||||||||||||||||||
| It("should return an OnceHandler", func() { | |
| handler := op.GetStatusHandler() | |
| Expect(handler).NotTo(BeNil()) | |
| _, ok := handler.(*OnceHandler) | |
| Expect(ok).To(BeTrue()) | |
| It("should return a properly configured OnceHandler", func() { | |
| handler := op.GetStatusHandler() | |
| Expect(handler).NotTo(BeNil()) | |
| onceHandler, ok := handler.(*OnceHandler) | |
| Expect(ok).To(BeTrue()) | |
| // Ensure the OnceHandler is fully initialized so that GetOperationStatus will not panic. | |
| Expect(onceHandler.dataBackup).NotTo(BeNil()) |
Check failure on line 172 in pkg/controllers/v1alpha1/databackup/implement_test.go
SonarQubeCloud / SonarCloud Code Analysis
Define a constant instead of duplicating this literal "pvc://my-pvc/path" 3 times.
See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AZ0fmepcshhUnMiqw3W_&open=AZ0fmepcshhUnMiqw3W_&pullRequest=5713
Check failure on line 180 in pkg/controllers/v1alpha1/databackup/implement_test.go
SonarQubeCloud / SonarCloud Code Analysis
Define a constant instead of duplicating this literal "local:///tmp/backup" 3 times.
See more on https://sonarcloud.io/project/issues?id=fluid-cloudnative_fluid&issues=AZ0fmepcshhUnMiqw3XA&open=AZ0fmepcshhUnMiqw3XA&pullRequest=5713
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The testScheme is already initialized in the BeforeEach block and is accessible within this test case. Creating a new scheme testScheme2 is redundant. You can reuse testScheme when creating the fake client to make the test code cleaner and less repetitive.
| testScheme2 := runtime.NewScheme() | |
| _ = datav1alpha1.AddToScheme(testScheme2) | |
| _ = corev1.AddToScheme(testScheme2) | |
| dataBackup2 := dataBackup.DeepCopy() | |
| dataBackup2.Spec.BackupPath = "local:///tmp/backup" | |
| fakeClient2 := fake.NewFakeClientWithScheme(testScheme2, dataBackup2, backupPod) | |
| dataBackup2 := dataBackup.DeepCopy() | |
| dataBackup2.Spec.BackupPath = "local:///tmp/backup" | |
| fakeClient2 := fake.NewFakeClientWithScheme(testScheme, dataBackup2, backupPod) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The testScheme is already initialized in the BeforeEach block. You can reuse it here instead of creating a new testScheme4.
| testScheme4 := runtime.NewScheme() | |
| _ = datav1alpha1.AddToScheme(testScheme4) | |
| _ = corev1.AddToScheme(testScheme4) | |
| fakeClient4 := fake.NewFakeClientWithScheme(testScheme4, dataBackup) | |
| fakeClient4 := fake.NewFakeClientWithScheme(testScheme, dataBackup) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The testScheme is already initialized in the BeforeEach block. You can reuse it here instead of creating a new testScheme3.
| testScheme3 := runtime.NewScheme() | |
| _ = datav1alpha1.AddToScheme(testScheme3) | |
| _ = corev1.AddToScheme(testScheme3) | |
| fakeClient3 := fake.NewFakeClientWithScheme(testScheme3, dataBackup, dataset) | |
| fakeClient3 := fake.NewFakeClientWithScheme(testScheme, dataBackup, dataset) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block contains redundant setup code. The testScheme is already created in the BeforeEach block and can be reused. Also, creating a new operation object (op3) for this test makes it verbose. A better approach is to update the client of the existing op object, which is reset for each test. This makes the test cleaner and easier to read.
A similar pattern of redundant setup is present in other tests like UpdateStatusInfoForCompleted and UpdateOperationApiStatus and could also be refactored.
| testScheme3 := runtime.NewScheme() | |
| _ = datav1alpha1.AddToScheme(testScheme3) | |
| _ = corev1.AddToScheme(testScheme3) | |
| fakeClient3 := fake.NewFakeClientWithScheme(testScheme3, dataBackup, dataset) | |
| op3 := &dataBackupOperation{ | |
| Client: fakeClient3, | |
| Log: ctrl.Log.WithName("test"), | |
| Recorder: record.NewFakeRecorder(10), | |
| dataBackup: dataBackup, | |
| } | |
| got, err := op3.GetTargetDataset() | |
| op.Client = fake.NewFakeClientWithScheme(testScheme, dataBackup, dataset) | |
| got, err := op.GetTargetDataset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The setup for the reconciler is duplicated in both test cases within this
Describeblock. To improve readability and maintainability, you can extract the common setup into aBeforeEachblock.