Repository: spidernet-io/spiderpool
Pull request #1402 (2023-03-06 08:58:50)

test: Add some unit tests for Endpoint manager and STS manager
Signed-off-by: iiiceoo <ziqian.xue@daocloud.io>

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=spidernet-io_spiderpool&pullRequest=1402)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1402&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1402) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1402&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/cmd/spiderpoolctl/cmd/command_root.go b/cmd/spiderpoolctl/cmd/command_root.go
index 76fea6eab..d0c73e8ad 100644
--- a/cmd/spiderpoolctl/cmd/command_root.go
+++ b/cmd/spiderpoolctl/cmd/command_root.go
@@ -30,6 +30,5 @@ func Execute() {
 
 func init() {
 	rootCmd.CompletionOptions.HiddenDefaultCmd = true
-
 	rootCmd.AddCommand(cmdgenmd.GenMarkDownCmd(SPIDERPOOL_CTL, rootCmd, logger))
 }
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager.go b/pkg/workloadendpointmanager/workloadendpoint_manager.go
index ea787136c..74e300ca3 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager.go
@@ -142,7 +142,9 @@ func (em *workloadEndpointManager) PatchIPAllocationResults(ctx context.Context,
 		return em.client.Create(ctx, endpoint)
 	}
 
-	if endpoint.Status.Current != nil && endpoint.Status.Current.UID == string(pod.UID) {
+	if endpoint.Status.Current != nil &&
+		endpoint.Status.Current.ContainerID == containerID &&
+		endpoint.Status.Current.UID == string(pod.UID) {
 		return nil
 	}
 
@@ -160,8 +162,7 @@ func (em *workloadEndpointManager) ReallocateCurrentIPAllocation(ctx context.Con
 	}
 
 	if endpoint.Status.Current.ContainerID == containerID &&
-		endpoint.Status.Current.UID == uid &&
-		endpoint.Status.Current.Node == nodeName {
+		endpoint.Status.Current.UID == uid {
 		return nil
 	}
 


Test patch:
diff --git a/pkg/lock/lock_debug_test.go b/pkg/lock/lock_debug_test.go
index f8582a657..f5f21e4ae 100644
--- a/pkg/lock/lock_debug_test.go
+++ b/pkg/lock/lock_debug_test.go
@@ -33,12 +33,12 @@ var _ = Describe("Debug lock", Label("unitest", "lock_test"), func() {
 			mutex = &lock.Mutex{}
 		})
 
-		It("general use", func() {
+		It("locks", func() {
 			mutex.Lock()
 			mutex.Unlock()
 		})
 
-		It("took lock timeout", func() {
+		It("holds the lock timeout", func() {
 			go func() {
 				mutex.Lock()
 				time.Sleep(selfishTimeout)
@@ -48,7 +48,7 @@ var _ = Describe("Debug lock", Label("unitest", "lock_test"), func() {
 			Eventually(buffer).Should(gbytes.Say("goroutine"))
 		})
 
-		It("ignore timeout when unlocking", func() {
+		It("ignores the timeout when unlocking", func() {
 			go func() {
 				mutex.Lock()
 				time.Sleep(selfishTimeout)
@@ -66,7 +66,7 @@ var _ = Describe("Debug lock", Label("unitest", "lock_test"), func() {
 			rwMutex = &lock.RWMutex{}
 		})
 
-		It("general use", func() {
+		It("locks", func() {
 			rwMutex.RLock()
 			rwMutex.RUnlock()
 
@@ -74,7 +74,7 @@ var _ = Describe("Debug lock", Label("unitest", "lock_test"), func() {
 			rwMutex.Unlock()
 		})
 
-		It("took lock timeout", func() {
+		It("holds the lock timeout", func() {
 			go func() {
 				rwMutex.Lock()
 				time.Sleep(selfishTimeout)
@@ -84,7 +84,7 @@ var _ = Describe("Debug lock", Label("unitest", "lock_test"), func() {
 			Eventually(buffer).Should(gbytes.Say("goroutine"))
 		})
 
-		It("ignore timeout when unlocking", func() {
+		It("ignores the timeout when unlocking", func() {
 			go func() {
 				rwMutex.Lock()
 				time.Sleep(selfishTimeout)
diff --git a/pkg/lock/lock_fast_test.go b/pkg/lock/lock_fast_test.go
index 6b95f7ef9..41a6d2f4c 100644
--- a/pkg/lock/lock_fast_test.go
+++ b/pkg/lock/lock_fast_test.go
@@ -21,7 +21,7 @@ var _ = Describe("Fast lock", Label("unitest", "lock_test"), func() {
 			mutex = &lock.Mutex{}
 		})
 
-		It("general use", func() {
+		It("locks", func() {
 			mutex.Lock()
 			Expect(mutex.TryLock()).NotTo(BeTrue())
 
@@ -41,7 +41,7 @@ var _ = Describe("Fast lock", Label("unitest", "lock_test"), func() {
 			rwMutex = &lock.RWMutex{}
 		})
 
-		It("general use", func() {
+		It("locks", func() {
 			rwMutex.Lock()
 			Expect(rwMutex.TryRLock()).NotTo(BeTrue())
 			Expect(rwMutex.TryLock()).NotTo(BeTrue())
diff --git a/pkg/statefulsetmanager/sts_manager_test.go b/pkg/statefulsetmanager/sts_manager_test.go
index 71b0ffba6..df1ab95b1 100644
--- a/pkg/statefulsetmanager/sts_manager_test.go
+++ b/pkg/statefulsetmanager/sts_manager_test.go
@@ -6,6 +6,7 @@ package statefulsetmanager_test
 import (
 	"context"
 	"fmt"
+	"strconv"
 	"sync/atomic"
 
 	"github.com/agiledragon/gomonkey/v2"
@@ -182,7 +183,61 @@ var _ = Describe("StatefulSetManager", Label("sts_manager_test"), func() {
 			})
 		})
 
-		PDescribe("IsValidStatefulSetPod", func() {
+		Describe("IsValidStatefulSetPod", func() {
+			It("is not a Pod of StatefulSet", func() {
+				ctx := context.TODO()
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, "invalid")
+				Expect(valid).To(BeFalse())
+			})
+
+			It("failed to parse replica string to int due to some unknown errors", func() {
+				patches := gomonkey.ApplyFuncReturn(strconv.ParseInt, int64(0), constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, fmt.Sprintf("%s-%d", stsName, 0))
+				Expect(valid).To(BeFalse())
+			})
+
+			It("is a valid Pod controlled by StatefulSet, but the StatefulSet no longer exists", func() {
+				ctx := context.TODO()
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, fmt.Sprintf("%s-%d", stsName, 0))
+				Expect(valid).To(BeFalse())
+			})
+
+			It("failed to get StatefulSets due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Get", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, fmt.Sprintf("%s-%d", stsName, 0))
+				Expect(valid).To(BeTrue())
+			})
+
+			It("used to be a Pod controlled by StatefulSet, but the StatefulSet scaled down", func() {
+				replicas := int32(1)
+				stsT.Spec.Replicas = &replicas
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, stsT)
+				Expect(err).NotTo(HaveOccurred())
+
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, fmt.Sprintf("%s-%d", stsName, replicas))
+				Expect(valid).To(BeFalse())
+			})
+
+			It("is a valid Pod controlled by StatefulSet", func() {
+				replicas := int32(1)
+				stsT.Spec.Replicas = &replicas
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, stsT)
+				Expect(err).NotTo(HaveOccurred())
+
+				valid := stsManager.IsValidStatefulSetPod(ctx, stsT.Namespace, fmt.Sprintf("%s-%d", stsName, replicas-1))
+				Expect(valid).To(BeTrue())
+			})
+
 		})
 	})
 })
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager_test.go b/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
index fa2f77a4c..776fcc86c 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager_test.go
@@ -11,6 +11,8 @@ import (
 	"github.com/agiledragon/gomonkey/v2"
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
+	appsv1 "k8s.io/api/apps/v1"
+	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
@@ -22,6 +24,7 @@ import (
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	spiderpooltypes "github.com/spidernet-io/spiderpool/pkg/types"
 	"github.com/spidernet-io/spiderpool/pkg/workloadendpointmanager"
 )
 
@@ -280,7 +283,123 @@ var _ = Describe("WorkloadEndpointManager", Label("workloadendpoint_manager_test
 			})
 		})
 
-		PDescribe("PatchIPAllocationResults", func() {
+		Describe("PatchIPAllocationResults", func() {
+			var podT *corev1.Pod
+
+			BeforeEach(func() {
+				podT = &corev1.Pod{
+					TypeMeta: metav1.TypeMeta{
+						Kind:       "Pod",
+						APIVersion: corev1.SchemeGroupVersion.String(),
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      endpointName,
+						Namespace: namespace,
+						UID:       uuid.NewUUID(),
+					},
+					Spec: corev1.PodSpec{
+						NodeName: "node",
+					},
+				}
+			})
+
+			It("inputs nil Pod", func() {
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(ctx, "", []*spiderpooltypes.AllocationResult{}, nil, nil, spiderpooltypes.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			})
+
+			It("failed to set ownerReference to Pod due to some unknown errors", func() {
+				patches := gomonkey.ApplyFuncReturn(controllerutil.SetOwnerReference, constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(ctx, "", []*spiderpooltypes.AllocationResult{}, nil, podT, spiderpooltypes.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
+			It("failed to create Endpoint due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Create", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(ctx, "", []*spiderpooltypes.AllocationResult{}, nil, podT, spiderpooltypes.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
+			It("creates Endpoint for orphan Pod", func() {
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(
+					ctx,
+					"",
+					[]*spiderpooltypes.AllocationResult{},
+					nil,
+					podT,
+					spiderpooltypes.PodTopController{
+						Kind:      constant.KindPod,
+						Namespace: podT.Namespace,
+						Name:      podT.Name,
+						UID:       podT.UID,
+						APP:       podT,
+					},
+				)
+				Expect(err).NotTo(HaveOccurred())
+
+				var endpoint spiderpoolv1.SpiderEndpoint
+				err = fakeClient.Get(ctx, types.NamespacedName{Namespace: podT.Namespace, Name: podT.Name}, &endpoint)
+				Expect(err).NotTo(HaveOccurred())
+
+				owner := endpoint.GetOwnerReferences()[0]
+				Expect(owner.UID).To(Equal(podT.GetUID()))
+				Expect(controllerutil.ContainsFinalizer(&endpoint, constant.SpiderFinalizer))
+			})
+
+			It("creates Endpoint for StatefulSet Pod", func() {
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(
+					ctx,
+					"",
+					[]*spiderpooltypes.AllocationResult{},
+					nil,
+					podT,
+					spiderpooltypes.PodTopController{
+						Kind:      constant.KindStatefulSet,
+						Namespace: namespace,
+						Name:      fmt.Sprintf("%s-sts", endpointName),
+						UID:       uuid.NewUUID(),
+						APP:       &appsv1.StatefulSet{},
+					},
+				)
+				Expect(err).NotTo(HaveOccurred())
+
+				var endpoint spiderpoolv1.SpiderEndpoint
+				err = fakeClient.Get(ctx, types.NamespacedName{Namespace: podT.Namespace, Name: podT.Name}, &endpoint)
+				Expect(err).NotTo(HaveOccurred())
+
+				owners := endpoint.GetOwnerReferences()
+				Expect(owners).To(BeEmpty())
+				Expect(controllerutil.ContainsFinalizer(&endpoint, constant.SpiderFinalizer))
+			})
+
+			It("patches IP allocation results with the same container ID and Pod UID", func() {
+				uid := uuid.NewUUID()
+				podT.SetUID(uid)
+				endpointT.Status.Current.UID = string(uid)
+
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(ctx, "", []*spiderpooltypes.AllocationResult{}, endpointT, podT, spiderpooltypes.PodTopController{})
+				Expect(err).NotTo(HaveOccurred())
+			})
+
+			It("failed to update the status of Endpoint due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Update", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := endpointManager.PatchIPAllocationResults(ctx, "", []*spiderpooltypes.AllocationResult{}, endpointT, podT, spiderpooltypes.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
 		})
 
 		Describe("ReallocateCurrentIPAllocation", func() {
@@ -298,15 +417,12 @@ var _ = Describe("WorkloadEndpointManager", Label("workloadendpoint_manager_test
 				Expect(err).To(HaveOccurred())
 			})
 
-			It("re-allocates the current IP allocation with the same container ID, Pod UID and Node name", func() {
-				uid := string(uuid.NewUUID())
-				nodeName := "node1"
-
-				endpointT.Status.Current.UID = uid
-				endpointT.Status.Current.Node = nodeName
+			It("re-allocates the current IP allocation with the same container ID and Pod UID", func() {
+				uid := uuid.NewUUID()
+				endpointT.Status.Current.UID = string(uid)
 
 				ctx := context.TODO()
-				err := endpointManager.ReallocateCurrentIPAllocation(ctx, "", uid, nodeName, endpointT)
+				err := endpointManager.ReallocateCurrentIPAllocation(ctx, "", string(uid), "node", endpointT)
 				Expect(err).NotTo(HaveOccurred())
 			})
 
@@ -315,10 +431,9 @@ var _ = Describe("WorkloadEndpointManager", Label("workloadendpoint_manager_test
 				defer patches.Reset()
 
 				endpointT.Status.Current.UID = string(uuid.NewUUID())
-				endpointT.Status.Current.Node = "node1"
 
 				ctx := context.TODO()
-				err := endpointManager.ReallocateCurrentIPAllocation(ctx, "", string(uuid.NewUUID()), "node1", endpointT)
+				err := endpointManager.ReallocateCurrentIPAllocation(ctx, "", string(uuid.NewUUID()), "node", endpointT)
 				Expect(err).To(MatchError(constant.ErrUnknown))
 			})