Skip to content

Commit 7955507

Browse files
shengnuoshivamerla
authored andcommitted
Add unit tests for NeMoDataStore
Signed-off-by: Sheng Lin <[email protected]>
1 parent 68857c9 commit 7955507

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package controller
2+
3+
import (
4+
"context"
5+
"path/filepath"
6+
"time"
7+
8+
appsv1alpha1 "github.com/NVIDIA/k8s-nim-operator/api/apps/v1alpha1"
9+
"github.com/NVIDIA/k8s-nim-operator/internal/conditions"
10+
"github.com/NVIDIA/k8s-nim-operator/internal/render"
11+
. "github.com/onsi/ginkgo/v2"
12+
. "github.com/onsi/gomega"
13+
monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
14+
appsv1 "k8s.io/api/apps/v1"
15+
autoscalingv2 "k8s.io/api/autoscaling/v2"
16+
batchv1 "k8s.io/api/batch/v1"
17+
corev1 "k8s.io/api/core/v1"
18+
networkingv1 "k8s.io/api/networking/v1"
19+
rbacv1 "k8s.io/api/rbac/v1"
20+
"k8s.io/apimachinery/pkg/api/errors"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"k8s.io/client-go/tools/record"
23+
24+
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/types"
26+
27+
"sigs.k8s.io/controller-runtime/pkg/client"
28+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
29+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
30+
)
31+
32+
var _ = Describe("NemoDatastore Controller", func() {
33+
const resourceName = "test-resource"
34+
35+
var (
36+
dsRec *NemoDatastoreReconciler
37+
scheme *runtime.Scheme
38+
client client.Client
39+
40+
ctx = context.Background()
41+
42+
typeNamespacedName = types.NamespacedName{
43+
Name: resourceName,
44+
Namespace: "default", // TODO(user):Modify as needed
45+
}
46+
47+
t = true
48+
resource = &appsv1alpha1.NemoDatastore{
49+
ObjectMeta: metav1.ObjectMeta{
50+
Name: resourceName,
51+
Namespace: "default",
52+
},
53+
Spec: appsv1alpha1.NemoDatastoreSpec{
54+
Image: appsv1alpha1.Image{
55+
Repository: "test-repo",
56+
Tag: "test-tag",
57+
},
58+
Replicas: 1,
59+
DatabaseConfig: appsv1alpha1.DatabaseConfig{
60+
Host: "test-pg-host",
61+
DatabaseName: "test-pg-database",
62+
Credentials: &appsv1alpha1.DatabaseCredentials{
63+
User: "test-pg-user",
64+
SecretName: "test-pg-secret",
65+
},
66+
},
67+
PVC: &appsv1alpha1.PersistentVolumeClaim{
68+
Name: "test-resource-pvc",
69+
Create: &t,
70+
StorageClass: "local-path",
71+
VolumeAccessMode: corev1.ReadWriteOnce,
72+
Size: "1Gi",
73+
},
74+
ObjectStoreConfig: appsv1alpha1.ObjectStoreConfig{
75+
Endpoint: "test-mino-host",
76+
BucketName: "test-bucket",
77+
Region: "test-region",
78+
SSL: false,
79+
},
80+
},
81+
}
82+
)
83+
84+
BeforeEach(func() {
85+
scheme = runtime.NewScheme()
86+
Expect(appsv1alpha1.AddToScheme(scheme)).To(Succeed())
87+
Expect(batchv1.AddToScheme(scheme)).To(Succeed())
88+
Expect(corev1.AddToScheme(scheme)).To(Succeed())
89+
Expect(autoscalingv2.AddToScheme(scheme)).To(Succeed())
90+
Expect(rbacv1.AddToScheme(scheme)).To(Succeed())
91+
Expect(networkingv1.AddToScheme(scheme)).To(Succeed())
92+
Expect(monitoringv1.AddToScheme(scheme)).To(Succeed())
93+
Expect(appsv1.AddToScheme(scheme)).To(Succeed())
94+
95+
manifestsDir, err := filepath.Abs("../../manifests")
96+
Expect(err).ToNot(HaveOccurred())
97+
98+
client = fake.NewClientBuilder().WithScheme(scheme).
99+
WithStatusSubresource(&appsv1alpha1.NemoDatastore{}).
100+
WithStatusSubresource(&appsv1.Deployment{}).
101+
Build()
102+
103+
dsRec = &NemoDatastoreReconciler{
104+
Client: client,
105+
scheme: scheme,
106+
updater: conditions.NewUpdater(client),
107+
recorder: record.NewFakeRecorder(1000),
108+
renderer: render.NewRenderer(manifestsDir),
109+
}
110+
})
111+
112+
Context("DataStore CR validation", func() {
113+
var (
114+
invalidDS *appsv1alpha1.NemoDatastore
115+
)
116+
117+
BeforeEach(func() {
118+
invalidDS = &appsv1alpha1.NemoDatastore{
119+
ObjectMeta: metav1.ObjectMeta{
120+
Name: resourceName,
121+
Namespace: "default",
122+
},
123+
Spec: appsv1alpha1.NemoDatastoreSpec{},
124+
}
125+
})
126+
127+
It("should reject DataStore with empty spec", func() {
128+
err := k8sClient.Create(ctx, invalidDS)
129+
Expect(err).To(HaveOccurred())
130+
Expect(errors.IsInvalid(err)).To(BeTrue())
131+
})
132+
133+
It("should reject DataStore with invalid database config", func() {
134+
invalidDS.Spec.DatabaseConfig = appsv1alpha1.DatabaseConfig{}
135+
err := k8sClient.Create(ctx, invalidDS)
136+
Expect(err).To(HaveOccurred())
137+
Expect(errors.IsInvalid(err)).To(BeTrue())
138+
})
139+
140+
It("should reject DataStore with invalid object store config", func() {
141+
invalidDS.Spec.ObjectStoreConfig = appsv1alpha1.ObjectStoreConfig{}
142+
err := k8sClient.Create(ctx, invalidDS)
143+
Expect(err).To(HaveOccurred())
144+
Expect(errors.IsInvalid(err)).To(BeTrue())
145+
})
146+
147+
It("should reject DataStore with invalid pre-requisite secrets", func() {
148+
invalidDS.Spec.Secrets = appsv1alpha1.Secrets{}
149+
err := k8sClient.Create(ctx, invalidDS)
150+
Expect(err).To(HaveOccurred())
151+
Expect(errors.IsInvalid(err)).To(BeTrue())
152+
})
153+
})
154+
155+
Context("DataStore CR reconciliation", func() {
156+
It("should successfully reconcile the DataStore object", func() {
157+
By("creating the custom resource for the kind NemoDatastore")
158+
Expect(client.Create(ctx, resource)).To(Succeed())
159+
160+
_, err := dsRec.Reconcile(ctx, reconcile.Request{
161+
NamespacedName: typeNamespacedName,
162+
})
163+
Expect(err).ToNot(HaveOccurred())
164+
165+
ds := &appsv1alpha1.NemoDatastore{}
166+
Expect(client.Get(ctx, typeNamespacedName, ds)).To(Succeed())
167+
Expect(ds.Finalizers).To(ContainElement(NemoDatastoreFinalizer))
168+
Expect(ds.Status.State).To(Equal(appsv1alpha1.NemoDatastoreStatusNotReady))
169+
170+
By("Ensuring PVC is created")
171+
pvc := &corev1.PersistentVolumeClaim{}
172+
Expect(client.Get(ctx, types.NamespacedName{
173+
Name: resource.Spec.PVC.Name,
174+
Namespace: resource.Namespace,
175+
}, pvc))
176+
177+
By("Ensuring Deployment is created")
178+
dsDep := appsv1.Deployment{}
179+
Expect(client.Get(ctx, typeNamespacedName, &dsDep)).To(Succeed())
180+
181+
By("Ensuring resources are deleted along with datastore CR")
182+
Expect(client.Delete(ctx, resource)).To(Succeed())
183+
_, err = dsRec.Reconcile(ctx, reconcile.Request{
184+
NamespacedName: typeNamespacedName,
185+
})
186+
Expect(err).ToNot(HaveOccurred())
187+
188+
Eventually(func() bool {
189+
ds = &appsv1alpha1.NemoDatastore{}
190+
err := client.Get(ctx, typeNamespacedName, ds)
191+
return err != nil && errors.IsNotFound(err)
192+
}, time.Second*5, time.Millisecond*500).Should(BeTrue())
193+
})
194+
})
195+
})

0 commit comments

Comments
 (0)