From 96cd929f58de70586f7665bfa2ab4b1b09147d83 Mon Sep 17 00:00:00 2001 From: Kefei Zhang Date: Tue, 27 Aug 2024 07:28:44 +0800 Subject: [PATCH] Enhance ut (#350) * add change status ut Signed-off-by: KfreeZ * add remove step test Signed-off-by: KfreeZ * remove useless code Signed-off-by: KfreeZ --------- Signed-off-by: KfreeZ --- .../controller/gmconnector_controller_test.go | 509 +++++++++++++++--- 1 file changed, 437 insertions(+), 72 deletions(-) diff --git a/microservices-connector/internal/controller/gmconnector_controller_test.go b/microservices-connector/internal/controller/gmconnector_controller_test.go index 1e6b7d68..8b600cfb 100644 --- a/microservices-connector/internal/controller/gmconnector_controller_test.go +++ b/microservices-connector/internal/controller/gmconnector_controller_test.go @@ -16,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/reconcile" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -187,98 +188,267 @@ var _ = Describe("GMConnector Controller", func() { Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) }) It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") controllerReconciler := &GMConnectorReconciler{ Client: k8sClient, Scheme: k8sClient.Scheme(), } + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + + Expect(err).NotTo(HaveOccurred()) + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-embedding-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-embedding-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "vector-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "vector-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "rerank-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "rerank-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "reranking-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-reranking-svc", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-reranking-svc-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "teirerank-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-service-name", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-service-name-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-uservice-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "router-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "router-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + pipeline := &mcv1alpha3.GMConnector{} + Expect(k8sClient.Get(ctx, typeNamespacedName, pipeline)).To(Succeed()) + Expect(pipeline.Status.Status).To(Equal("0/0/9")) + Expect(len(pipeline.Status.Annotations)).To(Equal(25)) + + }) + + It("should successfully reconcile the deployment for status update", func() { + controllerReconciler := &GMConnectorReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + By("Reconciling the existed resource") + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + embedDp := &appsv1.Deployment{} + embedDpMeta := types.NamespacedName{ + Name: "embedding-service-deployment", + Namespace: "default", + } + Expect(k8sClient.Get(ctx, embedDpMeta, embedDp)).To(Succeed()) + embedDp.Status.AvailableReplicas = int32(1) + embedDp.Status.Replicas = embedDp.Status.AvailableReplicas + embedDp.Status.ReadyReplicas = embedDp.Status.AvailableReplicas + Expect(*embedDp.Spec.Replicas).To(Equal(int32(1))) + Expect(embedDp.OwnerReferences[0].Name).To(Equal(resourceName)) + Expect(embedDp.OwnerReferences[0].Kind).To(Equal("GMConnector")) + err = k8sClient.Status().Update(ctx, embedDp) + Expect(err).NotTo(HaveOccurred()) + embedDp2 := &appsv1.Deployment{} + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-service-deployment", + Namespace: "default", + }, embedDp2)).To(Succeed()) + Expect(embedDp2.Status.AvailableReplicas).To(Equal(int32(1))) + _, err = controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: embedDpMeta, + }) + Expect(err).NotTo(HaveOccurred()) + pipeline := &mcv1alpha3.GMConnector{} + Expect(k8sClient.Get(ctx, typeNamespacedName, pipeline)).To(Succeed()) + Expect(pipeline.Status.Status).To(Equal("1/0/9")) + }) + It("should successfully reconcile the deployment for removing step", func() { + controllerReconciler := &GMConnectorReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + By("Reconciling the existed resource") _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ NamespacedName: typeNamespacedName, }) + Expect(err).NotTo(HaveOccurred()) + err = k8sClient.Get(ctx, typeNamespacedName, gmconnector) Expect(err).NotTo(HaveOccurred()) - // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. - // Example: If you expect a certain status condition after reconciliation, verify it here. - // update the resources - resource := &mcv1alpha3.GMConnector{} - Expect(k8sClient.Get(ctx, typeNamespacedName, resource)).To(Succeed()) - resource.Spec = mcv1alpha3.GMConnectorSpec{ - RouterConfig: mcv1alpha3.RouterConfig{ - Name: "router", - ServiceName: "router-service", - Config: map[string]string{ - "endpoint": "/", + resource := &mcv1alpha3.GMConnector{ + TypeMeta: gmconnector.TypeMeta, + ObjectMeta: gmconnector.ObjectMeta, + Spec: mcv1alpha3.GMConnectorSpec{ + RouterConfig: mcv1alpha3.RouterConfig{ + Name: "router", + ServiceName: "router-service", + Config: map[string]string{ + "endpoint": "/", + }, }, - }, - Nodes: map[string]mcv1alpha3.Router{ - "root": { - RouterType: "Sequence", - Steps: []mcv1alpha3.Step{ - { - StepName: TeiEmbeddingGaudi, - Executor: mcv1alpha3.Executor{ - InternalService: mcv1alpha3.GMCTarget{ - NameSpace: "default", - ServiceName: "tei-embedding-service", - Config: map[string]string{ - "endpoint": "/v1/tei-embeddings", - "MODEL_ID": "somemodel", - }, - IsDownstreamService: true, - }, - }, - }, - { - StepName: DataPrep, - Executor: mcv1alpha3.Executor{ - InternalService: mcv1alpha3.GMCTarget{ - NameSpace: "default", - ServiceName: "dataPrep-service", - Config: map[string]string{ - "endpoint": "/v1/vec", + Nodes: map[string]mcv1alpha3.Router{ + "root": { + RouterType: "Sequence", + Steps: []mcv1alpha3.Step{ + { + StepName: TeiEmbedding, + Executor: mcv1alpha3.Executor{ + InternalService: mcv1alpha3.GMCTarget{ + NameSpace: "default", + ServiceName: "tei-embedding-service", + Config: map[string]string{ + "endpoint": "/v1/tei-embeddings", + "MODEL_ID": "somemodel", + }, + IsDownstreamService: true, }, - IsDownstreamService: true, }, }, - }, - { - StepName: WebRetriever, - Executor: mcv1alpha3.Executor{ - InternalService: mcv1alpha3.GMCTarget{ - NameSpace: "default", - ServiceName: "webretriever-service", - Config: map[string]string{ - "endpoint": "/v1/retrv", - "REDIS_URL": "vector-service", - "TEI_EMBEDDING_ENDPOINT": "tei-embedding-service", + { + StepName: VectorDB, + Executor: mcv1alpha3.Executor{ + InternalService: mcv1alpha3.GMCTarget{ + NameSpace: "default", + ServiceName: "vector-service", + Config: map[string]string{ + "endpoint": "/v1/vec", + }, + IsDownstreamService: true, }, }, }, - }, - { - StepName: TgiGaudi, - Executor: mcv1alpha3.Executor{ - InternalService: mcv1alpha3.GMCTarget{ - NameSpace: "default", - ServiceName: "tgiguadi-service-name", - Config: map[string]string{ - "endpoint": "/generate", + { + StepName: TeiReranking, + Executor: mcv1alpha3.Executor{ + InternalService: mcv1alpha3.GMCTarget{ + NameSpace: "default", + ServiceName: "tei-reranking-svc", + Config: map[string]string{ + "endpoint": "/rernk", + }, + IsDownstreamService: true, }, - IsDownstreamService: true, }, }, - }, - { - StepName: Llm, - Executor: mcv1alpha3.Executor{ - InternalService: mcv1alpha3.GMCTarget{ - NameSpace: "default", - ServiceName: "llm-service", - Config: map[string]string{ - "endpoint": "/v1/llm", - "TGI_LLM_ENDPOINT": "tgi-service-name", + { + StepName: Tgi, + Executor: mcv1alpha3.Executor{ + InternalService: mcv1alpha3.GMCTarget{ + NameSpace: "default", + ServiceName: "tgi-service-name", + Config: map[string]string{ + "endpoint": "/generate", + }, + IsDownstreamService: true, }, }, }, @@ -287,10 +457,142 @@ var _ = Describe("GMConnector Controller", func() { }, }, } - Expect(k8sClient.Update(ctx, resource)).To(Succeed()) - }) + _, err = controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-service", + Namespace: "default", + }, &corev1.Service{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "embedding-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-embedding-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-embedding-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "vector-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "vector-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-service", + Namespace: "default", + }, &corev1.Service{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).NotTo(Succeed()) + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "retriever-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "rerank-service", + Namespace: "default", + }, &corev1.Service{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "rerank-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "reranking-usvc-config", + Namespace: "default", + }, &corev1.ConfigMap{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-reranking-svc", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tei-reranking-svc-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "teirerank-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-service-name", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-service-name-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "tgi-config", + Namespace: "default", + }, &corev1.ConfigMap{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-service", + Namespace: "default", + }, &corev1.Service{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "llm-uservice-config", + Namespace: "default", + }, &corev1.ConfigMap{})).NotTo(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "router-service", + Namespace: "default", + }, &corev1.Service{})).To(Succeed()) + + Expect(k8sClient.Get(ctx, types.NamespacedName{ + Name: "router-service-deployment", + Namespace: "default", + }, &appsv1.Deployment{})).To(Succeed()) + + pipeline := &mcv1alpha3.GMConnector{} + Expect(k8sClient.Get(ctx, typeNamespacedName, pipeline)).To(Succeed()) + Expect(pipeline.Status.Status).To(Equal("0/0/5")) + Expect(len(pipeline.Status.Annotations)).To(Equal(13)) + }) }) }) @@ -453,3 +755,66 @@ func TestIsMetadataChanged(t *testing.T) { t.Errorf("Expected metadata changes to not be detected, but got true") } } + +// func TestHandleStatusUpdate(t *testing.T) { +// // Create a fake GMConnector object +// graph := &mcv1alpha3.GMConnector{ +// ObjectMeta: metav1.ObjectMeta{ +// Namespace: "default", +// Name: "test-graph", +// }, +// } + +// // Create a fake Deployment object +// deployment := &appsv1.Deployment{ +// ObjectMeta: metav1.ObjectMeta{ +// Namespace: "default", +// Name: "test-deployment", +// OwnerReferences: []metav1.OwnerReference{ +// { +// Kind: "GMConnector", +// Name: "test-graph", +// }, +// }, +// }, +// } + +// // Create a fake GMConnectorReconciler +// r := &GMConnectorReconciler{ +// Client: fake.NewFakeClientWithScheme(scheme.Scheme, graph, deployment), +// } + +// // Create a fake context +// ctx := context.TODO() + +// // Create a fake reconcile request +// req := reconcile.Request{ +// NamespacedName: types.NamespacedName{ +// Namespace: "default", +// Name: "test-deployment", +// }, +// } + +// // Call the handleStatusUpdate function +// result, err := r.handleStatusUpdate(ctx, deployment) + +// // Check the result and error +// if err != nil { +// t.Errorf("handleStatusUpdate returned an error: %v", err) +// } + +// if result != (reconcile.Result{}) { +// t.Errorf("handleStatusUpdate returned an unexpected result: %v", result) +// } + +// // Check if the GMConnector object's status has been updated +// err = r.Get(ctx, types.NamespacedName{Namespace: "default", Name: "test-graph"}, graph) +// if err != nil { +// t.Errorf("Failed to get GMConnector object: %v", err) +// } + +// expectedStatus := "0/0/1" +// if graph.Status.Status != expectedStatus { +// t.Errorf("GMConnector object's status is not updated correctly. Expected: %s, Got: %s", expectedStatus, graph.Status.Status) +// } +// }