Repository: spidernet-io/spiderpool
Pull request #1178 (2022-12-13 02:41:54)

test: Add unit tests for pkg podmanager
Signed-off-by: iiiceoo <ziqian.xue@daocloud.io>


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

[![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=1178&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=1178&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178) No Coverage information  
[![3.6%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/5-16px.png '3.6%')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list) [3.6% Duplication](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list)


codecov[bot]: # [Codecov](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) Report
> Merging [#1178](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (2107a6e) into [main](https://codecov.io/gh/spidernet-io/spiderpool/commit/aa0caa3e05b4f74389457b41dab938a6c6e608a7?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (aa0caa3) will **increase** coverage by `6.76%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178/graphs/tree.svg?width=650&height=150&src=pr&token=YKXY2E4Q8G&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io)

```diff
@@            Coverage Diff             @@
##             main    #1178      +/-   ##
==========================================
+ Coverage   81.44%   88.21%   +6.76%     
==========================================
  Files          24       25       +1     
  Lines        1525     1510      -15     
==========================================
+ Hits         1242     1332      +90     
+ Misses        259      154     -105     
  Partials       24       24              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `88.21% <100.00%> (+6.76%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | Coverage Δ | |
|---|---|---|
| [pkg/limiter/config.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2xpbWl0ZXIvY29uZmlnLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/podmanager/config.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3BvZG1hbmFnZXIvY29uZmlnLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/podmanager/pod\_manager.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3BvZG1hbmFnZXIvcG9kX21hbmFnZXIuZ28=) | `49.61% <100.00%> (+49.61%)` | :arrow_up: |
| [pkg/podmanager/utils.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1178/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL3BvZG1hbmFnZXIvdXRpbHMuZ28=) | `100.00% <100.00%> (+100.00%)` | :arrow_up: |

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

[![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=1178&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=1178&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=CODE_SMELL) [4 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178) No Coverage information  
[![3.6%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/5-16px.png '3.6%')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list) [3.6% Duplication](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list)


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

[![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=1178&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=1178&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=spidernet-io_spiderpool&pullRequest=1178&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=1178&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=1178&resolved=false&types=CODE_SMELL) [5 Code Smells](https://sonarcloud.io/project/issues?id=spidernet-io_spiderpool&pullRequest=1178&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=1178) No Coverage information  
[![3.6%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/5-16px.png '3.6%')](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list) [3.6% Duplication](https://sonarcloud.io/component_measures?id=spidernet-io_spiderpool&pullRequest=1178&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/cmd/spiderpool-agent/cmd/daemon.go b/cmd/spiderpool-agent/cmd/daemon.go
index 077adba90..c8c345de6 100644
--- a/cmd/spiderpool-agent/cmd/daemon.go
+++ b/cmd/spiderpool-agent/cmd/daemon.go
@@ -261,23 +261,6 @@ func initAgentServiceManagers(ctx context.Context) {
 		ConflictRetryUnitTime: time.Duration(agentContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
 	}
 
-	logger.Debug("Begin to initialize WorkloadEndpoint Manager")
-	weManager, err := workloadendpointmanager.NewWorkloadEndpointManager(&workloadendpointmanager.EndpointManagerConfig{
-		UpdateCRConfig:    updateCRConfig,
-		MaxHistoryRecords: agentContext.Cfg.WorkloadEndpointMaxHistoryRecords,
-	}, agentContext.CRDManager)
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	agentContext.WEManager = weManager
-
-	logger.Debug("Begin to initialize ReservedIP manager")
-	rIPManager, err := reservedipmanager.NewReservedIPManager(agentContext.CRDManager.GetClient())
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	agentContext.RIPManager = rIPManager
-
 	logger.Debug("Begin to initialize Node manager")
 	nodeManager, err := nodemanager.NewNodeManager(agentContext.CRDManager.GetClient())
 	if err != nil {
@@ -292,34 +275,52 @@ func initAgentServiceManagers(ctx context.Context) {
 	}
 	agentContext.NSManager = nsManager
 
-	logger.Debug("Begin to initialize Pod Manager")
-	podManager, err := podmanager.NewPodManager(&podmanager.PodManagerConfig{
-		UpdateCRConfig: updateCRConfig,
+	logger.Debug("Begin to initialize Pod manager")
+	podManager, err := podmanager.NewPodManager(podmanager.PodManagerConfig{
+		MaxConflictRetries:    agentContext.Cfg.UpdateCRMaxRetries,
+		ConflictRetryUnitTime: time.Duration(agentContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
 	}, agentContext.CRDManager.GetClient())
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
 	agentContext.PodManager = podManager
 
+	logger.Debug("Begin to initialize StatefulSet Manager")
+	statefulSetManager, err := statefulsetmanager.NewStatefulSetManager(agentContext.CRDManager)
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	agentContext.StsManager = statefulSetManager
+
+	logger.Debug("Begin to initialize WorkloadEndpoint Manager")
+	weManager, err := workloadendpointmanager.NewWorkloadEndpointManager(&workloadendpointmanager.EndpointManagerConfig{
+		UpdateCRConfig:    updateCRConfig,
+		MaxHistoryRecords: agentContext.Cfg.WorkloadEndpointMaxHistoryRecords,
+	}, agentContext.CRDManager, agentContext.PodManager)
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	agentContext.WEManager = weManager
+
+	logger.Debug("Begin to initialize ReservedIP manager")
+	rIPManager, err := reservedipmanager.NewReservedIPManager(agentContext.CRDManager.GetClient())
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	agentContext.RIPManager = rIPManager
+
 	logger.Debug("Begin to initialize IPPool Manager")
 	ipPoolManager, err := ippoolmanager.NewIPPoolManager(&ippoolmanager.IPPoolManagerConfig{
 		EnableIPv4:      agentContext.Cfg.EnableIPv4,
 		EnableIPv6:      agentContext.Cfg.EnableIPv6,
 		UpdateCRConfig:  updateCRConfig,
 		MaxAllocatedIPs: agentContext.Cfg.IPPoolMaxAllocatedIPs,
-	}, agentContext.CRDManager, agentContext.RIPManager)
+	}, agentContext.CRDManager, agentContext.PodManager, agentContext.RIPManager)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
 	agentContext.IPPoolManager = ipPoolManager
 
-	logger.Debug("Begin to initialize StatefulSet Manager")
-	statefulSetManager, err := statefulsetmanager.NewStatefulSetManager(agentContext.CRDManager)
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	agentContext.StsManager = statefulSetManager
-
 	if agentContext.Cfg.EnableSpiderSubnet {
 		logger.Info("Begin to initialize Subnet Manager")
 		subnetManager, err := subnetmanager.NewSubnetManager(&subnetmanager.SubnetManagerConfig{
diff --git a/cmd/spiderpool-controller/cmd/daemon.go b/cmd/spiderpool-controller/cmd/daemon.go
index 3e114e23b..c27d67f2c 100644
--- a/cmd/spiderpool-controller/cmd/daemon.go
+++ b/cmd/spiderpool-controller/cmd/daemon.go
@@ -218,11 +218,42 @@ func initControllerServiceManagers(ctx context.Context) {
 	logger.Info("Begin to initialize spiderpool controller leader election")
 	initSpiderControllerLeaderElect(controllerContext.InnerCtx)
 
+	logger.Debug("Begin to initialize Node manager")
+	nodeManager, err := nodemanager.NewNodeManager(controllerContext.CRDManager.GetClient())
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	controllerContext.NodeManager = nodeManager
+
+	logger.Debug("Begin to initialize Namespace manager")
+	nsManager, err := namespacemanager.NewNamespaceManager(controllerContext.CRDManager.GetClient())
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	controllerContext.NSManager = nsManager
+
+	logger.Debug("Begin to initialize Pod manager")
+	podManager, err := podmanager.NewPodManager(podmanager.PodManagerConfig{
+		MaxConflictRetries:    controllerContext.Cfg.UpdateCRMaxRetries,
+		ConflictRetryUnitTime: time.Duration(controllerContext.Cfg.UpdateCRRetryUnitTime) * time.Millisecond,
+	}, controllerContext.CRDManager.GetClient())
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	controllerContext.PodManager = podManager
+
+	logger.Info("Begin to initialize StatefulSet Manager")
+	statefulSetManager, err := statefulsetmanager.NewStatefulSetManager(controllerContext.CRDManager)
+	if err != nil {
+		logger.Fatal(err.Error())
+	}
+	controllerContext.StsManager = statefulSetManager
+
 	logger.Info("Begin to initialize WorkloadEndpoint Manager")
 	wepManager, err := workloadendpointmanager.NewWorkloadEndpointManager(&workloadendpointmanager.EndpointManagerConfig{
 		UpdateCRConfig:    updateCRConfig,
 		MaxHistoryRecords: controllerContext.Cfg.WorkloadEndpointMaxHistoryRecords,
-	}, controllerContext.CRDManager)
+	}, controllerContext.CRDManager, controllerContext.PodManager)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
@@ -250,36 +281,6 @@ func initControllerServiceManagers(ctx context.Context) {
 		logger.Fatal(err.Error())
 	}
 
-	logger.Debug("Begin to initialize Node manager")
-	nodeManager, err := nodemanager.NewNodeManager(controllerContext.CRDManager.GetClient())
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	controllerContext.NodeManager = nodeManager
-
-	logger.Debug("Begin to initialize Namespace manager")
-	nsManager, err := namespacemanager.NewNamespaceManager(controllerContext.CRDManager.GetClient())
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	controllerContext.NSManager = nsManager
-
-	logger.Info("Begin to initialize Pod Manager")
-	podManager, err := podmanager.NewPodManager(&podmanager.PodManagerConfig{
-		UpdateCRConfig: updateCRConfig,
-	}, controllerContext.CRDManager.GetClient())
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	controllerContext.PodManager = podManager
-
-	logger.Info("Begin to initialize StatefulSet Manager")
-	statefulSetManager, err := statefulsetmanager.NewStatefulSetManager(controllerContext.CRDManager)
-	if err != nil {
-		logger.Fatal(err.Error())
-	}
-	controllerContext.StsManager = statefulSetManager
-
 	logger.Info("Begin to initialize IPPool Manager")
 	ipPoolManager, err := ippoolmanager.NewIPPoolManager(&ippoolmanager.IPPoolManagerConfig{
 		EnableIPv4:                    controllerContext.Cfg.EnableIPv4,
@@ -292,7 +293,7 @@ func initControllerServiceManagers(ctx context.Context) {
 		WorkQueueRequeueDelayDuration: time.Duration(controllerContext.Cfg.WorkQueueRequeueDelayDuration) * time.Second,
 		WorkerNum:                     controllerContext.Cfg.IPPoolInformerWorkers,
 		WorkQueueMaxRetries:           controllerContext.Cfg.WorkQueueMaxRetries,
-	}, controllerContext.CRDManager, controllerContext.RIPManager)
+	}, controllerContext.CRDManager, controllerContext.PodManager, controllerContext.RIPManager)
 	if err != nil {
 		logger.Fatal(err.Error())
 	}
diff --git a/pkg/constant/k8s.go b/pkg/constant/k8s.go
index fd096cf44..0d417a364 100644
--- a/pkg/constant/k8s.go
+++ b/pkg/constant/k8s.go
@@ -48,6 +48,7 @@ const (
 	PodFailed       types.PodStatus = "Failed"
 	PodEvicted      types.PodStatus = "Evicted"
 	PodDeleted      types.PodStatus = "Deleted"
+	PodUnknown      types.PodStatus = "Unknown"
 )
 
 const (
diff --git a/pkg/gcmanager/pod_cache.go b/pkg/gcmanager/pod_cache.go
index 1bce6a029..5cd07c68b 100644
--- a/pkg/gcmanager/pod_cache.go
+++ b/pkg/gcmanager/pod_cache.go
@@ -135,13 +135,14 @@ func (s *SpiderGC) buildPodEntry(oldPod, currentPod *corev1.Pod, deleted bool) (
 		return nil, fmt.Errorf("currentPod must be specified")
 	}
 
-	ownerControllerType, _ := podmanager.GetOwnerControllerType(currentPod)
+	// TODO(Icarus9913): Replace with method GetPodTopController.
+	ownerRef := metav1.GetControllerOf(currentPod)
 
 	// deleted pod
 	if deleted {
 		// check StatefulSet pod, we will trace it if its controller StatefulSet object was deleted or decreased its replicas and the pod index was out of the replicas.
-		if s.gcConfig.EnableStatefulSet && ownerControllerType == constant.OwnerStatefulSet {
-			isValidStsPod, err := s.stsMgr.IsValidStatefulSetPod(context.TODO(), currentPod.Namespace, currentPod.Name, ownerControllerType)
+		if s.gcConfig.EnableStatefulSet && ownerRef != nil && ownerRef.Kind == constant.OwnerStatefulSet {
+			isValidStsPod, err := s.stsMgr.IsValidStatefulSetPod(context.TODO(), currentPod.Namespace, currentPod.Name, ownerRef.Kind)
 			if nil != err {
 				return nil, err
 			}
@@ -167,7 +168,7 @@ func (s *SpiderGC) buildPodEntry(oldPod, currentPod *corev1.Pod, deleted bool) (
 		return podEntry, nil
 	} else {
 		// no need to trace Terminating StatefulSet pod.
-		if ownerControllerType == constant.OwnerStatefulSet {
+		if ownerRef != nil && ownerRef.Kind == constant.OwnerStatefulSet {
 			return nil, nil
 		}
 
diff --git a/pkg/ipam/ipam.go b/pkg/ipam/ipam.go
index 7a3b1422b..5a9b720b7 100644
--- a/pkg/ipam/ipam.go
+++ b/pkg/ipam/ipam.go
@@ -108,11 +108,14 @@ func (i *ipam) Allocate(ctx context.Context, addArgs *models.IpamAddArgs) (*mode
 		return nil, fmt.Errorf("failed to get Endpoint %s/%s: %v", *addArgs.PodNamespace, *addArgs.PodName, err)
 	}
 
-	ownerControllerType, ownerControllerName := podmanager.GetOwnerControllerType(pod)
-	if i.config.EnableStatefulSet && ownerControllerType == constant.OwnerStatefulSet {
+	ownerKind, owner, err := i.podManager.GetPodTopController(ctx, pod)
+	if err != nil {
+		return nil, err
+	}
+	if i.config.EnableStatefulSet && ownerKind == constant.OwnerStatefulSet {
 		addResp, err := i.retrieveStsIPAllocation(ctx, *addArgs.ContainerID, *addArgs.IfName, pod, endpoint)
 		if err != nil {
-			return nil, fmt.Errorf("failed to retrieve the IP allocation of StatefulSet %s/%s: %w", *addArgs.PodNamespace, ownerControllerName, err)
+			return nil, fmt.Errorf("failed to retrieve the IP allocation of StatefulSet %s/%s: %w", *addArgs.PodNamespace, owner.GetName(), err)
 		}
 		if addResp != nil {
 			return addResp, nil
diff --git a/pkg/ippoolmanager/ippool_manager.go b/pkg/ippoolmanager/ippool_manager.go
index 1729dac10..f8f122389 100644
--- a/pkg/ippoolmanager/ippool_manager.go
+++ b/pkg/ippoolmanager/ippool_manager.go
@@ -40,6 +40,7 @@ type ipPoolManager struct {
 	freeIPsLimiter limiter.Limiter
 	client         client.Client
 	runtimeMgr     ctrl.Manager
+	podManager     podmanager.PodManager
 	rIPManager     reservedipmanager.ReservedIPManager
 	subnetManager  subnetmanagertypes.SubnetManager
 
@@ -53,13 +54,16 @@ type ipPoolManager struct {
 	v6AutoCreatedRateLimitQueue workqueue.RateLimitingInterface
 }
 
-func NewIPPoolManager(c *IPPoolManagerConfig, mgr ctrl.Manager, rIPManager reservedipmanager.ReservedIPManager) (ippoolmanagertypes.IPPoolManager, error) {
+func NewIPPoolManager(c *IPPoolManagerConfig, mgr ctrl.Manager, podManager podmanager.PodManager, rIPManager reservedipmanager.ReservedIPManager) (ippoolmanagertypes.IPPoolManager, error) {
 	if c == nil {
 		return nil, errors.New("ippool manager config must be specified")
 	}
 	if mgr == nil {
 		return nil, errors.New("k8s manager must be specified")
 	}
+	if podManager == nil {
+		return nil, errors.New("pod manager must be specified")
+	}
 	if rIPManager == nil {
 		return nil, errors.New("reserved IP manager must be specified")
 	}
@@ -76,6 +80,7 @@ func NewIPPoolManager(c *IPPoolManagerConfig, mgr ctrl.Manager, rIPManager reser
 		freeIPsLimiter: freeIPsLimiter,
 		client:         mgr.GetClient(),
 		runtimeMgr:     mgr,
+		podManager:     podManager,
 		rIPManager:     rIPManager,
 	}
 
@@ -131,16 +136,22 @@ func (im *ipPoolManager) AllocateIP(ctx context.Context, poolName, containerID,
 			ipPool.Status.AllocatedIPs = spiderpoolv1.PoolIPAllocations{}
 		}
 
-		ownerControllerType, ownerControllerName := podmanager.GetOwnerControllerType(pod)
-		ipPool.Status.AllocatedIPs[allocatedIP.String()] = spiderpoolv1.PoolIPAllocation{
+		ownerKind, owner, err := im.podManager.GetPodTopController(ctx, pod)
+		if err != nil {
+			return nil, nil, err
+		}
+		allocation := spiderpoolv1.PoolIPAllocation{
 			ContainerID:         containerID,
 			NIC:                 nic,
 			Node:                pod.Spec.NodeName,
 			Namespace:           pod.Namespace,
 			Pod:                 pod.Name,
-			OwnerControllerType: ownerControllerType,
-			OwnerControllerName: ownerControllerName,
+			OwnerControllerType: ownerKind,
+		}
+		if owner != nil {
+			allocation.OwnerControllerName = owner.GetName()
 		}
+		ipPool.Status.AllocatedIPs[allocatedIP.String()] = allocation
 
 		if ipPool.Status.AllocatedIPCount == nil {
 			ipPool.Status.AllocatedIPCount = new(int64)
diff --git a/pkg/limiter/config.go b/pkg/limiter/config.go
index 58d5768c7..d967fdd91 100644
--- a/pkg/limiter/config.go
+++ b/pkg/limiter/config.go
@@ -16,12 +16,13 @@ type LimiterConfig struct {
 }
 
 func setDefaultsForLimiterConfig(config LimiterConfig) LimiterConfig {
-	maxQueueSize, maxWaitTime := defaultMaxQueueSize, defaultMaxWaitTime
 	if config.MaxQueueSize == nil {
+		maxQueueSize := defaultMaxQueueSize
 		config.MaxQueueSize = &maxQueueSize
 	}
 
 	if config.MaxWaitTime == nil {
+		maxWaitTime := defaultMaxWaitTime
 		config.MaxWaitTime = &maxWaitTime
 	}
 
diff --git a/pkg/podmanager/config.go b/pkg/podmanager/config.go
index 02e583bbe..bda487f41 100644
--- a/pkg/podmanager/config.go
+++ b/pkg/podmanager/config.go
@@ -3,8 +3,15 @@
 
 package podmanager
 
-import "github.com/spidernet-io/spiderpool/pkg/config"
+import (
+	"time"
+)
 
 type PodManagerConfig struct {
-	config.UpdateCRConfig
+	MaxConflictRetries    int
+	ConflictRetryUnitTime time.Duration
+}
+
+func setDefaultsForPodManagerConfig(config PodManagerConfig) PodManagerConfig {
+	return config
 }
diff --git a/pkg/podmanager/pod_manager.go b/pkg/podmanager/pod_manager.go
index d62b8632c..be40bec4f 100644
--- a/pkg/podmanager/pod_manager.go
+++ b/pkg/podmanager/pod_manager.go
@@ -5,7 +5,6 @@ package podmanager
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math/rand"
 	"time"
@@ -25,26 +24,23 @@ import (
 type PodManager interface {
 	GetPodByName(ctx context.Context, namespace, podName string) (*corev1.Pod, error)
 	ListPods(ctx context.Context, opts ...client.ListOption) (*corev1.PodList, error)
-	MergeAnnotations(ctx context.Context, namespace, podName string, annotations map[string]string) error
 	MatchLabelSelector(ctx context.Context, namespace, podName string, labelSelector *metav1.LabelSelector) (bool, error)
+	MergeAnnotations(ctx context.Context, namespace, podName string, annotations map[string]string) error
 	GetPodTopController(ctx context.Context, pod *corev1.Pod) (appKind string, app metav1.Object, err error)
 }
 
 type podManager struct {
-	config *PodManagerConfig
+	config PodManagerConfig
 	client client.Client
 }
 
-func NewPodManager(c *PodManagerConfig, client client.Client) (PodManager, error) {
-	if c == nil {
-		return nil, errors.New("pod manager config must be specified")
-	}
+func NewPodManager(config PodManagerConfig, client client.Client) (PodManager, error) {
 	if client == nil {
-		return nil, errors.New("k8s client must be specified")
+		return nil, fmt.Errorf("k8s client %w", constant.ErrMissingRequiredParam)
 	}
 
 	return &podManager{
-		config: c,
+		config: setDefaultsForPodManagerConfig(config),
 		client: client,
 	}, nil
 }
@@ -67,6 +63,29 @@ func (pm *podManager) ListPods(ctx context.Context, opts ...client.ListOption) (
 	return &podList, nil
 }
 
+func (pm *podManager) MatchLabelSelector(ctx context.Context, namespace, podName string, labelSelector *metav1.LabelSelector) (bool, error) {
+	selector, err := metav1.LabelSelectorAsSelector(labelSelector)
+	if err != nil {
+		return false, err
+	}
+
+	podList, err := pm.ListPods(
+		ctx,
+		client.InNamespace(namespace),
+		client.MatchingLabelsSelector{Selector: selector},
+		client.MatchingFields{metav1.ObjectNameField: podName},
+	)
+	if err != nil {
+		return false, err
+	}
+
+	if len(podList.Items) == 0 {
+		return false, nil
+	}
+
+	return true, nil
+}
+
 func (pm *podManager) MergeAnnotations(ctx context.Context, namespace, podName string, annotations map[string]string) error {
 	rand.Seed(time.Now().UnixNano())
 	for i := 0; i <= pm.config.MaxConflictRetries; i++ {
@@ -75,6 +94,10 @@ func (pm *podManager) MergeAnnotations(ctx context.Context, namespace, podName s
 			return err
 		}
 
+		if len(annotations) == 0 {
+			return nil
+		}
+
 		if pod.Annotations == nil {
 			pod.Annotations = map[string]string{}
 		}
@@ -87,7 +110,7 @@ func (pm *podManager) MergeAnnotations(ctx context.Context, namespace, podName s
 				return err
 			}
 			if i == pm.config.MaxConflictRetries {
-				return fmt.Errorf("%w, failed for %d times, failed to merge Pod annotations", constant.ErrRetriesExhausted, pm.config.MaxConflictRetries)
+				return fmt.Errorf("%w (%d times), failed to merge Pod annotations", constant.ErrRetriesExhausted, pm.config.MaxConflictRetries)
 			}
 			time.Sleep(time.Duration(rand.Intn(1<<(i+1))) * pm.config.ConflictRetryUnitTime)
 			continue
@@ -98,29 +121,6 @@ func (pm *podManager) MergeAnnotations(ctx context.Context, namespace, podName s
 	return nil
 }
 
-func (pm *podManager) MatchLabelSelector(ctx context.Context, namespace, podName string, labelSelector *metav1.LabelSelector) (bool, error) {
-	selector, err := metav1.LabelSelectorAsSelector(labelSelector)
-	if err != nil {
-		return false, err
-	}
-
-	podList, err := pm.ListPods(
-		ctx,
-		client.InNamespace(namespace),
-		client.MatchingLabelsSelector{Selector: selector},
-		client.MatchingFields{metav1.ObjectNameField: podName},
-	)
-	if err != nil {
-		return false, err
-	}
-
-	if len(podList.Items) == 0 {
-		return false, nil
-	}
-
-	return true, nil
-}
-
 // GetPodTopController will find the pod top owner controller with the given pod.
 // For example, once we create a deployment then it will create replicaset and the replicaset will create pods.
 // So, the pods' top owner is deployment. That's what the method implements.
diff --git a/pkg/podmanager/utils.go b/pkg/podmanager/utils.go
index 63e7de600..f9ead676e 100644
--- a/pkg/podmanager/utils.go
+++ b/pkg/podmanager/utils.go
@@ -7,38 +7,16 @@ import (
 	"time"
 
 	corev1 "k8s.io/api/core/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
 	"github.com/spidernet-io/spiderpool/pkg/types"
 )
 
-func GetOwnerControllerType(pod *corev1.Pod) (string, string) {
-	owner := metav1.GetControllerOf(pod)
-	if owner == nil {
-		return constant.OwnerNone, ""
+func CheckPodStatus(pod *corev1.Pod) (status types.PodStatus, allocatable bool) {
+	if pod == nil {
+		return constant.PodUnknown, false
 	}
 
-	var ownerType string
-	switch owner.Kind {
-	case constant.OwnerDeployment:
-		ownerType = constant.OwnerDeployment
-	case constant.OwnerStatefulSet:
-		ownerType = constant.OwnerStatefulSet
-	case constant.OwnerDaemonSet:
-		ownerType = constant.OwnerDaemonSet
-	case constant.OwnerReplicaSet:
-		ownerType = constant.OwnerReplicaSet
-	case constant.OwnerJob:
-		ownerType = constant.OwnerJob
-	default:
-		ownerType = constant.OwnerUnknown
-	}
-
-	return ownerType, owner.Name
-}
-
-func CheckPodStatus(pod *corev1.Pod) (podStatue types.PodStatus, isAllocatable bool) {
 	// TODO (Icarus9913): no pending phase?
 	if pod.DeletionTimestamp != nil && pod.DeletionGracePeriodSeconds != nil {
 		now := time.Now()
diff --git a/pkg/workloadendpointmanager/workloadendpoint_manager.go b/pkg/workloadendpointmanager/workloadendpoint_manager.go
index 549e966f3..32b9b238d 100644
--- a/pkg/workloadendpointmanager/workloadendpoint_manager.go
+++ b/pkg/workloadendpointmanager/workloadendpoint_manager.go
@@ -43,20 +43,25 @@ type workloadEndpointManager struct {
 	config     *EndpointManagerConfig
 	client     client.Client
 	runtimeMgr ctrl.Manager
+	podManager podmanager.PodManager
 }
 
-func NewWorkloadEndpointManager(c *EndpointManagerConfig, mgr ctrl.Manager) (WorkloadEndpointManager, error) {
+func NewWorkloadEndpointManager(c *EndpointManagerConfig, mgr ctrl.Manager, podManager podmanager.PodManager) (WorkloadEndpointManager, error) {
 	if c == nil {
 		return nil, errors.New("endpoint manager config must be specified")
 	}
 	if mgr == nil {
 		return nil, errors.New("k8s manager must be specified")
 	}
+	if podManager == nil {
+		return nil, errors.New("pod manager must be specified")
+	}
 
 	return &workloadEndpointManager{
 		config:     c,
 		client:     mgr.GetClient(),
 		runtimeMgr: mgr,
+		podManager: podManager,
 	}, nil
 }
 
@@ -95,17 +100,20 @@ func (em *workloadEndpointManager) MarkIPAllocation(ctx context.Context, contain
 			},
 		}
 
-		controllerutil.AddFinalizer(newWE, constant.SpiderFinalizer)
-		ownerControllerType, ownerControllerName := podmanager.GetOwnerControllerType(pod)
+		ownerKind, owner, err := em.podManager.GetPodTopController(ctx, pod)
+		if err != nil {
+			return nil, err
+		}
 
 		// We don't set ownerReference for Endpoint when the pod belongs to StatefulSet
 		// Once the StatefulSet pod restarts, we can retrieve the corresponding data immediately.
 		// And we don't need to wait the corresponding Endpoint clean up to create a new one if ownerReference exists.
-		if ownerControllerType != constant.OwnerStatefulSet {
+		if ownerKind != constant.OwnerStatefulSet {
 			if err := controllerutil.SetOwnerReference(pod, newWE, em.runtimeMgr.GetScheme()); err != nil {
 				return nil, err
 			}
 		}
+		controllerutil.AddFinalizer(newWE, constant.SpiderFinalizer)
 
 		if err := em.client.Create(ctx, newWE); err != nil {
 			return nil, err
@@ -113,8 +121,10 @@ func (em *workloadEndpointManager) MarkIPAllocation(ctx context.Context, contain
 
 		newWE.Status.Current = allocation
 		newWE.Status.History = []spiderpoolv1.PodIPAllocation{*allocation}
-		newWE.Status.OwnerControllerType = ownerControllerType
-		newWE.Status.OwnerControllerName = ownerControllerName
+		newWE.Status.OwnerControllerType = ownerKind
+		if owner != nil {
+			newWE.Status.OwnerControllerName = owner.GetName()
+		}
 		if err := em.client.Status().Update(ctx, newWE); err != nil {
 			return nil, err
 		}


Test patch:
diff --git a/pkg/namespacemanager/namespace_manager_suite_test.go b/pkg/namespacemanager/namespace_manager_suite_test.go
index 36b4baf80..cb4002a77 100644
--- a/pkg/namespacemanager/namespace_manager_suite_test.go
+++ b/pkg/namespacemanager/namespace_manager_suite_test.go
@@ -16,15 +16,15 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/namespacemanager"
 )
 
+var scheme *runtime.Scheme
+var fakeClient client.Client
+var nsManager namespacemanager.NamespaceManager
+
 func TestNamespaceManager(t *testing.T) {
 	RegisterFailHandler(Fail)
 	RunSpecs(t, "NamespaceManager Suite", Label("namespacemanager", "unitest"))
 }
 
-var scheme *runtime.Scheme
-var fakeClient client.Client
-var nsManager namespacemanager.NamespaceManager
-
 var _ = BeforeSuite(func() {
 	scheme = runtime.NewScheme()
 	err := corev1.AddToScheme(scheme)
diff --git a/pkg/namespacemanager/namespace_manager_test.go b/pkg/namespacemanager/namespace_manager_test.go
index a20c24e3c..57398c2c1 100644
--- a/pkg/namespacemanager/namespace_manager_test.go
+++ b/pkg/namespacemanager/namespace_manager_test.go
@@ -14,6 +14,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -55,10 +56,9 @@ var _ = Describe("NamespaceManager", Label("namespace_manager_test"), func() {
 		var deleteOption *client.DeleteOptions
 
 		AfterEach(func() {
-			zero := int64(0)
 			policy := metav1.DeletePropagationForeground
 			deleteOption = &client.DeleteOptions{
-				GracePeriodSeconds: &zero,
+				GracePeriodSeconds: pointer.Int64(0),
 				PropagationPolicy:  &policy,
 			}
 
@@ -161,19 +161,6 @@ var _ = Describe("NamespaceManager", Label("namespace_manager_test"), func() {
 		})
 
 		Describe("MatchLabelSelector", func() {
-			It("failed to list Namespace due to some unknown errors", func() {
-				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
-				defer patches.Reset()
-
-				ctx := context.TODO()
-				err := fakeClient.Create(ctx, nsT)
-				Expect(err).NotTo(HaveOccurred())
-
-				match, err := nsManager.MatchLabelSelector(ctx, nsName, &metav1.LabelSelector{MatchLabels: labels})
-				Expect(err).To(MatchError(constant.ErrUnknown))
-				Expect(match).To(BeFalse())
-			})
-
 			It("checks non-existent Namespace", func() {
 				ctx := context.TODO()
 				match, err := nsManager.MatchLabelSelector(ctx, nsName, &metav1.LabelSelector{MatchLabels: labels})
@@ -196,6 +183,19 @@ var _ = Describe("NamespaceManager", Label("namespace_manager_test"), func() {
 				Expect(match).To(BeFalse())
 			})
 
+			It("failed to list Namespace due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, nsT)
+				Expect(err).NotTo(HaveOccurred())
+
+				match, err := nsManager.MatchLabelSelector(ctx, nsName, &metav1.LabelSelector{MatchLabels: labels})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(match).To(BeFalse())
+			})
+
 			It("matches nothing", func() {
 				ctx := context.TODO()
 				err := fakeClient.Create(ctx, nsT)
diff --git a/pkg/nodemanager/node_manager_suite_test.go b/pkg/nodemanager/node_manager_suite_test.go
index b213fe612..a0c443b19 100644
--- a/pkg/nodemanager/node_manager_suite_test.go
+++ b/pkg/nodemanager/node_manager_suite_test.go
@@ -16,15 +16,15 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/nodemanager"
 )
 
+var scheme *runtime.Scheme
+var fakeClient client.Client
+var nodeManager nodemanager.NodeManager
+
 func TestNodeManager(t *testing.T) {
 	RegisterFailHandler(Fail)
 	RunSpecs(t, "NodeManager Suite", Label("nodemanager", "unitest"))
 }
 
-var scheme *runtime.Scheme
-var fakeClient client.Client
-var nodeManager nodemanager.NodeManager
-
 var _ = BeforeSuite(func() {
 	scheme = runtime.NewScheme()
 	err := corev1.AddToScheme(scheme)
diff --git a/pkg/nodemanager/node_manager_test.go b/pkg/nodemanager/node_manager_test.go
index 2097090a1..e913fae70 100644
--- a/pkg/nodemanager/node_manager_test.go
+++ b/pkg/nodemanager/node_manager_test.go
@@ -14,6 +14,7 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -55,10 +56,9 @@ var _ = Describe("NodeManager", Label("node_manager_test"), func() {
 		var deleteOption *client.DeleteOptions
 
 		AfterEach(func() {
-			zero := int64(0)
 			policy := metav1.DeletePropagationForeground
 			deleteOption = &client.DeleteOptions{
-				GracePeriodSeconds: &zero,
+				GracePeriodSeconds: pointer.Int64(0),
 				PropagationPolicy:  &policy,
 			}
 
@@ -161,19 +161,6 @@ var _ = Describe("NodeManager", Label("node_manager_test"), func() {
 		})
 
 		Describe("MatchLabelSelector", func() {
-			It("failed to list Nodes due to some unknown errors", func() {
-				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
-				defer patches.Reset()
-
-				ctx := context.TODO()
-				err := fakeClient.Create(ctx, nodeT)
-				Expect(err).NotTo(HaveOccurred())
-
-				match, err := nodeManager.MatchLabelSelector(ctx, nodeName, &metav1.LabelSelector{MatchLabels: labels})
-				Expect(err).To(MatchError(constant.ErrUnknown))
-				Expect(match).To(BeFalse())
-			})
-
 			It("checks non-existent Node", func() {
 				ctx := context.TODO()
 				match, err := nodeManager.MatchLabelSelector(ctx, nodeName, &metav1.LabelSelector{MatchLabels: labels})
@@ -196,6 +183,19 @@ var _ = Describe("NodeManager", Label("node_manager_test"), func() {
 				Expect(match).To(BeFalse())
 			})
 
+			It("failed to list Nodes due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, nodeT)
+				Expect(err).NotTo(HaveOccurred())
+
+				match, err := nodeManager.MatchLabelSelector(ctx, nodeName, &metav1.LabelSelector{MatchLabels: labels})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(match).To(BeFalse())
+			})
+
 			It("matches nothing", func() {
 				ctx := context.TODO()
 				err := fakeClient.Create(ctx, nodeT)
diff --git a/pkg/podmanager/pod_manager_suite_test.go b/pkg/podmanager/pod_manager_suite_test.go
new file mode 100644
index 000000000..63c43baab
--- /dev/null
+++ b/pkg/podmanager/pod_manager_suite_test.go
@@ -0,0 +1,42 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package podmanager_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	"github.com/spidernet-io/spiderpool/pkg/podmanager"
+)
+
+var scheme *runtime.Scheme
+var fakeClient client.Client
+var podManager podmanager.PodManager
+
+func TestPodManager(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "PodManager Suite", Label("podmanager", "unitest"))
+}
+
+var _ = BeforeSuite(func() {
+	scheme = runtime.NewScheme()
+	err := corev1.AddToScheme(scheme)
+	Expect(err).NotTo(HaveOccurred())
+
+	fakeClient = fake.NewClientBuilder().
+		WithScheme(scheme).
+		Build()
+
+	podManager, err = podmanager.NewPodManager(
+		podmanager.PodManagerConfig{MaxConflictRetries: 1},
+		fakeClient,
+	)
+	Expect(err).NotTo(HaveOccurred())
+})
diff --git a/pkg/podmanager/pod_manager_test.go b/pkg/podmanager/pod_manager_test.go
index 670b56ba5..be8415e72 100644
--- a/pkg/podmanager/pod_manager_test.go
+++ b/pkg/podmanager/pod_manager_test.go
@@ -4,9 +4,324 @@
 package podmanager_test
 
 import (
+	"context"
+	"fmt"
+	"sync/atomic"
+
+	"github.com/agiledragon/gomonkey/v2"
 	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	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"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	"github.com/spidernet-io/spiderpool/pkg/podmanager"
 )
 
-var _ = Describe("Podmanager", Label("unittest", "podmanager_test"), func() {
+var _ = Describe("PodManager", Label("pod_manager_test"), func() {
+	Describe("New PodManager", func() {
+		It("sets default config", func() {
+			manager, err := podmanager.NewPodManager(podmanager.PodManagerConfig{}, fakeClient)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(manager).NotTo(BeNil())
+		})
+
+		It("inputs nil client", func() {
+			manager, err := podmanager.NewPodManager(podmanager.PodManagerConfig{}, nil)
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+	})
+
+	Describe("Test PodManager's method", func() {
+		var count uint64
+		var namespace string
+		var podName string
+		var labels map[string]string
+		var podT *corev1.Pod
+
+		BeforeEach(func() {
+			atomic.AddUint64(&count, 1)
+			namespace = "default"
+			podName = fmt.Sprintf("pod-%v", count)
+			labels = map[string]string{"foo": fmt.Sprintf("bar-%v", count)}
+			podT = &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      podName,
+					Namespace: namespace,
+					Labels:    labels,
+				},
+				Spec: corev1.PodSpec{},
+			}
+		})
+
+		var deleteOption *client.DeleteOptions
+
+		AfterEach(func() {
+			policy := metav1.DeletePropagationForeground
+			deleteOption = &client.DeleteOptions{
+				GracePeriodSeconds: pointer.Int64(0),
+				PropagationPolicy:  &policy,
+			}
+
+			ctx := context.TODO()
+			err := fakeClient.Delete(ctx, podT, deleteOption)
+			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+		})
+
+		Describe("GetPodByName", func() {
+			It("gets non-existent Pod", func() {
+				ctx := context.TODO()
+				pod, err := podManager.GetPodByName(ctx, namespace, podName)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+				Expect(pod).To(BeNil())
+			})
+
+			It("gets an existing Pod", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				pod, err := podManager.GetPodByName(ctx, namespace, podName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(pod).NotTo(BeNil())
+
+				Expect(pod).To(Equal(podT))
+			})
+		})
+
+		Describe("ListPods", func() {
+			It("failed to list Pods due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				podList, err := podManager.ListPods(ctx)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(podList).To(BeNil())
+			})
+
+			It("lists all Pods", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				podList, err := podManager.ListPods(ctx)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(podList.Items).NotTo(BeEmpty())
+
+				hasPod := false
+				for _, pod := range podList.Items {
+					if pod.Name == podName {
+						hasPod = true
+						break
+					}
+				}
+				Expect(hasPod).To(BeTrue())
+			})
+
+			It("filters results by Namespace", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				podList, err := podManager.ListPods(ctx, client.InNamespace(namespace))
+				Expect(err).NotTo(HaveOccurred())
+				Expect(podList.Items).NotTo(BeEmpty())
+
+				hasPod := false
+				for _, pod := range podList.Items {
+					if pod.Name == podName {
+						hasPod = true
+						break
+					}
+				}
+				Expect(hasPod).To(BeTrue())
+			})
+
+			It("filters results by label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				podList, err := podManager.ListPods(ctx, client.MatchingLabels(labels))
+				Expect(err).NotTo(HaveOccurred())
+				Expect(podList.Items).NotTo(BeEmpty())
+
+				hasPod := false
+				for _, pod := range podList.Items {
+					if pod.Name == podName {
+						hasPod = true
+						break
+					}
+				}
+				Expect(hasPod).To(BeTrue())
+			})
+
+			It("filters results by field selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				podList, err := podManager.ListPods(ctx, client.MatchingFields{metav1.ObjectNameField: podName})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(podList.Items).NotTo(BeEmpty())
+
+				hasPod := false
+				for _, pod := range podList.Items {
+					if pod.Name == podName {
+						hasPod = true
+						break
+					}
+				}
+				Expect(hasPod).To(BeTrue())
+			})
+		})
+
+		Describe("MatchLabelSelector", func() {
+			It("checks non-existent Pod", func() {
+				ctx := context.TODO()
+				match, err := podManager.MatchLabelSelector(ctx, namespace, podName, &metav1.LabelSelector{MatchLabels: labels})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(match).To(BeFalse())
+			})
+
+			It("matches invalid label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				invalidSelector := &metav1.LabelSelector{
+					MatchLabels: map[string]string{
+						"": "",
+					},
+				}
+				match, err := podManager.MatchLabelSelector(ctx, namespace, podName, invalidSelector)
+				Expect(err).To(HaveOccurred())
+				Expect(match).To(BeFalse())
+			})
+
+			It("failed to list Pods due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				match, err := podManager.MatchLabelSelector(ctx, namespace, podName, &metav1.LabelSelector{MatchLabels: labels})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(match).To(BeFalse())
+			})
+
+			It("matches nothing", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				match, err := podManager.MatchLabelSelector(ctx, namespace, podName, nil)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(match).To(BeFalse())
+			})
+
+			It("matches the label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				match, err := podManager.MatchLabelSelector(ctx, namespace, podName, &metav1.LabelSelector{MatchLabels: labels})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(match).To(BeTrue())
+			})
+		})
+
+		Describe("MergeAnnotations", func() {
+			It("merges annotations to non-existent Pod", func() {
+				ctx := context.TODO()
+				anno := map[string]string{"foo": "bar"}
+				err := podManager.MergeAnnotations(ctx, namespace, podName, anno)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+			})
+
+			It("merges empty annotations", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = podManager.MergeAnnotations(ctx, namespace, podName, nil)
+				Expect(err).NotTo(HaveOccurred())
+			})
+
+			It("failed to update Pod due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Update", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				anno := map[string]string{"foo": "bar"}
+				err = podManager.MergeAnnotations(ctx, namespace, podName, anno)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
+			It("runs out of retries to update Pod, but conflicts still occur", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Update", apierrors.NewConflict(schema.GroupResource{Resource: "test"}, "other", nil))
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				anno := map[string]string{"foo": "bar"}
+				err = podManager.MergeAnnotations(ctx, namespace, podName, anno)
+				Expect(err).To(MatchError(constant.ErrRetriesExhausted))
+			})
+
+			It("merges annotations to Pod", func() {
+				podT.SetAnnotations(map[string]string{
+					"foo":   "merge",
+					"exist": "value",
+				})
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, podT)
+				Expect(err).NotTo(HaveOccurred())
+
+				anno := map[string]string{
+					"foo": "bar",
+					"new": "value",
+				}
+				err = podManager.MergeAnnotations(ctx, namespace, podName, anno)
+				Expect(err).NotTo(HaveOccurred())
+
+				var pod corev1.Pod
+				err = fakeClient.Get(ctx, types.NamespacedName{Namespace: namespace, Name: podName}, &pod)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(pod.GetAnnotations()).To(Equal(
+					map[string]string{
+						"foo":   "bar",
+						"exist": "value",
+						"new":   "value",
+					},
+				))
+			})
+		})
+
+		PDescribe("GetPodTopController", func() {
 
+		})
+	})
 })
diff --git a/pkg/podmanager/podmanager_suite_test.go b/pkg/podmanager/podmanager_suite_test.go
deleted file mode 100644
index 358671c19..000000000
--- a/pkg/podmanager/podmanager_suite_test.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package podmanager_test
-
-import (
-	"testing"
-
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-)
-
-func TestPodmanager(t *testing.T) {
-	RegisterFailHandler(Fail)
-	RunSpecs(t, "Podmanager Suite")
-}
diff --git a/pkg/podmanager/utils_test.go b/pkg/podmanager/utils_test.go
new file mode 100644
index 000000000..c796f728a
--- /dev/null
+++ b/pkg/podmanager/utils_test.go
@@ -0,0 +1,95 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package podmanager_test
+
+import (
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/pointer"
+
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	"github.com/spidernet-io/spiderpool/pkg/podmanager"
+)
+
+var _ = Describe("PodManager utils", Label("pod_manager_utils_test"), func() {
+	Describe("Test CheckPodStatus", func() {
+		var podT *corev1.Pod
+
+		BeforeEach(func() {
+			podT = &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "pod",
+					Namespace: "default",
+				},
+				Spec:   corev1.PodSpec{},
+				Status: corev1.PodStatus{},
+			}
+		})
+
+		It("inputs nil Pod", func() {
+			status, allocatable := podmanager.CheckPodStatus(nil)
+			Expect(status).To(Equal(constant.PodUnknown))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks terminated Pod", func() {
+			now := metav1.Now()
+			podT.DeletionTimestamp = &now
+			podT.DeletionGracePeriodSeconds = pointer.Int64(0)
+
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodGraceTimeout))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks terminating Pod", func() {
+			now := metav1.Now()
+			podT.DeletionTimestamp = &now
+			podT.DeletionGracePeriodSeconds = pointer.Int64(30)
+
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodTerminating))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks succeeded Pod", func() {
+			podT.Status.Phase = corev1.PodSucceeded
+			podT.Spec.RestartPolicy = corev1.RestartPolicyNever
+
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodSucceeded))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks failed Pod", func() {
+			podT.Status.Phase = corev1.PodFailed
+			podT.Spec.RestartPolicy = corev1.RestartPolicyNever
+
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodFailed))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks evicted Pod", func() {
+			podT.Status.Phase = corev1.PodFailed
+			podT.Status.Reason = "Evicted"
+
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodEvicted))
+			Expect(allocatable).To(BeFalse())
+		})
+
+		It("checks running Pod", func() {
+			status, allocatable := podmanager.CheckPodStatus(podT)
+			Expect(status).To(Equal(constant.PodRunning))
+			Expect(allocatable).To(BeTrue())
+		})
+	})
+})
diff --git a/pkg/reservedipmanager/reservedip_manager_test.go b/pkg/reservedipmanager/reservedip_manager_test.go
index cee7ec11d..f2a4f8d1f 100644
--- a/pkg/reservedipmanager/reservedip_manager_test.go
+++ b/pkg/reservedipmanager/reservedip_manager_test.go
@@ -13,6 +13,7 @@ import (
 	. "github.com/onsi/gomega"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/spidernet-io/spiderpool/pkg/constant"
@@ -55,10 +56,9 @@ var _ = Describe("ReservedIPManager", Label("reservedip_manager_test"), func() {
 		var deleteOption *client.DeleteOptions
 
 		AfterEach(func() {
-			zero := int64(0)
 			policy := metav1.DeletePropagationForeground
 			deleteOption = &client.DeleteOptions{
-				GracePeriodSeconds: &zero,
+				GracePeriodSeconds: pointer.Int64(0),
 				PropagationPolicy:  &policy,
 			}
 
diff --git a/pkg/reservedipmanager/reservedip_webhook_test.go b/pkg/reservedipmanager/reservedip_webhook_test.go
index 93cc656a4..b0dd4a4e1 100644
--- a/pkg/reservedipmanager/reservedip_webhook_test.go
+++ b/pkg/reservedipmanager/reservedip_webhook_test.go
@@ -243,39 +243,39 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("failed to list ReservedIPs due to some unknown errors", func() {
-					mockRIPManager.EXPECT().
-						ListReservedIPs(gomock.All()).
-						Return(nil, constant.ErrUnknown).
-						Times(1)
-
+				It("inputs empty 'spec.ips'", func() {
 					ipVersion := constant.IPv4
 					rIPT.Spec.IPVersion = &ipVersion
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs,
-						[]string{
-							"172.18.40.1-172.18.40.2",
-							"172.18.40.10",
-						}...,
-					)
 
 					ctx := context.TODO()
 					err := rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(err).To(HaveOccurred())
+					Expect(err).NotTo(HaveOccurred())
 				})
 
-				It("inputs empty 'spec.ips'", func() {
+				It("inputs invalid 'spec.ips'", func() {
 					ipVersion := constant.IPv4
 					rIPT.Spec.IPVersion = &ipVersion
+					rIPT.Spec.IPs = append(rIPT.Spec.IPs, constant.InvalidIPRange)
 
 					ctx := context.TODO()
 					err := rIPWebhook.ValidateCreate(ctx, rIPT)
-					Expect(err).NotTo(HaveOccurred())
+					Expect(err).To(HaveOccurred())
 				})
 
-				It("inputs invalid 'spec.ips'", func() {
+				It("failed to list ReservedIPs due to some unknown errors", func() {
+					mockRIPManager.EXPECT().
+						ListReservedIPs(gomock.All()).
+						Return(nil, constant.ErrUnknown).
+						Times(1)
+
 					ipVersion := constant.IPv4
 					rIPT.Spec.IPVersion = &ipVersion
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs, constant.InvalidIPRange)
+					rIPT.Spec.IPs = append(rIPT.Spec.IPs,
+						[]string{
+							"172.18.40.1-172.18.40.2",
+							"172.18.40.10",
+						}...,
+					)
 
 					ctx := context.TODO()
 					err := rIPWebhook.ValidateCreate(ctx, rIPT)
@@ -452,30 +452,30 @@ var _ = Describe("ReservedIPWebhook", Label("reservedip_webhook_test"), func() {
 			})
 
 			When("Validating 'spec.ips'", func() {
-				It("failed to list ReservedIPs due to some unknown errors", func() {
-					mockRIPManager.EXPECT().
-						ListReservedIPs(gomock.All()).
-						Return(nil, constant.ErrUnknown).
-						Times(1)
-
+				It("appends an invalid IP range to 'spec.ips'", func() {
 					ipVersion := constant.IPv4
 					rIPT.Spec.IPVersion = &ipVersion
-					rIPT.Spec.IPs = append(rIPT.Spec.IPs, "172.18.40.1-172.18.40.2")
 
 					newRIPT := rIPT.DeepCopy()
-					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, "172.18.40.10")
+					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, constant.InvalidIPRange)
 
 					ctx := context.TODO()
 					err := rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)
 					Expect(err).To(HaveOccurred())
 				})
 
-				It("appends an invalid IP range to 'spec.ips'", func() {
+				It("failed to list ReservedIPs due to some unknown errors", func() {
+					mockRIPManager.EXPECT().
+						ListReservedIPs(gomock.All()).
+						Return(nil, constant.ErrUnknown).
+						Times(1)
+
 					ipVersion := constant.IPv4
 					rIPT.Spec.IPVersion = &ipVersion
+					rIPT.Spec.IPs = append(rIPT.Spec.IPs, "172.18.40.1-172.18.40.2")
 
 					newRIPT := rIPT.DeepCopy()
-					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, constant.InvalidIPRange)
+					newRIPT.Spec.IPs = append(newRIPT.Spec.IPs, "172.18.40.10")
 
 					ctx := context.TODO()
 					err := rIPWebhook.ValidateUpdate(ctx, rIPT, newRIPT)