Repository: spidernet-io/spiderpool
Pull request #1343 (2023-02-20 08:40:35)

unittest: Add ippoolmanager unit tests for pkg ippoolmanager
**make sure your commit is signed off**
Signed-off-by: ty-dc [tao.yang@daocloud.io](mailto:tao.yang@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=1343)

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


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=1343)

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


codecov[bot]: # [Codecov](https://codecov.io/gh/spidernet-io/spiderpool/pull/1343?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) Report
> Merging [#1343](https://codecov.io/gh/spidernet-io/spiderpool/pull/1343?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (7899580) into [main](https://codecov.io/gh/spidernet-io/spiderpool/commit/ba4112907fd0a788984698a0b8df4e82877576ab?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) (ba41129) will **increase** coverage by `0.53%`.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/spidernet-io/spiderpool/pull/1343/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/1343?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    #1343      +/-   ##
==========================================
+ Coverage   52.60%   53.14%   +0.53%     
==========================================
  Files          44       44              
  Lines        4456     4456              
==========================================
+ Hits         2344     2368      +24     
+ Misses       2088     2064      -24     
  Partials       24       24              
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `53.14% <ø> (+0.53%)` | :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/1343?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io) | Coverage Δ | |
|---|---|---|
| [pkg/ippoolmanager/ippool\_manager.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1343?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2lwcG9vbG1hbmFnZXIvaXBwb29sX21hbmFnZXIuZ28=) | `8.86% <0.00%> (+8.86%)` | :arrow_up: |
| [pkg/ippoolmanager/config.go](https://codecov.io/gh/spidernet-io/spiderpool/pull/1343?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=spidernet-io#diff-cGtnL2lwcG9vbG1hbmFnZXIvY29uZmlnLmdv) | `100.00% <0.00%> (+100.00%)` | :arrow_up: |

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=1343)

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


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=1343)

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


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=1343)

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

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

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

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

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

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

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

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

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

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



Patch:
diff --git a/go.mod b/go.mod
index 246f4c74c..b85bff0ba 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
 	github.com/go-openapi/validate v0.22.1
 	github.com/go-swagger/go-swagger v0.30.3
 	github.com/gogo/protobuf v1.3.2
-	github.com/google/gops v0.3.27
+	github.com/google/gops v0.3.26
 	github.com/jessevdk/go-flags v1.5.0
 	github.com/onsi/ginkgo/v2 v2.8.3
 	github.com/onsi/gomega v1.27.0
diff --git a/go.sum b/go.sum
index 873db21ae..980454d88 100644
--- a/go.sum
+++ b/go.sum
@@ -180,6 +180,7 @@ github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY=
 github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc=
 github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo=
@@ -313,8 +314,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gops v0.3.27 h1:BDdWfedShsBbeatZ820oA4DbVOC8yJ4NI8xAlDFWfgI=
-github.com/google/gops v0.3.27/go.mod h1:lYqabmfnq4Q6UumWNx96Hjup5BDAVc8zmfIy0SkNCSk=
+github.com/google/gops v0.3.26 h1:Ziyfd8sEhWVbrCIy59c1WOKodI63Jzojwm0JSZbBPS4=
+github.com/google/gops v0.3.26/go.mod h1:vZ68aOXu2zJoybPyGpaHMmrCyd51DCxJoex4cO3ht/o=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
 github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@@ -408,6 +409,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
 github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -488,6 +490,7 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
@@ -529,6 +532,7 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
 github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
+github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk=
 github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
 github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -561,6 +565,7 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -570,10 +575,13 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI=
 github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs=
 github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
+github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
 github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ=
 github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -581,12 +589,14 @@ github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+
 github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
 github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
+github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
 go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng=
 go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
@@ -778,6 +788,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -804,6 +815,7 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1172,6 +1184,7 @@ k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHU
 k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
 k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/controller-runtime v0.13.0 h1:iqa5RNciy7ADWnIc8QxCbOX5FEKVR3uxVxKHRMc2WIQ=
diff --git a/pkg/ippoolmanager/ippool_informer.go b/pkg/ippoolmanager/ippool_informer.go
index cefb194d9..1ee3e9b25 100644
--- a/pkg/ippoolmanager/ippool_informer.go
+++ b/pkg/ippoolmanager/ippool_informer.go
@@ -42,7 +42,7 @@ import (
 	"github.com/spidernet-io/spiderpool/pkg/types"
 )
 
-var informerLogger *zap.Logger
+var InformerLogger *zap.Logger
 
 type IPPoolController struct {
 	IPPoolControllerConfig
@@ -55,6 +55,9 @@ type IPPoolController struct {
 	subnetsLister listers.SpiderSubnetLister
 	subnetsSynced cache.InformerSynced
 
+	SubnetIndexer cache.Indexer
+	IPPoolIndexer cache.Indexer
+
 	// the normalPoolWorkQueue serves for normal IPPools
 	normalPoolWorkQueue workqueue.RateLimitingInterface
 
@@ -80,7 +83,7 @@ type IPPoolControllerConfig struct {
 }
 
 func NewIPPoolController(poolControllerConfig IPPoolControllerConfig, client client.Client, rIPManager reservedipmanager.ReservedIPManager) *IPPoolController {
-	informerLogger = logutils.Logger.Named("SpiderIPPool-Informer")
+	InformerLogger = logutils.Logger.Named("SpiderIPPool-Informer")
 
 	c := &IPPoolController{
 		IPPoolControllerConfig: poolControllerConfig,
@@ -93,10 +96,10 @@ func NewIPPoolController(poolControllerConfig IPPoolControllerConfig, client cli
 
 func (ic *IPPoolController) SetupInformer(ctx context.Context, client crdclientset.Interface, controllerLeader election.SpiderLeaseElector) error {
 	if controllerLeader == nil {
-		return fmt.Errorf("failed to start SpiderIPPool informer, controller leader must be specified")
+		return fmt.Errorf("failed to start SpiderIPPool informer, controller leader%w", constant.ErrMissingRequiredParam)
 	}
 
-	informerLogger.Info("try to register SpiderIPPool informer")
+	InformerLogger.Info("try to register SpiderIPPool informer")
 	go func() {
 		for {
 			select {
@@ -120,7 +123,7 @@ func (ic *IPPoolController) SetupInformer(ctx context.Context, client crdclients
 					}
 
 					if !controllerLeader.IsElected() {
-						informerLogger.Warn("Leader lost, stop Subnet informer")
+						InformerLogger.Warn("Leader lost, stop Subnet informer")
 						innerCancel()
 						return
 					}
@@ -128,7 +131,7 @@ func (ic *IPPoolController) SetupInformer(ctx context.Context, client crdclients
 				}
 			}()
 
-			informerLogger.Info("create SpiderIPPool informer")
+			InformerLogger.Info("create SpiderIPPool informer")
 			factory := externalversions.NewSharedInformerFactory(client, ic.ResyncPeriod)
 			ic.addEventHandlers(
 				factory.Spiderpool().V1().SpiderIPPools(),
@@ -137,9 +140,9 @@ func (ic *IPPoolController) SetupInformer(ctx context.Context, client crdclients
 			factory.Start(innerCtx.Done())
 
 			if err := ic.Run(innerCtx.Done()); nil != err {
-				informerLogger.Sugar().Errorf("failed to run ippool controller, error: %v", err)
+				InformerLogger.Sugar().Errorf("failed to run ippool controller, error: %v", err)
 			}
-			informerLogger.Error("SpiderIPPool informer broken")
+			InformerLogger.Error("SpiderIPPool informer broken")
 		}
 	}()
 
@@ -151,7 +154,8 @@ func (ic *IPPoolController) addEventHandlers(poolInformer informers.SpiderIPPool
 	ic.poolSynced = poolInformer.Informer().HasSynced
 	ic.subnetsLister = subnetInformer.Lister()
 	ic.subnetsSynced = subnetInformer.Informer().HasSynced
-
+	ic.SubnetIndexer = subnetInformer.Informer().GetIndexer()
+	ic.IPPoolIndexer = poolInformer.Informer().GetIndexer()
 	ic.normalPoolWorkQueue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "Normal-SpiderIPPools")
 	ic.v4AutoPoolWorkQueue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "AutoCreated-SpiderIPPools-IPv4")
 	ic.v6AutoPoolWorkQueue = workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "AutoCreated-SpiderIPPools-IPv6")
@@ -209,27 +213,27 @@ func (ic *IPPoolController) enqueueIPPool(pool *spiderpoolv1.SpiderIPPool) {
 
 		if ipVersion == constant.IPv4 {
 			if ic.v4AutoPoolWorkQueue.Len() >= ic.MaxWorkqueueLength {
-				informerLogger.Sugar().Errorf("The Auto-Created IPv4 IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
+				InformerLogger.Sugar().Errorf("The Auto-Created IPv4 IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
 				return
 			}
 			ic.v4AutoPoolWorkQueue.Add(pool.Name)
 		} else {
 			if ic.v6AutoPoolWorkQueue.Len() >= ic.MaxWorkqueueLength {
-				informerLogger.Sugar().Errorf("The Auto-Created IPv6 IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
+				InformerLogger.Sugar().Errorf("The Auto-Created IPv6 IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
 				return
 			}
 			ic.v6AutoPoolWorkQueue.Add(pool.Name)
 		}
 
-		informerLogger.Sugar().Debugf("added '%s' to Auto-Created IPv%d IPPool workqueue", pool.Name, ipVersion)
+		InformerLogger.Sugar().Debugf("added '%s' to Auto-Created IPv%d IPPool workqueue", pool.Name, ipVersion)
 	} else {
 		// the Normal IPPools enqueue the corresponding NormalPoolWorkqueue
 		if ic.normalPoolWorkQueue.Len() >= ic.MaxWorkqueueLength {
-			informerLogger.Sugar().Errorf("The Normal IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
+			InformerLogger.Sugar().Errorf("The Normal IPPool workqueue is out of capacity, discard enqueue IPPool '%s'", pool.Name)
 			return
 		}
 		ic.normalPoolWorkQueue.Add(pool.Name)
-		informerLogger.Sugar().Debugf("added '%s' to Normal IPPool workqueue", pool.Name)
+		InformerLogger.Sugar().Debugf("added '%s' to Normal IPPool workqueue", pool.Name)
 	}
 }
 
@@ -237,9 +241,9 @@ func (ic *IPPoolController) enqueueIPPool(pool *spiderpoolv1.SpiderIPPool) {
 func (ic *IPPoolController) onIPPoolAdd(obj interface{}) {
 	pool := obj.(*spiderpoolv1.SpiderIPPool)
 
-	err := ic.updateSpiderIPPool(nil, pool, informerLogger.With(zap.String("onIPPoolAdd", pool.Name)))
+	err := ic.updateSpiderIPPool(nil, pool, InformerLogger.With(zap.String("onIPPoolAdd", pool.Name)))
 	if nil != err {
-		informerLogger.Sugar().Errorf("onSpiderIPPoolAdd error: %v", err)
+		InformerLogger.Sugar().Errorf("onSpiderIPPoolAdd error: %v", err)
 	}
 }
 
@@ -248,9 +252,9 @@ func (ic *IPPoolController) onIPPoolUpdate(oldObj interface{}, newObj interface{
 	oldPool := oldObj.(*spiderpoolv1.SpiderIPPool)
 	newPool := newObj.(*spiderpoolv1.SpiderIPPool)
 
-	err := ic.updateSpiderIPPool(oldPool, newPool, informerLogger.With(zap.String("onIPPoolUpdate", newPool.Name)))
+	err := ic.updateSpiderIPPool(oldPool, newPool, InformerLogger.With(zap.String("onIPPoolUpdate", newPool.Name)))
 	if nil != err {
-		informerLogger.Sugar().Errorf("onAllIPPoolUpdate error: %v", err)
+		InformerLogger.Sugar().Errorf("onAllIPPoolUpdate error: %v", err)
 	}
 }
 
@@ -311,31 +315,31 @@ func (ic *IPPoolController) Run(stopCh <-chan struct{}) error {
 	defer utilruntime.HandleCrash()
 	defer ic.normalPoolWorkQueue.ShutDown()
 
-	informerLogger.Debug("Waiting for informer caches to sync")
+	InformerLogger.Debug("Waiting for informer caches to sync")
 	if ok := cache.WaitForCacheSync(stopCh, ic.poolSynced, ic.subnetsSynced); !ok {
 		return fmt.Errorf("failed to wait for caches to sync")
 	}
 
 	for i := 0; i < ic.IPPoolControllerWorkers; i++ {
-		informerLogger.Sugar().Debugf("Starting Normal IPPool processing worker '%d'", i)
+		InformerLogger.Sugar().Debugf("Starting Normal IPPool processing worker '%d'", i)
 		go wait.Until(ic.runNormalIPPoolWorker, 1*time.Second, stopCh)
 	}
 
 	if ic.EnableIPv4 && ic.EnableSpiderSubnet {
 		defer ic.v4AutoPoolWorkQueue.ShutDown()
-		informerLogger.Debug("Staring IPv4 Auto-Created IPPool processing worker")
+		InformerLogger.Debug("Staring IPv4 Auto-Created IPPool processing worker")
 		go wait.Until(ic.runV4AutoPoolWorker, 1*time.Second, stopCh)
 	}
 	if ic.EnableIPv6 && ic.EnableSpiderSubnet {
 		defer ic.v6AutoPoolWorkQueue.ShutDown()
-		informerLogger.Debug("Staring IPv6 Auto-Created IPPool processing worker")
+		InformerLogger.Debug("Staring IPv6 Auto-Created IPPool processing worker")
 		go wait.Until(ic.runV6AutoPoolWorker, 1*time.Second, stopCh)
 	}
 
-	informerLogger.Info("IPPool controller workers started")
+	InformerLogger.Info("IPPool controller workers started")
 
 	<-stopCh
-	informerLogger.Error("Shutting down IPPool controller workers")
+	InformerLogger.Error("Shutting down IPPool controller workers")
 	return nil
 }
 
@@ -345,7 +349,7 @@ func (ic *IPPoolController) Run(stopCh <-chan struct{}) error {
 // processNextWorkItem function in order to read and process a message on the
 // IPv4 Auto-created workQueue and try to scale it if needed
 func (ic *IPPoolController) runV4AutoPoolWorker() {
-	log := informerLogger.With(zap.String("IPPool_Informer_Worker", "IPv4_IPPool"))
+	log := InformerLogger.With(zap.String("IPPool_Informer_Worker", "IPv4_IPPool"))
 	for ic.processNextWorkItem(ic.v4AutoPoolWorkQueue, ic.handleIPPool, log) {
 	}
 }
@@ -356,7 +360,7 @@ func (ic *IPPoolController) runV4AutoPoolWorker() {
 // processNextWorkItem function in order to read and process a message on the
 // IPv6 Auto-created workQueue and try to scale it if needed
 func (ic *IPPoolController) runV6AutoPoolWorker() {
-	log := informerLogger.With(zap.String("IPPool_Informer_Worker", "IPv6_IPPool"))
+	log := InformerLogger.With(zap.String("IPPool_Informer_Worker", "IPv6_IPPool"))
 	for ic.processNextWorkItem(ic.v6AutoPoolWorkQueue, ic.handleIPPool, log) {
 	}
 }
@@ -364,7 +368,7 @@ func (ic *IPPoolController) runV6AutoPoolWorker() {
 // worker runs a worker thread that just dequeues items, processes them, and marks them done.
 // This will update SpiderIPPool status counts
 func (ic *IPPoolController) runNormalIPPoolWorker() {
-	log := informerLogger.With(zap.String("IPPool_Informer_Worker", "All_IPPool"))
+	log := InformerLogger.With(zap.String("IPPool_Informer_Worker", "All_IPPool"))
 	for ic.processNextWorkItem(ic.normalPoolWorkQueue, ic.syncHandleAllIPPool, log) {
 	}
 }
@@ -453,7 +457,7 @@ func (ic *IPPoolController) scaleIPPoolIfNeeded(ctx context.Context, pool *spide
 	}
 
 	if pool.Status.AutoDesiredIPCount == nil {
-		informerLogger.Sugar().Debugf("maybe IPPool '%s' is just created for a while, wait for updating status DesiredIPCount", pool.Name)
+		InformerLogger.Sugar().Debugf("maybe IPPool '%s' is just created for a while, wait for updating status DesiredIPCount", pool.Name)
 		return nil
 	}
 
@@ -469,14 +473,14 @@ func (ic *IPPoolController) scaleIPPoolIfNeeded(ctx context.Context, pool *spide
 		// no need to scale
 		return nil
 	}
-	informerLogger.Sugar().Debugf("IPPool '%s' need to change its IP number from '%d' to desired number '%d'", pool.Name, totalIPCount, desiredIPNum)
+	InformerLogger.Sugar().Debugf("IPPool '%s' need to change its IP number from '%d' to desired number '%d'", pool.Name, totalIPCount, desiredIPNum)
 
 	timeRecorder := metric.NewTimeRecorder()
 	defer func() {
 		// Time taken for once Auto-created IPPool scale.
 		scaleDuration := timeRecorder.SinceInSeconds()
 		metric.AutoPoolScaleDurationConstruct.RecordAutoPoolScaleDuration(ctx, scaleDuration)
-		informerLogger.Sugar().Infof("Auto-created IPPool '%s' scale duration: %v", pool.Name, scaleDuration)
+		InformerLogger.Sugar().Infof("Auto-created IPPool '%s' scale duration: %v", pool.Name, scaleDuration)
 	}()
 
 	if desiredIPNum > totalIPCount {
@@ -490,12 +494,12 @@ func (ic *IPPoolController) scaleIPPoolIfNeeded(ctx context.Context, pool *spide
 			ic.v6GenIPsCursor = !ic.v6GenIPsCursor
 		}
 
-		ipsFromSubnet, err := ic.generateIPsFromSubnetWhenScaleUpIP(logutils.IntoContext(ctx, informerLogger), subnetName, pool, cursor)
+		ipsFromSubnet, err := ic.generateIPsFromSubnetWhenScaleUpIP(logutils.IntoContext(ctx, InformerLogger), subnetName, pool, cursor)
 		if nil != err {
 			return fmt.Errorf("failed to generate IPs from subnet '%s', error: %w", subnetName, err)
 		}
 
-		informerLogger.Sugar().Infof("try to scale IPPool '%s' IP number from '%d' to '%d' with generated IPs '%v'", pool.Name, totalIPCount, desiredIPNum, ipsFromSubnet)
+		InformerLogger.Sugar().Infof("try to scale IPPool '%s' IP number from '%d' to '%d' with generated IPs '%v'", pool.Name, totalIPCount, desiredIPNum, ipsFromSubnet)
 		// the IPPool webhook will automatically assign the scaled IP from SpiderSubnet
 		err = ic.scaleIPPoolWithIPs(ctx, pool, ipsFromSubnet, true, desiredIPNum)
 		if nil != err {
@@ -521,9 +525,9 @@ func (ic *IPPoolController) scaleIPPoolIfNeeded(ctx context.Context, pool *spide
 				return fmt.Errorf("%w: failed to convert IPs '%v' to IP ranges, error: %v", constant.ErrWrongInput, discardedIPs, err)
 			}
 
-			informerLogger.Sugar().Infof("try to scale IPPool '%s' IP number from '%d' to '%d' with discarded IPs '%v'", pool.Name, totalIPCount, desiredIPNum, discardedIPs)
+			InformerLogger.Sugar().Infof("try to scale IPPool '%s' IP number from '%d' to '%d' with discarded IPs '%v'", pool.Name, totalIPCount, desiredIPNum, discardedIPs)
 			// the IPPool webhook will automatically return the released IP back to SpiderSubnet
-			err = ic.scaleIPPoolWithIPs(logutils.IntoContext(ctx, informerLogger), pool, discardedIPRanges, false, desiredIPNum)
+			err = ic.scaleIPPoolWithIPs(logutils.IntoContext(ctx, InformerLogger), pool, discardedIPRanges, false, desiredIPNum)
 			if nil != err {
 				return fmt.Errorf("failed to shrink IPPool '%s' with IPs '%v': %w", pool.Name, discardedIPs, err)
 			}
@@ -579,12 +583,12 @@ func (ic *IPPoolController) cleanAutoIPPoolLegacy(ctx context.Context, pool *spi
 		enableDelete := false
 
 		// check the IPPool's corresponding application whether is existed or not
-		informerLogger.Sugar().Debugf("try to get auto-created IPPool '%s' corresponding application '%s/%s/%s'", pool.Name, kind, ns, name)
+		InformerLogger.Sugar().Debugf("try to get auto-created IPPool '%s' corresponding application '%s/%s/%s'", pool.Name, kind, ns, name)
 		err = ic.client.Get(ctx, apitypes.NamespacedName{Namespace: ns, Name: name}, object)
 		if nil != err {
 			// if the application is no longer exist, we should delete the IPPool
 			if apierrors.IsNotFound(err) {
-				informerLogger.Sugar().Warnf("auto-created IPPool '%s' corresponding application '%s/%s/%s' is no longer exist, try to gc IPPool",
+				InformerLogger.Sugar().Warnf("auto-created IPPool '%s' corresponding application '%s/%s/%s' is no longer exist, try to gc IPPool",
 					pool.Name, kind, ns, name)
 				enableDelete = true
 			} else {
@@ -594,7 +598,7 @@ func (ic *IPPoolController) cleanAutoIPPoolLegacy(ctx context.Context, pool *spi
 			// mismatch application UID
 			if string(object.GetUID()) != poolLabels[constant.LabelIPPoolOwnerApplicationUID] {
 				enableDelete = true
-				informerLogger.Sugar().Warnf("auto-created IPPool '%v' mismatches application '%s/%s/%s' UID '%s', try to gc IPPool",
+				InformerLogger.Sugar().Warnf("auto-created IPPool '%v' mismatches application '%s/%s/%s' UID '%s', try to gc IPPool",
 					pool, kind, ns, name, object.GetUID())
 			}
 		}
@@ -652,13 +656,13 @@ func (ic *IPPoolController) syncHandleAllIPPool(ctx context.Context, pool *spide
 			err := ic.removeFinalizer(ctx, pool)
 			if nil != err {
 				if apierrors.IsNotFound(err) {
-					informerLogger.Sugar().Debugf("SpiderIPPool '%s' is already deleted", pool.Name)
+					InformerLogger.Sugar().Debugf("SpiderIPPool '%s' is already deleted", pool.Name)
 					return nil
 				}
 				return fmt.Errorf("failed to remove SpiderIPPool '%s' finalizer: %w", pool.Name, err)
 			}
 
-			informerLogger.Sugar().Infof("remove SpiderIPPool '%s' finalizer successfully", pool.Name)
+			InformerLogger.Sugar().Infof("remove SpiderIPPool '%s' finalizer successfully", pool.Name)
 		}
 	} else {
 		needUpdate := false
@@ -667,7 +671,7 @@ func (ic *IPPoolController) syncHandleAllIPPool(ctx context.Context, pool *spide
 		if pool.Status.AllocatedIPCount == nil {
 			needUpdate = true
 			pool.Status.AllocatedIPCount = pointer.Int64(0)
-			informerLogger.Sugar().Infof("initial SpiderIPPool '%s' status AllocatedIPCount to 0", pool.Name)
+			InformerLogger.Sugar().Infof("initial SpiderIPPool '%s' status AllocatedIPCount to 0", pool.Name)
 		}
 
 		totalIPs, err := spiderpoolip.AssembleTotalIPs(*pool.Spec.IPVersion, pool.Spec.IPs, pool.Spec.ExcludeIPs)
@@ -685,7 +689,7 @@ func (ic *IPPoolController) syncHandleAllIPPool(ctx context.Context, pool *spide
 			if nil != err {
 				return err
 			}
-			informerLogger.Sugar().Debugf("update SpiderIPPool '%s' status TotalIPCount to '%d' successfully", pool.Name, *pool.Status.TotalIPCount)
+			InformerLogger.Sugar().Debugf("update SpiderIPPool '%s' status TotalIPCount to '%d' successfully", pool.Name, *pool.Status.TotalIPCount)
 		}
 	}
 
@@ -699,7 +703,7 @@ func (ic *IPPoolController) syncSubnetIPPools(obj interface{}) {
 	selector := labels.Set{constant.LabelIPPoolOwnerSpiderSubnet: subnet.Name}.AsSelector()
 	ipPools, err := ic.poolLister.List(selector)
 	if nil != err {
-		informerLogger.Sugar().Errorf("syncSubnetIPPools error: %v", err)
+		InformerLogger.Sugar().Errorf("syncSubnetIPPools error: %v", err)
 		return
 	}
 
@@ -711,7 +715,7 @@ func (ic *IPPoolController) syncSubnetIPPools(obj interface{}) {
 		// If the auto-created IPPool's current IP number is not equal with the desired IP number, we'll try to scale it.
 		// If its allocated IPs are empty, we will check whether the IPPool should be deleted or not.
 		if ShouldScaleIPPool(pool) || len(pool.Status.AllocatedIPs) == 0 {
-			informerLogger.Sugar().Debugf("try to add IPPool %s to resync with SpiderSubnet %s", pool.Name, subnet.Name)
+			InformerLogger.Sugar().Debugf("try to add IPPool %s to resync with SpiderSubnet %s", pool.Name, subnet.Name)
 			ic.enqueueIPPool(pool)
 		}
 	}
diff --git a/pkg/ippoolmanager/ippool_manager.go b/pkg/ippoolmanager/ippool_manager.go
index df9e6abc8..6a20a4081 100644
--- a/pkg/ippoolmanager/ippool_manager.go
+++ b/pkg/ippoolmanager/ippool_manager.go
@@ -76,6 +76,9 @@ func (im *ipPoolManager) ListIPPools(ctx context.Context, opts ...client.ListOpt
 }
 
 func (im *ipPoolManager) AllocateIP(ctx context.Context, poolName, containerID, nic string, pod *corev1.Pod, podController types.PodTopController) (*models.IPConfig, error) {
+	if pod == nil {
+		return nil, fmt.Errorf("pod %w", constant.ErrMissingRequiredParam)
+	}
 	logger := logutils.FromContext(ctx)
 
 	r := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -277,6 +280,9 @@ func (im *ipPoolManager) UpdateAllocatedIPs(ctx context.Context, poolName string
 }
 
 func (im *ipPoolManager) DeleteAllIPPools(ctx context.Context, pool *spiderpoolv1.SpiderIPPool, opts ...client.DeleteAllOfOption) error {
+	if pool == nil {
+		return fmt.Errorf("pool %w", constant.ErrMissingRequiredParam)
+	}
 	err := im.client.DeleteAllOf(ctx, pool, opts...)
 	if client.IgnoreNotFound(err) != nil {
 		return err
@@ -286,6 +292,10 @@ func (im *ipPoolManager) DeleteAllIPPools(ctx context.Context, pool *spiderpoolv
 }
 
 func (im *ipPoolManager) UpdateDesiredIPNumber(ctx context.Context, pool *spiderpoolv1.SpiderIPPool, ipNum int) error {
+	if pool == nil {
+		return fmt.Errorf("pool %w", constant.ErrMissingRequiredParam)
+	}
+
 	if pool.Status.AutoDesiredIPCount == nil {
 		pool.Status.AutoDesiredIPCount = new(int64)
 	} else {
diff --git a/pkg/ippoolmanager/mock/ippool_manager_mock.go b/pkg/ippoolmanager/mock/ippool_manager_mock.go
new file mode 100644
index 000000000..c7bcbcc85
--- /dev/null
+++ b/pkg/ippoolmanager/mock/ippool_manager_mock.go
@@ -0,0 +1,154 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./ippool_manager.go
+
+// Package mock is a generated GoMock package.
+package mock
+
+import (
+	context "context"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	models "github.com/spidernet-io/spiderpool/api/v1/agent/models"
+	v1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	types "github.com/spidernet-io/spiderpool/pkg/types"
+	v10 "k8s.io/api/core/v1"
+	client "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// MockIPPoolManager is a mock of IPPoolManager interface.
+type MockIPPoolManager struct {
+	ctrl     *gomock.Controller
+	recorder *MockIPPoolManagerMockRecorder
+}
+
+// MockIPPoolManagerMockRecorder is the mock recorder for MockIPPoolManager.
+type MockIPPoolManagerMockRecorder struct {
+	mock *MockIPPoolManager
+}
+
+// NewMockIPPoolManager creates a new mock instance.
+func NewMockIPPoolManager(ctrl *gomock.Controller) *MockIPPoolManager {
+	mock := &MockIPPoolManager{ctrl: ctrl}
+	mock.recorder = &MockIPPoolManagerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIPPoolManager) EXPECT() *MockIPPoolManagerMockRecorder {
+	return m.recorder
+}
+
+// AllocateIP mocks base method.
+func (m *MockIPPoolManager) AllocateIP(ctx context.Context, poolName, containerID, nic string, pod *v10.Pod, podController types.PodTopController) (*models.IPConfig, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AllocateIP", ctx, poolName, containerID, nic, pod, podController)
+	ret0, _ := ret[0].(*models.IPConfig)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// AllocateIP indicates an expected call of AllocateIP.
+func (mr *MockIPPoolManagerMockRecorder) AllocateIP(ctx, poolName, containerID, nic, pod, podController interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocateIP", reflect.TypeOf((*MockIPPoolManager)(nil).AllocateIP), ctx, poolName, containerID, nic, pod, podController)
+}
+
+// DeleteAllIPPools mocks base method.
+func (m *MockIPPoolManager) DeleteAllIPPools(ctx context.Context, pool *v1.SpiderIPPool, opts ...client.DeleteAllOfOption) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx, pool}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "DeleteAllIPPools", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// DeleteAllIPPools indicates an expected call of DeleteAllIPPools.
+func (mr *MockIPPoolManagerMockRecorder) DeleteAllIPPools(ctx, pool interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx, pool}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAllIPPools", reflect.TypeOf((*MockIPPoolManager)(nil).DeleteAllIPPools), varargs...)
+}
+
+// GetIPPoolByName mocks base method.
+func (m *MockIPPoolManager) GetIPPoolByName(ctx context.Context, poolName string) (*v1.SpiderIPPool, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetIPPoolByName", ctx, poolName)
+	ret0, _ := ret[0].(*v1.SpiderIPPool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetIPPoolByName indicates an expected call of GetIPPoolByName.
+func (mr *MockIPPoolManagerMockRecorder) GetIPPoolByName(ctx, poolName interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetIPPoolByName", reflect.TypeOf((*MockIPPoolManager)(nil).GetIPPoolByName), ctx, poolName)
+}
+
+// ListIPPools mocks base method.
+func (m *MockIPPoolManager) ListIPPools(ctx context.Context, opts ...client.ListOption) (*v1.SpiderIPPoolList, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListIPPools", varargs...)
+	ret0, _ := ret[0].(*v1.SpiderIPPoolList)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListIPPools indicates an expected call of ListIPPools.
+func (mr *MockIPPoolManagerMockRecorder) ListIPPools(ctx interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIPPools", reflect.TypeOf((*MockIPPoolManager)(nil).ListIPPools), varargs...)
+}
+
+// ReleaseIP mocks base method.
+func (m *MockIPPoolManager) ReleaseIP(ctx context.Context, poolName string, ipAndCIDs []types.IPAndCID) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ReleaseIP", ctx, poolName, ipAndCIDs)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ReleaseIP indicates an expected call of ReleaseIP.
+func (mr *MockIPPoolManagerMockRecorder) ReleaseIP(ctx, poolName, ipAndCIDs interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseIP", reflect.TypeOf((*MockIPPoolManager)(nil).ReleaseIP), ctx, poolName, ipAndCIDs)
+}
+
+// UpdateAllocatedIPs mocks base method.
+func (m *MockIPPoolManager) UpdateAllocatedIPs(ctx context.Context, poolName string, ipAndCIDs []types.IPAndCID) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateAllocatedIPs", ctx, poolName, ipAndCIDs)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// UpdateAllocatedIPs indicates an expected call of UpdateAllocatedIPs.
+func (mr *MockIPPoolManagerMockRecorder) UpdateAllocatedIPs(ctx, poolName, ipAndCIDs interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAllocatedIPs", reflect.TypeOf((*MockIPPoolManager)(nil).UpdateAllocatedIPs), ctx, poolName, ipAndCIDs)
+}
+
+// UpdateDesiredIPNumber mocks base method.
+func (m *MockIPPoolManager) UpdateDesiredIPNumber(ctx context.Context, pool *v1.SpiderIPPool, ipNum int) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "UpdateDesiredIPNumber", ctx, pool, ipNum)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// UpdateDesiredIPNumber indicates an expected call of UpdateDesiredIPNumber.
+func (mr *MockIPPoolManagerMockRecorder) UpdateDesiredIPNumber(ctx, pool, ipNum interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDesiredIPNumber", reflect.TypeOf((*MockIPPoolManager)(nil).UpdateDesiredIPNumber), ctx, pool, ipNum)
+}
diff --git a/pkg/reservedipmanager/mock/reservedip_manager_mock.go b/pkg/reservedipmanager/mock/reservedip_manager_mock.go
new file mode 100644
index 000000000..941a41fe2
--- /dev/null
+++ b/pkg/reservedipmanager/mock/reservedip_manager_mock.go
@@ -0,0 +1,92 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./reservedip_manager.go
+
+// Package mock is a generated GoMock package.
+package mock
+
+import (
+	context "context"
+	net "net"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	v1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	types "github.com/spidernet-io/spiderpool/pkg/types"
+	client "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// MockReservedIPManager is a mock of ReservedIPManager interface.
+type MockReservedIPManager struct {
+	ctrl     *gomock.Controller
+	recorder *MockReservedIPManagerMockRecorder
+}
+
+// MockReservedIPManagerMockRecorder is the mock recorder for MockReservedIPManager.
+type MockReservedIPManagerMockRecorder struct {
+	mock *MockReservedIPManager
+}
+
+// NewMockReservedIPManager creates a new mock instance.
+func NewMockReservedIPManager(ctrl *gomock.Controller) *MockReservedIPManager {
+	mock := &MockReservedIPManager{ctrl: ctrl}
+	mock.recorder = &MockReservedIPManagerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReservedIPManager) EXPECT() *MockReservedIPManagerMockRecorder {
+	return m.recorder
+}
+
+// AssembleReservedIPs mocks base method.
+func (m *MockReservedIPManager) AssembleReservedIPs(ctx context.Context, version types.IPVersion) ([]net.IP, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AssembleReservedIPs", ctx, version)
+	ret0, _ := ret[0].([]net.IP)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// AssembleReservedIPs indicates an expected call of AssembleReservedIPs.
+func (mr *MockReservedIPManagerMockRecorder) AssembleReservedIPs(ctx, version interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AssembleReservedIPs", reflect.TypeOf((*MockReservedIPManager)(nil).AssembleReservedIPs), ctx, version)
+}
+
+// GetReservedIPByName mocks base method.
+func (m *MockReservedIPManager) GetReservedIPByName(ctx context.Context, rIPName string) (*v1.SpiderReservedIP, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetReservedIPByName", ctx, rIPName)
+	ret0, _ := ret[0].(*v1.SpiderReservedIP)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetReservedIPByName indicates an expected call of GetReservedIPByName.
+func (mr *MockReservedIPManagerMockRecorder) GetReservedIPByName(ctx, rIPName interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReservedIPByName", reflect.TypeOf((*MockReservedIPManager)(nil).GetReservedIPByName), ctx, rIPName)
+}
+
+// ListReservedIPs mocks base method.
+func (m *MockReservedIPManager) ListReservedIPs(ctx context.Context, opts ...client.ListOption) (*v1.SpiderReservedIPList, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListReservedIPs", varargs...)
+	ret0, _ := ret[0].(*v1.SpiderReservedIPList)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListReservedIPs indicates an expected call of ListReservedIPs.
+func (mr *MockReservedIPManagerMockRecorder) ListReservedIPs(ctx interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListReservedIPs", reflect.TypeOf((*MockReservedIPManager)(nil).ListReservedIPs), varargs...)
+}
diff --git a/pkg/subnetmanager/mock/subnet_manager_mock.go b/pkg/subnetmanager/mock/subnet_manager_mock.go
new file mode 100644
index 000000000..3e9548ef2
--- /dev/null
+++ b/pkg/subnetmanager/mock/subnet_manager_mock.go
@@ -0,0 +1,106 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: ./subnet_manager.go
+
+// Package mock is a generated GoMock package.
+package mock
+
+import (
+	context "context"
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	v1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	types "github.com/spidernet-io/spiderpool/pkg/types"
+	v10 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	client "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// MockSubnetManager is a mock of SubnetManager interface.
+type MockSubnetManager struct {
+	ctrl     *gomock.Controller
+	recorder *MockSubnetManagerMockRecorder
+}
+
+// MockSubnetManagerMockRecorder is the mock recorder for MockSubnetManager.
+type MockSubnetManagerMockRecorder struct {
+	mock *MockSubnetManager
+}
+
+// NewMockSubnetManager creates a new mock instance.
+func NewMockSubnetManager(ctrl *gomock.Controller) *MockSubnetManager {
+	mock := &MockSubnetManager{ctrl: ctrl}
+	mock.recorder = &MockSubnetManagerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockSubnetManager) EXPECT() *MockSubnetManagerMockRecorder {
+	return m.recorder
+}
+
+// AllocateEmptyIPPool mocks base method.
+func (m *MockSubnetManager) AllocateEmptyIPPool(ctx context.Context, subnetMgrName string, podController types.PodTopController, podSelector *v10.LabelSelector, ipNum int, ipVersion types.IPVersion, reclaimIPPool bool, ifName string) (*v1.SpiderIPPool, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AllocateEmptyIPPool", ctx, subnetMgrName, podController, podSelector, ipNum, ipVersion, reclaimIPPool, ifName)
+	ret0, _ := ret[0].(*v1.SpiderIPPool)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// AllocateEmptyIPPool indicates an expected call of AllocateEmptyIPPool.
+func (mr *MockSubnetManagerMockRecorder) AllocateEmptyIPPool(ctx, subnetMgrName, podController, podSelector, ipNum, ipVersion, reclaimIPPool, ifName interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllocateEmptyIPPool", reflect.TypeOf((*MockSubnetManager)(nil).AllocateEmptyIPPool), ctx, subnetMgrName, podController, podSelector, ipNum, ipVersion, reclaimIPPool, ifName)
+}
+
+// CheckScaleIPPool mocks base method.
+func (m *MockSubnetManager) CheckScaleIPPool(ctx context.Context, pool *v1.SpiderIPPool, subnetManagerName string, ipNum int) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CheckScaleIPPool", ctx, pool, subnetManagerName, ipNum)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CheckScaleIPPool indicates an expected call of CheckScaleIPPool.
+func (mr *MockSubnetManagerMockRecorder) CheckScaleIPPool(ctx, pool, subnetManagerName, ipNum interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckScaleIPPool", reflect.TypeOf((*MockSubnetManager)(nil).CheckScaleIPPool), ctx, pool, subnetManagerName, ipNum)
+}
+
+// GetSubnetByName mocks base method.
+func (m *MockSubnetManager) GetSubnetByName(ctx context.Context, subnetName string) (*v1.SpiderSubnet, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetSubnetByName", ctx, subnetName)
+	ret0, _ := ret[0].(*v1.SpiderSubnet)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetSubnetByName indicates an expected call of GetSubnetByName.
+func (mr *MockSubnetManagerMockRecorder) GetSubnetByName(ctx, subnetName interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSubnetByName", reflect.TypeOf((*MockSubnetManager)(nil).GetSubnetByName), ctx, subnetName)
+}
+
+// ListSubnets mocks base method.
+func (m *MockSubnetManager) ListSubnets(ctx context.Context, opts ...client.ListOption) (*v1.SpiderSubnetList, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{ctx}
+	for _, a := range opts {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ListSubnets", varargs...)
+	ret0, _ := ret[0].(*v1.SpiderSubnetList)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// ListSubnets indicates an expected call of ListSubnets.
+func (mr *MockSubnetManagerMockRecorder) ListSubnets(ctx interface{}, opts ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{ctx}, opts...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListSubnets", reflect.TypeOf((*MockSubnetManager)(nil).ListSubnets), varargs...)
+}
diff --git a/pkg/subnetmanager/subnet_manager.go b/pkg/subnetmanager/subnet_manager.go
index c3c33b869..e1254ad42 100644
--- a/pkg/subnetmanager/subnet_manager.go
+++ b/pkg/subnetmanager/subnet_manager.go
@@ -80,7 +80,7 @@ func (sm *subnetManager) ListSubnets(ctx context.Context, opts ...client.ListOpt
 func (sm *subnetManager) AllocateEmptyIPPool(ctx context.Context, subnetName string, podController types.PodTopController,
 	podSelector *metav1.LabelSelector, ipNum int, ipVersion types.IPVersion, reclaimIPPool bool, ifName string) (*spiderpoolv1.SpiderIPPool, error) {
 	if len(subnetName) == 0 {
-		return nil, fmt.Errorf("%w: spider subnet name must be specified", constant.ErrWrongInput)
+		return nil, fmt.Errorf("spider subnet name %w", constant.ErrMissingRequiredParam)
 	}
 	if ipNum < 0 {
 		return nil, fmt.Errorf("%w: the required IP numbers '%d' is invalid", constant.ErrWrongInput, ipNum)
@@ -138,7 +138,7 @@ func (sm *subnetManager) AllocateEmptyIPPool(ctx context.Context, subnetName str
 
 	err = ctrl.SetControllerReference(subnet, sp, sm.Scheme)
 	if nil != err {
-		return nil, fmt.Errorf("failed to set SpiderIPPool %s owner reference with SpiderSubnet %s: %v", sp.Name, subnetName, err)
+		return nil, fmt.Errorf("failed to set SpiderIPPool %s owner reference with SpiderSubnet %s: %w", sp.Name, subnetName, err)
 	}
 
 	timeRecorder := metric.NewTimeRecorder()
@@ -167,7 +167,7 @@ func (sm *subnetManager) AllocateEmptyIPPool(ctx context.Context, subnetName str
 // CheckScaleIPPool will fetch some IPs from the specified subnet manager to expand the pool IPs
 func (sm *subnetManager) CheckScaleIPPool(ctx context.Context, pool *spiderpoolv1.SpiderIPPool, subnetName string, ipNum int) error {
 	if pool == nil {
-		return fmt.Errorf("%w: IPPool must be specified", constant.ErrWrongInput)
+		return fmt.Errorf("IPPool: %w ", constant.ErrMissingRequiredParam)
 	}
 	if ipNum <= 0 {
 		return fmt.Errorf("%w: assign IP number '%d' is invalid", constant.ErrWrongInput, ipNum)
diff --git a/vendor/github.com/google/gops/agent/agent.go b/vendor/github.com/google/gops/agent/agent.go
index b7978069d..de6d90f90 100644
--- a/vendor/github.com/google/gops/agent/agent.go
+++ b/vendor/github.com/google/gops/agent/agent.go
@@ -12,6 +12,7 @@ import (
 	"encoding/binary"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"net"
 	"os"
 	gosignal "os/signal"
@@ -114,7 +115,7 @@ func Listen(opts Options) error {
 	}
 	port := listener.Addr().(*net.TCPAddr).Port
 	portfile = filepath.Join(gopsdir, strconv.Itoa(os.Getpid()))
-	err = os.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)
+	err = ioutil.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)
 	if err != nil {
 		return err
 	}
diff --git a/vendor/github.com/google/gops/internal/internal.go b/vendor/github.com/google/gops/internal/internal.go
index 7e3492aae..7fc162a69 100644
--- a/vendor/github.com/google/gops/internal/internal.go
+++ b/vendor/github.com/google/gops/internal/internal.go
@@ -6,9 +6,11 @@ package internal
 
 import (
 	"errors"
+	"io/ioutil"
 	"os"
 	"os/user"
 	"path/filepath"
+	"runtime"
 	"strconv"
 	"strings"
 )
@@ -24,6 +26,14 @@ func ConfigDir() (string, error) {
 		return filepath.Join(userConfigDir, "gops"), nil
 	}
 
+	if runtime.GOOS == "windows" {
+		return filepath.Join(os.Getenv("APPDATA"), "gops"), nil
+	}
+
+	if xdgConfigDir := os.Getenv("XDG_CONFIG_HOME"); xdgConfigDir != "" {
+		return filepath.Join(xdgConfigDir, "gops"), nil
+	}
+
 	homeDir := guessUnixHomeDir()
 	if homeDir == "" {
 		return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
@@ -52,7 +62,7 @@ func GetPort(pid int) (string, error) {
 	if err != nil {
 		return "", err
 	}
-	b, err := os.ReadFile(portfile)
+	b, err := ioutil.ReadFile(portfile)
 	if err != nil {
 		return "", err
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index e4f0897de..b5310da4b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -197,8 +197,8 @@ github.com/google/go-cmp/cmp/internal/value
 # github.com/google/gofuzz v1.1.0
 ## explicit; go 1.12
 github.com/google/gofuzz
-# github.com/google/gops v0.3.27
-## explicit; go 1.17
+# github.com/google/gops v0.3.26
+## explicit; go 1.13
 github.com/google/gops/agent
 github.com/google/gops/internal
 github.com/google/gops/signal


Test patch:
diff --git a/pkg/ippoolmanager/ippool_informer_test.go b/pkg/ippoolmanager/ippool_informer_test.go
new file mode 100644
index 000000000..d0e7fc3bc
--- /dev/null
+++ b/pkg/ippoolmanager/ippool_informer_test.go
@@ -0,0 +1,119 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package ippoolmanager_test
+
+import (
+	"context"
+	"fmt"
+	"sync/atomic"
+
+	"github.com/agiledragon/gomonkey/v2"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/testing"
+	"k8s.io/client-go/tools/cache"
+	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
+	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	spiderpoolfake "github.com/spidernet-io/spiderpool/pkg/k8s/client/clientset/versioned/fake"
+	"github.com/spidernet-io/spiderpool/pkg/logutils"
+)
+
+var _ = Describe("IPPoolInformer", Label("ippool_informer_test"), func() {
+	Describe("New IPPoolController", func() {
+		It("sets default IPPoolController", func() {
+			controller := ippoolmanager.NewIPPoolController(ippoolmanager.IPPoolControllerConfig{}, fakeClient, rIPManager)
+			Expect(controller).NotTo(BeNil())
+		})
+
+		It("inputs nil client", func() {
+			controller := ippoolmanager.NewIPPoolController(ippoolmanager.IPPoolControllerConfig{}, nil, rIPManager)
+			Expect(controller).NotTo(BeNil())
+		})
+
+		It("inputs nil reserved-IP manager", func() {
+			manager := ippoolmanager.NewIPPoolController(ippoolmanager.IPPoolControllerConfig{}, fakeClient, nil)
+			Expect(manager).NotTo(BeNil())
+		})
+	})
+
+	Describe("Test IPPoolInformer's method", func() {
+		var count uint64
+		var ipPoolName string
+		var ipPoolT *spiderpoolv1.SpiderIPPool
+
+		var ippoolController *ippoolmanager.IPPoolController
+		var fakeIPPoolWatch *watch.FakeWatcher
+		// var ipPoolIndexer cache.Indexer
+
+		BeforeEach(func() {
+			ippoolmanager.InformerLogger = logutils.Logger.Named("Ippool-Informer")
+			atomic.AddUint64(&count, 1)
+			ipPoolName = fmt.Sprintf("ippool-%v", count)
+			ipPoolT = &spiderpoolv1.SpiderIPPool{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       constant.SpiderIPPoolKind,
+					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:   ipPoolName,
+					Labels: map[string]string{},
+				},
+				Spec: spiderpoolv1.IPPoolSpec{},
+			}
+
+			ippoolController = &ippoolmanager.IPPoolController{}
+
+			patches := gomonkey.ApplyFuncReturn(cache.WaitForNamedCacheSync, true)
+			DeferCleanup(patches.Reset)
+
+			mockLeaderElector.EXPECT().
+				IsElected().
+				Return(true).
+				AnyTimes()
+
+			ctx, cancel := context.WithCancel(context.Background())
+			DeferCleanup(cancel)
+
+			fakeIPPoolWatch = watch.NewFake()
+			fakeClientset := spiderpoolfake.NewSimpleClientset()
+			fakeClientset.PrependWatchReactor("spiderippools", testing.DefaultWatchReactor(fakeIPPoolWatch, nil))
+
+			err := ippoolController.SetupInformer(ctx, fakeClientset, mockLeaderElector)
+			Expect(err).NotTo(HaveOccurred())
+			Eventually(func(g Gomega) {
+				g.Expect(ippoolController.IPPoolIndexer).NotTo(BeNil())
+				// ipPoolIndexer = ippoolController.IPPoolIndexer
+			}).Should(Succeed())
+
+		})
+
+		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, ipPoolT, deleteOption)
+			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+		})
+
+		It("inputs nil setupInformer's controllerLeader", func() {
+			ctx := context.TODO()
+			fakeClientset := spiderpoolfake.NewSimpleClientset()
+			fakeClientset.PrependWatchReactor("spiderippools", testing.DefaultWatchReactor(fakeIPPoolWatch, nil))
+			err := ippoolController.SetupInformer(ctx, fakeClientset, nil)
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+		})
+	})
+})
diff --git a/pkg/ippoolmanager/ippool_manager_suite_test.go b/pkg/ippoolmanager/ippool_manager_suite_test.go
index 8187b7d1e..4ef6ba4f7 100644
--- a/pkg/ippoolmanager/ippool_manager_suite_test.go
+++ b/pkg/ippoolmanager/ippool_manager_suite_test.go
@@ -5,6 +5,7 @@ package ippoolmanager_test
 
 import (
 	"testing"
+	"time"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -12,15 +13,29 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 
+	"github.com/golang/mock/gomock"
+	electionmock "github.com/spidernet-io/spiderpool/pkg/election/mock"
 	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	"github.com/spidernet-io/spiderpool/pkg/reservedipmanager"
+	ripmanagermock "github.com/spidernet-io/spiderpool/pkg/reservedipmanager/mock"
+	corev1 "k8s.io/api/core/v1"
 )
 
 var scheme *runtime.Scheme
 var fakeClient client.Client
 var ipPoolWebhook *ippoolmanager.IPPoolWebhook
+var ipPoolManager ippoolmanager.IPPoolManager
+var rIPManagerMock *ripmanagermock.MockReservedIPManager
+var rIPManager reservedipmanager.ReservedIPManager
+
+var mockCtrl *gomock.Controller
+var mockLeaderElector *electionmock.MockSpiderLeaseElector
 
 func TestIPPoolManager(t *testing.T) {
+	mockCtrl = gomock.NewController(t)
+	defer mockCtrl.Finish()
+
 	RegisterFailHandler(Fail)
 	RunSpecs(t, "IPPoolManager Suite", Label("ippoolmanager", "unitest"))
 }
@@ -30,6 +45,9 @@ var _ = BeforeSuite(func() {
 	err := spiderpoolv1.AddToScheme(scheme)
 	Expect(err).NotTo(HaveOccurred())
 
+	err = corev1.AddToScheme(scheme)
+	Expect(err).NotTo(HaveOccurred())
+
 	fakeClient = fake.NewClientBuilder().
 		WithScheme(scheme).
 		Build()
@@ -41,4 +59,15 @@ var _ = BeforeSuite(func() {
 		EnableIPv6:         true,
 		EnableSpiderSubnet: true,
 	}
+
+	rIPManager, err = reservedipmanager.NewReservedIPManager(fakeClient)
+	Expect(err).NotTo(HaveOccurred())
+
+	ipPoolManager, err = ippoolmanager.NewIPPoolManager(ippoolmanager.IPPoolManagerConfig{
+		MaxConflictRetries:    3,
+		ConflictRetryUnitTime: time.Second,
+	}, fakeClient, rIPManager)
+	Expect(err).NotTo(HaveOccurred())
+
+	mockLeaderElector = electionmock.NewMockSpiderLeaseElector(mockCtrl)
 })
diff --git a/pkg/ippoolmanager/ippool_manager_test.go b/pkg/ippoolmanager/ippool_manager_test.go
new file mode 100644
index 000000000..46be05aac
--- /dev/null
+++ b/pkg/ippoolmanager/ippool_manager_test.go
@@ -0,0 +1,651 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package ippoolmanager_test
+
+import (
+	"context"
+	"fmt"
+	"sync/atomic"
+
+	"github.com/agiledragon/gomonkey/v2"
+	"github.com/moby/moby/pkg/stringid"
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/util/uuid"
+	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
+	"github.com/spidernet-io/spiderpool/pkg/types"
+
+	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	corev1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+var _ = Describe("IPPoolManager_test", Label("ippool_manager_test"), func() {
+	Describe("New IPPoolManager", func() {
+		It("sets default config", func() {
+			manager, err := ippoolmanager.NewIPPoolManager(ippoolmanager.IPPoolManagerConfig{}, fakeClient, rIPManagerMock)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(manager).NotTo(BeNil())
+		})
+
+		It("inputs nil client", func() {
+			manager, err := ippoolmanager.NewIPPoolManager(ippoolmanager.IPPoolManagerConfig{}, nil, rIPManager)
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+
+		It("inputs nil reserved-IP manager", func() {
+			manager, err := ippoolmanager.NewIPPoolManager(ippoolmanager.IPPoolManagerConfig{}, fakeClient, nil)
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+	})
+
+	Describe("Test IPPoolManager's method", func() {
+		var count uint64
+		var namespace string
+		var podName string
+		var ipPoolName string
+		var ipPoolT *spiderpoolv1.SpiderIPPool
+		var labels map[string]string
+
+		BeforeEach(func() {
+			atomic.AddUint64(&count, 1)
+			ipPoolName = fmt.Sprintf("IPPool-%v", count)
+			labels = map[string]string{"foo": fmt.Sprintf("bar-%v", count)}
+			ipPoolT = &spiderpoolv1.SpiderIPPool{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       constant.SpiderIPPoolKind,
+					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:   ipPoolName,
+					Labels: labels,
+				},
+				Spec: spiderpoolv1.IPPoolSpec{},
+			}
+		})
+		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, ipPoolT, deleteOption)
+			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+		})
+
+		Describe("GetIPPoolByName", func() {
+			It("gets non-existent IPPool", func() {
+				ctx := context.TODO()
+				ippool, err := ipPoolManager.GetIPPoolByName(ctx, ipPoolName)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+				Expect(ippool).To(BeNil())
+			})
+
+			It("gets an existing IPPool", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ippool, err := ipPoolManager.GetIPPoolByName(ctx, ipPoolName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ippool).NotTo(BeNil())
+				Expect(ippool).To(Equal(ipPoolT))
+			})
+		})
+
+		Describe("ListIPPools", func() {
+			It("failed to list IPPools due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(ipPoolList).To(BeNil())
+			})
+
+			It("lists all IPPools", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ipPoolList.Items).NotTo(BeEmpty())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeTrue())
+			})
+
+			It("filters results by label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx, client.MatchingLabels(labels))
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ipPoolList.Items).NotTo(BeEmpty())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeTrue())
+			})
+
+			It("filters results by field selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx, client.MatchingFields{metav1.ObjectNameField: ipPoolName})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ipPoolList.Items).NotTo(BeEmpty())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeTrue())
+			})
+		})
+
+		Describe("AllocateIP", func() {
+			var podT *corev1.Pod
+
+			BeforeEach(func() {
+				ipPoolT.SetUID(uuid.NewUUID())
+				ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+				ipPoolT.Spec.Vlan = pointer.Int64(0)
+				ipPoolT.Spec.Subnet = "172.19.41.0/24"
+				ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
+					[]string{
+						"172.19.41.2",
+						"172.19.41.3-172.19.41.100",
+					}...,
+				)
+
+				podT = &corev1.Pod{
+					TypeMeta: metav1.TypeMeta{
+						Kind:       "Pod",
+						APIVersion: corev1.SchemeGroupVersion.String(),
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      podName,
+						Namespace: namespace,
+						UID:       uuid.NewUUID(),
+					},
+					Spec: corev1.PodSpec{
+						NodeName: "node",
+					},
+				}
+
+			})
+
+			It("inputs non-existent IPPool name", func() {
+				ctx := context.TODO()
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, podT, types.PodTopController{})
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+				Expect(ipPool).To(BeNil())
+			})
+
+			It("inputs nil Pod", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, nil, types.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+				Expect(ipPool).To(BeNil())
+			})
+
+			It("allocate IP but IPPool's IPs is empty", func() {
+				ipPoolT.Spec.IPs = []string{}
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, podT, types.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrIPUsedOut))
+				Expect(ipPool).To(BeNil())
+			})
+
+			It("failed to allocate IP due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				patches := gomonkey.ApplyMethodReturn(fakeClient.Status(), "Update", constant.ErrUnknown)
+				defer patches.Reset()
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, podT, types.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(ipPool).To(BeNil())
+			})
+
+			PIt("runs out of retries to allocate IP , but conflicts still occur", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Update", apierrors.NewConflict(schema.GroupResource{Resource: "test"}, "other", nil))
+				defer patches.Reset()
+
+				controllerutil.AddFinalizer(ipPoolT, constant.SpiderFinalizer)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, podT, types.PodTopController{})
+				Expect(err).To(MatchError(constant.ErrRetriesExhausted))
+				Expect(ipPool).To(BeNil())
+			})
+
+			It("passes", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPool, err := ipPoolManager.AllocateIP(ctx, ipPoolName, stringid.GenerateRandomID(), constant.ClusterDefaultInterfaceName, podT, types.PodTopController{})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ipPool).NotTo(BeNil())
+				Expect(ipPool.IPPool).To(Equal(ipPoolName))
+				Expect(*ipPool.Nic).To(Equal(constant.ClusterDefaultInterfaceName))
+			})
+		})
+
+		Describe("ReleaseIP", func() {
+			var containerID, diffContainerID string
+			var ipNumber, diffIPNumber string
+			var diffIPAndCID []types.IPAndCID
+
+			BeforeEach(func() {
+				ipNumber = "172.19.45.2"
+				diffIPNumber = "172.19.45.3"
+				ipPoolT.Spec.Subnet = "172.19.45.0/24"
+				containerID = stringid.GenerateRandomID()
+				diffContainerID = stringid.GenerateRandomID()
+
+				ipPoolT.Status.AllocatedIPs = spiderpoolv1.PoolIPAllocations{}
+				allocation := spiderpoolv1.PoolIPAllocation{
+					ContainerID: containerID,
+				}
+				ipPoolT.Status.AllocatedIPs[ipNumber] = allocation
+
+				diffIPAndCID = []types.IPAndCID{
+					{
+						IP:          ipNumber,
+						ContainerID: containerID,
+					},
+				}
+			})
+
+			It("inputs non-existent IPPool name", func() {
+				ctx := context.TODO()
+				err := ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPAndCID)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+			})
+
+			It("inputs nil ipAndCID", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.ReleaseIP(ctx, ipPoolName, nil)
+				Expect(err).To(BeNil())
+			})
+
+			When("The status IP of the IPPool is the same as the ipAndCIDs[x].IP", func() {
+				It("different container ID", func() {
+					diffIPAndCID[0].ContainerID = diffContainerID
+
+					ctx := context.TODO()
+					err := fakeClient.Create(ctx, ipPoolT)
+					Expect(err).NotTo(HaveOccurred())
+
+					err = ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPAndCID)
+					Expect(err).To(BeNil())
+				})
+			})
+
+			When("The status IP of IPPool is different from ipAndCIDs[x].IP", func() {
+				It("different IP", func() {
+					ipPoolT.Status.AllocatedIPs[ipNumber] = spiderpoolv1.PoolIPAllocation{
+						ContainerID: containerID,
+					}
+					diffIPNumberCID := []types.IPAndCID{
+						{
+							IP: diffIPNumber,
+						},
+					}
+					ctx := context.TODO()
+					err := fakeClient.Create(ctx, ipPoolT)
+					Expect(err).NotTo(HaveOccurred())
+
+					err = ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPNumberCID)
+					Expect(err).To(BeNil())
+				})
+			})
+
+			It("failed to release IP due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				patches := gomonkey.ApplyMethodReturn(fakeClient.Status(), "Update", constant.ErrUnknown)
+				defer patches.Reset()
+
+				err = ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPAndCID)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
+			PIt("runs out of retries to release IP , but conflicts still occur", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Update", apierrors.NewConflict(schema.GroupResource{Resource: "test"}, "other", nil))
+				defer patches.Reset()
+
+				controllerutil.AddFinalizer(ipPoolT, constant.SpiderFinalizer)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPAndCID)
+				Expect(err).To(MatchError(constant.ErrRetriesExhausted))
+			})
+
+			It("passes", func() {
+				diffIPAndCID[0].ContainerID = containerID
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.ReleaseIP(ctx, ipPoolName, diffIPAndCID)
+				Expect(err).To(BeNil())
+			})
+		})
+
+		Describe("UpdateAllocatedIPs", func() {
+			var containerID, diffContainerID string
+			var ipNumber, diffIPNumber string
+			var diffIPAndCID []types.IPAndCID
+
+			BeforeEach(func() {
+				ipNumber = "172.19.40.2"
+				diffIPNumber = "172.19.40.3"
+				containerID = stringid.GenerateRandomID()
+				diffContainerID = stringid.GenerateRandomID()
+
+				ipPoolT.Status.AllocatedIPs = spiderpoolv1.PoolIPAllocations{}
+				allocation := spiderpoolv1.PoolIPAllocation{
+					ContainerID: containerID,
+				}
+				ipPoolT.Status.AllocatedIPs[ipNumber] = allocation
+
+				diffIPAndCID = []types.IPAndCID{
+					{
+						IP:          ipNumber,
+						ContainerID: diffContainerID,
+					},
+				}
+			})
+
+			It("inputs non-existent IPPool name", func() {
+				ctx := context.TODO()
+				err := ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, diffIPAndCID)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+			})
+
+			It("inputs nil resource", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, nil)
+				Expect(err).NotTo(HaveOccurred())
+			})
+
+			It("test updating the same IP and container ID", func() {
+				ipPoolT.Status.AllocatedIPs[ipNumber] = spiderpoolv1.PoolIPAllocation{
+					ContainerID: containerID,
+				}
+				sameIPAndContainerID := []types.IPAndCID{
+					{
+						IP:          ipNumber,
+						ContainerID: containerID,
+					},
+				}
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, sameIPAndContainerID)
+				Expect(err).To(BeNil())
+			})
+
+			It("test updating the diff IP Number", func() {
+				ipPoolT.Status.AllocatedIPs[ipNumber] = spiderpoolv1.PoolIPAllocation{
+					ContainerID: containerID,
+				}
+
+				diffIPNumberCID := []types.IPAndCID{
+					{
+						IP: diffIPNumber,
+					},
+				}
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, diffIPNumberCID)
+				Expect(err).To(BeNil())
+			})
+
+			It("failed to update the status of IPPool AllocatedIPs due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				patches := gomonkey.ApplyMethodReturn(fakeClient.Status(), "Update", constant.ErrUnknown)
+				defer patches.Reset()
+
+				err = ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, diffIPAndCID)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+			})
+
+			It("passes", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateAllocatedIPs(ctx, ipPoolName, diffIPAndCID)
+				Expect(err).To(BeNil())
+			})
+		})
+
+		Describe("DeleteAllIPPools", func() {
+			var deleteAllOfOption client.DeleteAllOfOption
+
+			BeforeEach(func() {
+				policy := metav1.DeletePropagationForeground
+				deleteAllOfOption = &client.DeleteAllOfOptions{
+					DeleteOptions: client.DeleteOptions{
+						GracePeriodSeconds: pointer.Int64(0),
+						PropagationPolicy:  &policy,
+					},
+				}
+			})
+
+			It("inputs nil IPPool", func() {
+				ctx := context.TODO()
+				err := ipPoolManager.DeleteAllIPPools(ctx, nil)
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			})
+
+			It("Delete All IPPools", func() {
+				newIPPoolT := ipPoolT.DeepCopy()
+				newIPPoolT.SetUID(uuid.NewUUID())
+				newIPPoolT.Name = fmt.Sprintf("newIPPool-%v", count)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+				err = fakeClient.Create(ctx, newIPPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.DeleteAllIPPools(ctx, ipPoolT, deleteAllOfOption)
+				Expect(err).NotTo(HaveOccurred())
+
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx)
+				Expect(err).NotTo(HaveOccurred())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName || ipPool.Name == newIPPoolT.Name {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeFalse())
+			})
+
+			It("delete all ippools by label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.DeleteAllIPPools(ctx, ipPoolT, client.MatchingLabels(labels))
+				Expect(err).NotTo(HaveOccurred())
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx)
+				Expect(err).NotTo(HaveOccurred())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeFalse())
+			})
+
+			It("delete all ippools by field selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.DeleteAllIPPools(ctx, ipPoolT, client.MatchingFields{metav1.ObjectNameField: ipPoolName})
+				Expect(err).NotTo(HaveOccurred())
+				ipPoolList, err := ipPoolManager.ListIPPools(ctx)
+				Expect(err).NotTo(HaveOccurred())
+
+				hasIPPool := false
+				for _, ipPool := range ipPoolList.Items {
+					if ipPool.Name == ipPoolName {
+						hasIPPool = true
+						break
+					}
+				}
+				Expect(hasIPPool).To(BeFalse())
+			})
+		})
+
+		Describe("UpdateDesiredIPNumber", func() {
+			var ipNum int
+
+			BeforeEach(func() {
+				ipNum = 1
+			})
+
+			It("inputs nil IPPool ", func() {
+				ctx := context.TODO()
+				err := ipPoolManager.UpdateDesiredIPNumber(ctx, nil, ipNum)
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			})
+
+			It("inputs nil AutoDesiredIPCount", func() {
+				ipPoolT.Status.AutoDesiredIPCount = nil
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateDesiredIPNumber(ctx, ipPoolT, ipNum)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(*ipPoolT.Status.AutoDesiredIPCount).To(Equal(int64(ipNum)))
+			})
+
+			It("Enter an ip number equal to the autoDesiredIPCount ", func() {
+				var autoDesiredIPCount int = 2
+				ipPoolT.Status.AutoDesiredIPCount = pointer.Int64(2)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateDesiredIPNumber(ctx, ipPoolT, autoDesiredIPCount)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(*ipPoolT.Status.AutoDesiredIPCount).To(Equal(int64(autoDesiredIPCount)))
+			})
+
+			It("IPPool status AutoDesiredIPCount is nil", func() {
+				ipPoolT.Status.AutoDesiredIPCount = nil
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateDesiredIPNumber(ctx, ipPoolT, ipNum)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(*ipPoolT.Status.AutoDesiredIPCount).To(Equal(int64(ipNum)))
+			})
+
+			It("failed to update the status of IPPool AutoDesiredIPCount due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				errInfo := fmt.Errorf("failed to update IPPool '%s' auto desired IP count to %d : unknown", ipPoolName, ipNum)
+				patches := gomonkey.ApplyMethodReturn(fakeClient.Status(), "Update", constant.ErrUnknown)
+				defer patches.Reset()
+
+				err = ipPoolManager.UpdateDesiredIPNumber(ctx, ipPoolT, ipNum)
+				Expect(err).To(MatchError(errInfo))
+			})
+
+			It("passes", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = ipPoolManager.UpdateDesiredIPNumber(ctx, ipPoolT, ipNum)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(*ipPoolT.Status.AutoDesiredIPCount).To(Equal(int64(ipNum)))
+			})
+		})
+	})
+})
diff --git a/pkg/ippoolmanager/utils_test.go b/pkg/ippoolmanager/utils_test.go
new file mode 100644
index 000000000..807896123
--- /dev/null
+++ b/pkg/ippoolmanager/utils_test.go
@@ -0,0 +1,130 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package ippoolmanager_test
+
+import (
+	"context"
+	"fmt"
+	"sync/atomic"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
+	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/uuid"
+	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+var _ = Describe("IPPoolManager utils", Label("ippool_manager_utils_test"), func() {
+	var count uint64
+	var ipPoolName string
+	var ipPoolT *spiderpoolv1.SpiderIPPool
+	var labels map[string]string
+
+	BeforeEach(func() {
+		atomic.AddUint64(&count, 1)
+		ipPoolName = fmt.Sprintf("ippool-%v", count)
+		labels = map[string]string{"foo": fmt.Sprintf("bar-%v", count)}
+		ipPoolT = &spiderpoolv1.SpiderIPPool{
+			TypeMeta: metav1.TypeMeta{
+				Kind:       constant.SpiderIPPoolKind,
+				APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
+			},
+			ObjectMeta: metav1.ObjectMeta{
+				Name:   ipPoolName,
+				Labels: labels,
+			},
+			Spec: spiderpoolv1.IPPoolSpec{},
+		}
+		ipPoolT.SetUID(uuid.NewUUID())
+		ipPoolT.Spec.IPVersion = pointer.Int64(constant.IPv4)
+		ipPoolT.Spec.Vlan = pointer.Int64(0)
+		ipPoolT.Spec.Subnet = "172.20.10.0/24"
+		ipPoolT.Spec.IPs = append(ipPoolT.Spec.IPs,
+			[]string{
+				"172.20.10.2",
+				"172.20.10.3-172.20.10.100",
+			}...,
+		)
+	})
+
+	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, ipPoolT, deleteOption)
+		Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+	})
+
+	Describe("ShouldScaleIPPool", func() {
+
+		It("scale an IPPool with the pool's AutoDesiredIPCount is nil", func() {
+			ipPoolT.Status.AutoDesiredIPCount = nil
+			ctx := context.TODO()
+			err := fakeClient.Create(ctx, ipPoolT)
+			Expect(err).NotTo(HaveOccurred())
+
+			isOk := ippoolmanager.ShouldScaleIPPool(ipPoolT)
+			Expect(isOk).To(BeFalse())
+		})
+
+		When("scale an IPPool with the pool's AutoDesiredIPCount not nil", func() {
+			It("assemble total IPs not equal to AutoDesiredIPCount", func() {
+				ipPoolT.Status.AutoDesiredIPCount = pointer.Int64(10)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				isOk := ippoolmanager.ShouldScaleIPPool(ipPoolT)
+				Expect(isOk).To(BeTrue())
+			})
+
+			It("assemble total IPs equal to AutoDesiredIPCount", func() {
+				ipPoolT.Status.AutoDesiredIPCount = pointer.Int64(2)
+				ipPoolT.Spec.IPs = []string{
+					"172.20.10.2",
+					"172.20.10.3",
+				}
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				isOk := ippoolmanager.ShouldScaleIPPool(ipPoolT)
+				Expect(isOk).To(BeFalse())
+			})
+		})
+	})
+
+	Describe("IsAutoCreatedIPPool", func() {
+		It("label 'ipam.spidernet.io/owner-application' does not exist", func() {
+			ctx := context.TODO()
+			err := fakeClient.Create(ctx, ipPoolT)
+			Expect(err).NotTo(HaveOccurred())
+
+			isOk := ippoolmanager.IsAutoCreatedIPPool(ipPoolT)
+			Expect(isOk).To(BeFalse())
+		})
+
+		It("label 'ipam.spidernet.io/owner-application' exist", func() {
+			labels = map[string]string{"ipam.spidernet.io/owner-application": ipPoolName}
+			ipPoolT.Labels = labels
+			ctx := context.TODO()
+			err := fakeClient.Create(ctx, ipPoolT)
+			Expect(err).NotTo(HaveOccurred())
+
+			isOk := ippoolmanager.IsAutoCreatedIPPool(ipPoolT)
+			Expect(isOk).To(BeTrue())
+		})
+	})
+})
diff --git a/pkg/subnetmanager/controllers/controller_internal_test.go b/pkg/subnetmanager/controllers/controller_internal_test.go
deleted file mode 100644
index d065ba2ad..000000000
--- a/pkg/subnetmanager/controllers/controller_internal_test.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"go.uber.org/zap"
-)
-
-var _ = Describe("Controller", Label("unitest"), func() {
-	Context("NewApplicationController", func() {
-		type controllerAgs struct {
-			reconcileFunc AppInformersAddOrUpdateFunc
-			cleanupFunc   APPInformersDelFunc
-			logger        *zap.Logger
-
-			expect bool
-		}
-		var conrollerags controllerAgs
-		BeforeEach(func() {
-			conrollerags = controllerAgs{
-				reconcileFunc: func(ctx context.Context, oldObj, newObj interface{}) error {
-					return nil
-				},
-				cleanupFunc: func(ctx context.Context, obj interface{}) error {
-					return nil
-				},
-				logger: &zap.Logger{},
-			}
-		})
-
-		DescribeTable("UT NewApplicationController", Label("NewApplicationController"), func(getParam func() *controllerAgs) {
-			p := getParam()
-			if p.reconcileFunc == nil || p.cleanupFunc == nil {
-				_, err := NewApplicationController(p.reconcileFunc, p.cleanupFunc, p.logger)
-				Expect(err).To(HaveOccurred())
-			}
-			if p.expect {
-				_, err := NewApplicationController(p.reconcileFunc, p.cleanupFunc, p.logger)
-				Expect(err).NotTo(HaveOccurred())
-			}
-		},
-			Entry("nil reconcile", func() *controllerAgs {
-				conrollerags.reconcileFunc = nil
-				return &conrollerags
-			}),
-			Entry("nil cleanup", func() *controllerAgs {
-				conrollerags.cleanupFunc = nil
-				return &conrollerags
-			}),
-		)
-	})
-})
diff --git a/pkg/subnetmanager/controllers/controllers_suite_test.go b/pkg/subnetmanager/controllers/controllers_suite_test.go
deleted file mode 100644
index 23aecf1e1..000000000
--- a/pkg/subnetmanager/controllers/controllers_suite_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	kubeinformers "k8s.io/client-go/informers"
-	"k8s.io/client-go/kubernetes/fake"
-	"testing"
-
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-)
-
-func TestControllers(t *testing.T) {
-	RegisterFailHandler(Fail)
-	RunSpecs(t, "Controllers Suite")
-}
-
-var factory kubeinformers.SharedInformerFactory
-
-var _ = BeforeSuite(func() {
-	clientSet := fake.NewSimpleClientset()
-	factory = kubeinformers.NewSharedInformerFactory(clientSet, 0)
-})
diff --git a/pkg/subnetmanager/controllers/cronjob_informer_internal_test.go b/pkg/subnetmanager/controllers/cronjob_informer_internal_test.go
deleted file mode 100644
index 975f57175..000000000
--- a/pkg/subnetmanager/controllers/cronjob_informer_internal_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	batchv1 "k8s.io/api/batch/v1"
-)
-
-var _ = Describe("CronjobInformer", Label("unitest"), func() {
-
-	Context("UT cronjob_informer", Serial, func() {
-		defer GinkgoRecover()
-		cronObj1 := batchv1.CronJob{}
-		cronObj2 := batchv1.CronJob{}
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-		logger := logutils.Logger.Named("ut-test-cronjob-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onCronJobAdd", func() {
-			controller.onCronJobAdd(&cronObj1)
-		})
-		It("failed to onCronJobUpdate", func() {
-			controller.onCronJobUpdate(&cronObj1, &cronObj2)
-		})
-		It("failed to onCronJobDelete", func() {
-			controller.onCronJobDelete(&cronObj1)
-		})
-		It("AddCronJobHandler", func() {
-			cronJobInformer := factory.Batch().V1().CronJobs().Informer()
-			controller.AddJobController(cronJobInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/daemonset_informer_internal_test.go b/pkg/subnetmanager/controllers/daemonset_informer_internal_test.go
deleted file mode 100644
index 81735598b..000000000
--- a/pkg/subnetmanager/controllers/daemonset_informer_internal_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	appv1 "k8s.io/api/apps/v1"
-)
-
-var _ = Describe("DaemonSetInformer", Label("unitest"), func() {
-
-	Context("UT daemonSet_informer", Serial, func() {
-		defer GinkgoRecover()
-
-		ds1 := appv1.DaemonSet{}
-		ds2 := appv1.DaemonSet{}
-
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		logger := logutils.Logger.Named("ut-test-daemonSet-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onDaemonSetAdd", func() {
-			controller.onDaemonSetAdd(&ds1)
-		})
-		It("failed to onDaemonSetUpdate", func() {
-			controller.onDaemonSetUpdate(&ds1, &ds2)
-		})
-		It("failed to onDaemonSetDelete", func() {
-			controller.onDaemonSetDelete(&ds1)
-		})
-		It("AddDaemonSetHandler", func() {
-			daemonSetInformer := factory.Apps().V1().DaemonSets().Informer()
-			controller.AddDaemonSetHandler(daemonSetInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/deployment_informer_internal_test.go b/pkg/subnetmanager/controllers/deployment_informer_internal_test.go
deleted file mode 100644
index d1f211f7f..000000000
--- a/pkg/subnetmanager/controllers/deployment_informer_internal_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	appv1 "k8s.io/api/apps/v1"
-)
-
-var _ = Describe("DeploymentInformer", Label("unitest"), func() {
-
-	Context("UT deployment_informer", Serial, func() {
-		defer GinkgoRecover()
-
-		deploy1 := appv1.Deployment{}
-		deploy2 := appv1.Deployment{}
-
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		logger := logutils.Logger.Named("ut-test-deploy-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onDeploymentAdd", func() {
-			controller.onDeploymentAdd(&deploy1)
-		})
-		It("failed to onDeploymentUpdate", func() {
-			controller.onDeploymentUpdate(&deploy1, &deploy2)
-		})
-		It("failed to onDeploymentDelete", func() {
-			controller.onDeploymentDelete(&deploy1)
-		})
-		It("AddDeploymentHandler", func() {
-			deploymentInformer := factory.Apps().V1().Deployments().Informer()
-			controller.AddDaemonSetHandler(deploymentInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/job_informer_internal_test.go b/pkg/subnetmanager/controllers/job_informer_internal_test.go
deleted file mode 100644
index 11359a1b2..000000000
--- a/pkg/subnetmanager/controllers/job_informer_internal_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	batchv1 "k8s.io/api/batch/v1"
-)
-
-var _ = Describe("JobInformer", Label("unitest"), func() {
-
-	Context("UT job_informer", Serial, func() {
-		defer GinkgoRecover()
-		job1 := batchv1.Job{}
-		job2 := batchv1.Job{}
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-		logger := logutils.Logger.Named("ut-test-job-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onJobAdd", func() {
-			controller.onJobAdd(&job1)
-		})
-		It("failed to onJobUpdate", func() {
-			controller.onJobUpdate(&job1, &job2)
-		})
-		It("failed to onJobDelete", func() {
-			controller.onJobDelete(&job1)
-		})
-		It("AddJobController", func() {
-			jobInformer := factory.Batch().V1().Jobs().Informer()
-			controller.AddJobController(jobInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/replicaset_informer_internal_test.go b/pkg/subnetmanager/controllers/replicaset_informer_internal_test.go
deleted file mode 100644
index 0bb8a6d60..000000000
--- a/pkg/subnetmanager/controllers/replicaset_informer_internal_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	appv1 "k8s.io/api/apps/v1"
-)
-
-var _ = Describe("ReplicaSetInformer", Label("unitest"), func() {
-
-	Context("UT ReplicaSet_informer", Serial, func() {
-		defer GinkgoRecover()
-
-		ds1 := appv1.ReplicaSet{}
-		ds2 := appv1.ReplicaSet{}
-
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		logger := logutils.Logger.Named("ut-test-replicaSet-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onReplicaSetAdd", func() {
-			controller.onReplicaSetAdd(&ds1)
-		})
-		It("failed to onReplicaSetUpdate", func() {
-			controller.onReplicaSetUpdate(&ds1, &ds2)
-		})
-		It("failed to onReplicaSetDelete", func() {
-			controller.onReplicaSetDelete(&ds1)
-		})
-		It("AddReplicaSetHandler", func() {
-			replicaSetsInformer := factory.Apps().V1().ReplicaSets().Informer()
-			controller.AddDaemonSetHandler(replicaSetsInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/statefulset_informer_internal_test.go b/pkg/subnetmanager/controllers/statefulset_informer_internal_test.go
deleted file mode 100644
index a3369fd75..000000000
--- a/pkg/subnetmanager/controllers/statefulset_informer_internal_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"context"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	appv1 "k8s.io/api/apps/v1"
-)
-
-var _ = Describe("StatefulSetInformer", Label("unitest"), func() {
-
-	Context("UT statefulSet_informer", Serial, func() {
-		defer GinkgoRecover()
-
-		ds1 := appv1.StatefulSet{}
-		ds2 := appv1.StatefulSet{}
-
-		reconcile := func(ctx context.Context, oldObj, newObj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		cleanup := func(ctx context.Context, obj interface{}) error {
-			return constant.ErrUnknown
-		}
-
-		logger := logutils.Logger.Named("ut-test-statefulSet-informer")
-
-		// NewApplicationController
-		controller, err := NewApplicationController(reconcile, cleanup, logger)
-		Expect(err).NotTo(HaveOccurred())
-
-		It("failed to onStatefulSetAdd", func() {
-			controller.onStatefulSetAdd(&ds1)
-		})
-		It("failed to onStatefulSetUpdate", func() {
-			controller.onStatefulSetUpdate(&ds1, &ds2)
-		})
-		It("failed to onStatefulSetDelete", func() {
-			controller.onStatefulSetDelete(&ds1)
-		})
-		It("AddStatefulSetHandler", func() {
-			statefulSetInformer := factory.Apps().V1().StatefulSets().Informer()
-			controller.AddDaemonSetHandler(statefulSetInformer)
-		})
-	})
-})
diff --git a/pkg/subnetmanager/controllers/utils_internal_test.go b/pkg/subnetmanager/controllers/utils_internal_test.go
deleted file mode 100644
index dcb5e3600..000000000
--- a/pkg/subnetmanager/controllers/utils_internal_test.go
+++ /dev/null
@@ -1,539 +0,0 @@
-// Copyright 2022 Authors of spidernet-io
-// SPDX-License-Identifier: Apache-2.0
-
-package controllers
-
-import (
-	"encoding/json"
-	"fmt"
-	"github.com/agiledragon/gomonkey/v2"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
-	"github.com/spidernet-io/spiderpool/pkg/constant"
-	spiderpoolip "github.com/spidernet-io/spiderpool/pkg/ip"
-	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
-	"github.com/spidernet-io/spiderpool/pkg/logutils"
-	"github.com/spidernet-io/spiderpool/pkg/types"
-	apitypes "k8s.io/apimachinery/pkg/types"
-	"k8s.io/utils/pointer"
-	"strings"
-)
-
-var _ = Describe("Utils", func() {
-	It("SubnetPoolName", Label("unitest", "SubnetPoolName"), func() {
-		//controllerKind, controllerNS, controllerName string, ipVersion types.IPVersion, ifName string, controllerUID apitypes.UID
-		controllerKind := "test-kind"
-		controllerNS := "test-ns"
-		controllerName := "test-name"
-		ipVersion := types.IPVersion(4)
-		ifName := "test-nic"
-		controllerUID := apitypes.UID("a-b-c-d")
-		lastOne := "d"
-		expectRes := fmt.Sprintf("auto-%s-%s-%s-v%d-%s-%s",
-			strings.ToLower(controllerKind), strings.ToLower(controllerNS), strings.ToLower(controllerName), ipVersion, ifName, strings.ToLower(lastOne))
-
-		res := SubnetPoolName(controllerKind, controllerNS, controllerName, ipVersion, ifName, controllerUID)
-		Expect(res).To(Equal(expectRes), "failed UT")
-	})
-
-	It("AppLabelValue", Label("unitest", "AppLabelValue"), func() {
-		appKind := "test-kind"
-		appNS := "test-ns"
-		appName := "test-name"
-		expectRes := fmt.Sprintf("%s_%s_%s", appKind, appNS, appName)
-		res := AppLabelValue(appKind, appNS, appName)
-		Expect(res).To(Equal(expectRes))
-	})
-
-	It("ParseAppLabelValue", Label("unitest", "ParseAppLabelValue"), func() {
-		str := "a_b_c"
-		//appKind, appNS, appName string, isFound bool
-		appKind := "a"
-		appNS := "b"
-		appName := "c"
-
-		value, ns, name, found := ParseAppLabelValue(str)
-		Expect(appKind).To(Equal(value))
-		Expect(appNS).To(Equal(ns))
-		Expect(found).To(BeTrue())
-		Expect(appName).To(Equal(name))
-	})
-
-	It("GetAppReplicas", Label("unitest", "GetAppReplicas"), func() {
-		Expect(GetAppReplicas(nil)).To(Equal(0))
-		Expect(GetAppReplicas(pointer.Int32(4))).To(Equal(int(4)))
-	})
-
-	Context("GenSubnetFreeIPs", Label("unitest", "GenSubnetFreeIPs"), func() {
-		var subnet spiderpoolv1.SpiderSubnet
-		var e = fmt.Errorf("bad")
-
-		BeforeEach(func() {
-			subnet = spiderpoolv1.SpiderSubnet{
-				Spec: spiderpoolv1.SubnetSpec{
-					IPVersion: pointer.Int64(4),
-					IPs: []string{
-						"10.0.0.10-10.0.0.100",
-						"10.0.1.10-10.0.1.101",
-					},
-					ExcludeIPs: []string{
-						"10.0.1.101",
-					},
-				},
-				Status: spiderpoolv1.SubnetStatus{
-					ControlledIPPools: spiderpoolv1.PoolIPPreAllocations{
-						"test-pool": spiderpoolv1.PoolIPPreAllocation{
-							IPs: []string{
-								"10.0.0.10-10.0.0.100",
-							},
-						},
-					},
-				},
-			}
-		})
-
-		It("failed to ParseIPRanges", func() {
-			patch := gomonkey.ApplyFuncReturn(spiderpoolip.ParseIPRange, nil, e)
-			defer patch.Reset()
-
-			_, err := GenSubnetFreeIPs(&subnet)
-			Expect(err).To(MatchError(e))
-		})
-
-		It("failed to AssembleTotalIPs", func() {
-			patch := gomonkey.ApplyFuncReturn(spiderpoolip.AssembleTotalIPs, nil, e)
-			defer patch.Reset()
-			_, err := GenSubnetFreeIPs(&subnet)
-			Expect(err).To(MatchError(e))
-		})
-
-		It("succeeded to GenSubnetFreeIPs", func() {
-			_, err := GenSubnetFreeIPs(&subnet)
-			Expect(err).NotTo(HaveOccurred())
-		})
-	})
-
-	Context("GetSubnetAnnoConfig", Label("unitest", "GetSubnetAnnoConfig"), func() {
-		var podAnno map[string]string
-		var e = fmt.Errorf("bad")
-		var log = logutils.Logger.Named("test")
-		//ipam.spidernet.io/subnets: '[{"interface":"eth0","ipv4":["default-v4-subnet"],"ipv6":["default-v6-subnet"]}]'
-		var patches []*gomonkey.Patches
-
-		AfterEach(func() {
-			for _, patch := range patches {
-				if patch != nil {
-					patch.Reset()
-				}
-			}
-		})
-
-		It("failed to Unmarshal subnets", func() {
-			podAnno = map[string]string{constant.AnnoSpiderSubnets: "test-val"}
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, e)
-			defer patch.Reset()
-
-			_, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-		})
-
-		It("failed to Unmarshal subnet", func() {
-			podAnno = map[string]string{constant.AnnoSpiderSubnet: "test-val"}
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, e)
-			defer patch.Reset()
-
-			_, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-		})
-
-		It("no spiderSubnet annotations", func() {
-			podAnno = map[string]string{"noSubnetKey": "test-val"}
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(BeNil())
-			Expect(config).To(BeNil())
-		})
-
-		It("failed to GetPoolIPNumber", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(GetPoolIPNumber, false, 0, e)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(MatchError(e))
-			Expect(config).To(BeNil())
-		})
-
-		It("negative number", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(GetPoolIPNumber, false, -1, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-			Expect(config).To(BeNil())
-		})
-
-		It("negative number", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(GetPoolIPNumber, false, -1, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-			Expect(config).To(BeNil())
-		})
-
-		It("failed to ShouldReclaimIPPool", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet: "test-val",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(ShouldReclaimIPPool, nil, e)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-			Expect(config).To(BeNil())
-		})
-
-		It("reclaimPool is true", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(GetPoolIPNumber, true, +1, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(ShouldReclaimIPPool, false, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(mutateAndValidateSubnetAnno, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(config).NotTo(BeNil())
-			Expect(*config.FlexibleIPNum).To(Equal(int(1)))
-			Expect(config.ReclaimIPPool).To(BeFalse())
-		})
-
-		It("isFlexible is true", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet: "test-val",
-			}
-
-			patch := gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(ShouldReclaimIPPool, true, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(mutateAndValidateSubnetAnno, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(config).NotTo(BeNil())
-			Expect(config.ReclaimIPPool).To(BeTrue())
-		})
-
-		It("isFlexible is false", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-			patch := gomonkey.ApplyFuncReturn(GetPoolIPNumber, false, +1, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(ShouldReclaimIPPool, true, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(mutateAndValidateSubnetAnno, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(config).NotTo(BeNil())
-			Expect(config.AssignIPNum).To(Equal(int(1)))
-		})
-
-		It("failed to mutateAndValidateSubnetAnno", func() {
-			podAnno = map[string]string{
-				constant.AnnoSpiderSubnet:             "test-val",
-				constant.AnnoSpiderSubnetPoolIPNumber: "+1",
-			}
-			patch := gomonkey.ApplyFuncReturn(GetPoolIPNumber, false, +1, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(json.Unmarshal, nil)
-			patches = append(patches, patch)
-			patch = gomonkey.ApplyFuncReturn(ShouldReclaimIPPool, true, nil)
-			patches = append(patches, patch)
-
-			config, err := GetSubnetAnnoConfig(podAnno, log)
-			Expect(err).To(HaveOccurred())
-			Expect(config).To(BeNil())
-		})
-	})
-
-	Context("mutateAndValidateSubnetAnno", Label("unitest", "mutateAndValidateSubnetAnno"), func() {
-		var subnetConfig types.PodSubnetAnnoConfig
-
-		It("MultipleSubnets empty IPv4 subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{IPv4: []string{""}},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("MultipleSubnets empty IPv6 subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{IPv6: []string{""}},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("MultipleSubnets both IPV4 and IPv6 empty subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{IPv4: []string{}},
-					{IPv6: []string{}},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("MultipleSubnets containsDuplicate v4subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{IPv4: []string{"10.0.0.0/16"}},
-					{IPv4: []string{"10.0.0.0/16"}},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("MultipleSubnets containsDuplicate interface", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{
-						IPv6:      []string{"fd00:10::/120"},
-						Interface: "a",
-					},
-					{
-						IPv6:      []string{"fd00:20::/120"},
-						Interface: "a",
-					},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("SingleSubnet empty IPv4 subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				SingleSubnet: &types.AnnoSubnetItem{
-					IPv4: []string{""},
-				},
-			}
-		})
-		It("SingleSubnet empty IPv6 subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				SingleSubnet: &types.AnnoSubnetItem{
-					IPv6: []string{""},
-				},
-			}
-		})
-
-		It("SingleSubnet both IPV4 and IPv6 empty subnet", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				SingleSubnet: &types.AnnoSubnetItem{
-					IPv4: []string{},
-					IPv6: []string{},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("specify 'eth0' as the default single interface if it's none", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				SingleSubnet: &types.AnnoSubnetItem{
-					IPv4:      []string{"10.0.0.0/16"},
-					Interface: "",
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).NotTo(HaveOccurred())
-		})
-
-		It("no subnets specified", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).To(HaveOccurred())
-		})
-
-		It("succeeded to mutateAndValidateSubnetAnno", func() {
-			subnetConfig = types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{
-						IPv4:      []string{"10.0.0.0/16"},
-						Interface: "a",
-					},
-				},
-			}
-			Expect(mutateAndValidateSubnetAnno(&subnetConfig)).NotTo(HaveOccurred())
-		})
-	})
-
-	Context("GetPoolIPNumber", Label("unitest", "GetPoolIPNumber"), func() {
-		var str string
-		It("invalid input", func() {
-			str = "+++123"
-			ok, num, err := GetPoolIPNumber(str)
-			Expect(err).To(HaveOccurred())
-			Expect(ok).To(BeFalse())
-			Expect(num).To(Equal(int(-1)))
-
-			str = "+bad"
-			ok, num, err = GetPoolIPNumber(str)
-			Expect(err).To(HaveOccurred())
-			Expect(ok).To(BeFalse())
-			Expect(num).To(Equal(int(-1)))
-		})
-
-		It("succeeded get ip number", func() {
-			str = "+123"
-			ok, num, err := GetPoolIPNumber(str)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ok).To(BeTrue())
-			Expect(num).To(Equal(int(123)))
-
-			str = "321"
-			ok, num, err = GetPoolIPNumber(str)
-			GinkgoWriter.Printf("ok:%t,num:%d,err:%w\n", ok, num, err)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ok).To(BeFalse())
-			Expect(num).To(Equal(int(321)))
-		})
-	})
-
-	Context("CalculateJobPodNum", Label("unitest", "CalculateJobPodNum"), func() {
-		var jobSpecParallelism, jobSpecCompletions *int32
-
-		It("jobSpecParallelism not nil", func() {
-			jobSpecParallelism = pointer.Int32(0)
-			jobSpecCompletions = nil
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(1)))
-
-			jobSpecParallelism = pointer.Int32(2)
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(2)))
-		})
-
-		It("jobSpecCompletions not nil", func() {
-			jobSpecParallelism = nil
-			jobSpecCompletions = pointer.Int32(0)
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(1)))
-
-			jobSpecCompletions = pointer.Int32(2)
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(2)))
-		})
-
-		It("both not nil", func() {
-			jobSpecParallelism = pointer.Int32(3)
-			jobSpecCompletions = pointer.Int32(0)
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(1)))
-
-			jobSpecCompletions = pointer.Int32(2)
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(2)))
-		})
-
-		It("both nil", func() {
-			jobSpecParallelism = nil
-			jobSpecCompletions = nil
-			Expect(CalculateJobPodNum(jobSpecParallelism, jobSpecCompletions)).To(Equal(int(1)))
-		})
-	})
-
-	Context("IsDefaultIPPoolMode", Label("unitest", "IsDefaultIPPoolMode"), func() {
-		var subnetConfig *types.PodSubnetAnnoConfig
-		It("nil subnetConfig", func() {
-			subnetConfig = nil
-			Expect(IsDefaultIPPoolMode(subnetConfig)).To(BeTrue())
-		})
-
-		It("SpiderSubnet with multiple interfaces", func() {
-			subnetConfig = &types.PodSubnetAnnoConfig{
-				MultipleSubnets: []types.AnnoSubnetItem{
-					{Interface: "a"},
-				},
-			}
-			Expect(IsDefaultIPPoolMode(subnetConfig)).To(BeFalse())
-		})
-
-		It("SpiderSubnet with single interface", func() {
-			subnetConfig = &types.PodSubnetAnnoConfig{
-				SingleSubnet: &types.AnnoSubnetItem{
-					Interface: "a",
-				},
-			}
-			Expect(IsDefaultIPPoolMode(subnetConfig)).To(BeFalse())
-		})
-
-		It("not IsDefaultIPPoolMode", func() {
-			subnetConfig = &types.PodSubnetAnnoConfig{}
-			Expect(IsDefaultIPPoolMode(subnetConfig)).To(BeFalse())
-		})
-	})
-
-	Context("ShouldReclaimIPPool", Label("unitest", "ShouldReclaimIPPool"), func() {
-		var anno map[string]string
-		It("failed to ParseBool", func() {
-			anno = map[string]string{constant.AnnoSpiderSubnetReclaimIPPool: "bad-value"}
-			ok, err := ShouldReclaimIPPool(anno)
-			Expect(err).To(HaveOccurred())
-			Expect(ok).To(BeFalse())
-		})
-
-		It("succeeded to ParseBool", func() {
-			anno = map[string]string{constant.AnnoSpiderSubnetReclaimIPPool: "false"}
-			ok, err := ShouldReclaimIPPool(anno)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ok).To(BeFalse())
-
-			anno = map[string]string{constant.AnnoSpiderSubnetReclaimIPPool: "true"}
-			ok, err = ShouldReclaimIPPool(anno)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ok).To(BeTrue())
-		})
-
-		It("no specified reclaim-IPPool", func() {
-			anno = map[string]string{"bad-key": "bad-value"}
-			ok, err := ShouldReclaimIPPool(anno)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ok).To(BeTrue())
-		})
-	})
-
-})
diff --git a/pkg/subnetmanager/subnet_manager_suite_test.go b/pkg/subnetmanager/subnet_manager_suite_test.go
index d1fff13ac..7b6a14521 100644
--- a/pkg/subnetmanager/subnet_manager_suite_test.go
+++ b/pkg/subnetmanager/subnet_manager_suite_test.go
@@ -14,8 +14,11 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 
 	electionmock "github.com/spidernet-io/spiderpool/pkg/election/mock"
+	"github.com/spidernet-io/spiderpool/pkg/ippoolmanager"
 	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	"github.com/spidernet-io/spiderpool/pkg/reservedipmanager"
 	"github.com/spidernet-io/spiderpool/pkg/subnetmanager"
+	corev1 "k8s.io/api/core/v1"
 )
 
 var mockCtrl *gomock.Controller
@@ -24,6 +27,9 @@ var mockLeaderElector *electionmock.MockSpiderLeaseElector
 var scheme *runtime.Scheme
 var fakeClient client.Client
 var subnetWebhook *subnetmanager.SubnetWebhook
+var subnetManager subnetmanager.SubnetManager
+var ipPoolManager ippoolmanager.IPPoolManager
+var rIPManager reservedipmanager.ReservedIPManager
 
 func TestSubnetManager(t *testing.T) {
 	mockCtrl = gomock.NewController(t)
@@ -38,6 +44,9 @@ var _ = BeforeSuite(func() {
 	err := spiderpoolv1.AddToScheme(scheme)
 	Expect(err).NotTo(HaveOccurred())
 
+	err = corev1.AddToScheme(scheme)
+	Expect(err).NotTo(HaveOccurred())
+
 	fakeClient = fake.NewClientBuilder().
 		WithScheme(scheme).
 		Build()
@@ -47,4 +56,17 @@ var _ = BeforeSuite(func() {
 	}
 
 	mockLeaderElector = electionmock.NewMockSpiderLeaseElector(mockCtrl)
+
+	rIPManager, err = reservedipmanager.NewReservedIPManager(fakeClient)
+	Expect(err).NotTo(HaveOccurred())
+
+	ipPoolManager, err = ippoolmanager.NewIPPoolManager(ippoolmanager.IPPoolManagerConfig{
+		MaxConflictRetries: 3,
+	}, fakeClient, rIPManager)
+	Expect(err).NotTo(HaveOccurred())
+
+	subnetManager, err = subnetmanager.NewSubnetManager(subnetmanager.SubnetManagerConfig{
+		MaxConflictRetries: 3,
+	}, fakeClient, ipPoolManager, fakeClient.Scheme())
+	Expect(err).NotTo(HaveOccurred())
 })
diff --git a/pkg/subnetmanager/subnet_manager_test.go b/pkg/subnetmanager/subnet_manager_test.go
new file mode 100644
index 000000000..e28680842
--- /dev/null
+++ b/pkg/subnetmanager/subnet_manager_test.go
@@ -0,0 +1,377 @@
+// Copyright 2022 Authors of spidernet-io
+// SPDX-License-Identifier: Apache-2.0
+
+package subnetmanager_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"
+
+	"github.com/spidernet-io/spiderpool/pkg/constant"
+	spiderpoolv1 "github.com/spidernet-io/spiderpool/pkg/k8s/apis/spiderpool.spidernet.io/v1"
+	"github.com/spidernet-io/spiderpool/pkg/subnetmanager"
+	"github.com/spidernet-io/spiderpool/pkg/types"
+	"k8s.io/apimachinery/pkg/util/uuid"
+	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+)
+
+var _ = Describe("SubnetManager_test", Label("subnet_manager_test"), func() {
+	Describe("New SubnetManager", func() {
+		It("sets default config", func() {
+			manager, err := subnetmanager.NewSubnetManager(subnetmanager.SubnetManagerConfig{}, fakeClient, ipPoolManager, fakeClient.Scheme())
+			Expect(err).NotTo(HaveOccurred())
+			Expect(manager).NotTo(BeNil())
+		})
+
+		It("inputs nil client", func() {
+			manager, err := subnetmanager.NewSubnetManager(subnetmanager.SubnetManagerConfig{}, nil, ipPoolManager, fakeClient.Scheme())
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+
+		It("inputs nil IPPool manager", func() {
+			manager, err := subnetmanager.NewSubnetManager(subnetmanager.SubnetManagerConfig{}, fakeClient, nil, fakeClient.Scheme())
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+
+		It("inputs nil Scheme", func() {
+			manager, err := subnetmanager.NewSubnetManager(subnetmanager.SubnetManagerConfig{}, fakeClient, ipPoolManager, nil)
+			Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			Expect(manager).To(BeNil())
+		})
+	})
+
+	Describe("Test SubnetManager's method", func() {
+		var count uint64
+		var subnetName string
+		var subnetT *spiderpoolv1.SpiderSubnet
+		var labels map[string]string
+
+		BeforeEach(func() {
+			atomic.AddUint64(&count, 1)
+			subnetName = fmt.Sprintf("Subnet-%v", count)
+			labels = map[string]string{"foo": fmt.Sprintf("bar-%v", count)}
+			subnetT = &spiderpoolv1.SpiderSubnet{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       constant.SpiderSubnetKind,
+					APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:   subnetName,
+					Labels: labels,
+				},
+				Spec: spiderpoolv1.SubnetSpec{},
+			}
+			ipVersion := constant.IPv4
+			subnet := "172.18.43.0/24"
+			subnetT.Spec.IPVersion = &ipVersion
+			subnetT.Spec.Subnet = subnet
+		})
+		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, subnetT, deleteOption)
+			Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+		})
+
+		Describe("GetSubnetByName", func() {
+			It("gets non-existent Subnet", func() {
+				ctx := context.TODO()
+				subnet, err := subnetManager.GetSubnetByName(ctx, subnetName)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+				Expect(subnet).To(BeNil())
+			})
+
+			It("gets an existing Subnet", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnet, err := subnetManager.GetSubnetByName(ctx, subnetName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnet).NotTo(BeNil())
+				Expect(subnet).To(Equal(subnetT))
+			})
+		})
+
+		Describe("ListSubnets", func() {
+			It("failed to list IPPools due to some unknown errors", func() {
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "List", constant.ErrUnknown)
+				defer patches.Reset()
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetList, err := subnetManager.ListSubnets(ctx)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(subnetList).To(BeNil())
+			})
+
+			It("lists all Subnets", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetList, err := subnetManager.ListSubnets(ctx)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnetList.Items).NotTo(BeEmpty())
+
+				hasSubnet := false
+				for _, subnet := range subnetList.Items {
+					if subnet.Name == subnetName {
+						hasSubnet = true
+						break
+					}
+				}
+				Expect(hasSubnet).To(BeTrue())
+			})
+
+			It("filters results by label selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetList, err := subnetManager.ListSubnets(ctx, client.MatchingLabels(labels))
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnetList.Items).NotTo(BeEmpty())
+
+				hasSubnet := false
+				for _, subnet := range subnetList.Items {
+					if subnet.Name == subnetName {
+						hasSubnet = true
+						break
+					}
+				}
+				Expect(hasSubnet).To(BeTrue())
+			})
+
+			It("filters results by field selector", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetList, err := subnetManager.ListSubnets(ctx, client.MatchingFields{metav1.ObjectNameField: subnetName})
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnetList.Items).NotTo(BeEmpty())
+
+				hasSubnet := false
+				for _, subnet := range subnetList.Items {
+					if subnet.Name == subnetName {
+						hasSubnet = true
+						break
+					}
+				}
+				Expect(hasSubnet).To(BeTrue())
+			})
+		})
+
+		Describe("AllocateEmptyIPPool", func() {
+			var podT *corev1.Pod
+			var podController types.PodTopController
+			var podSelector *metav1.LabelSelector
+			var ipNum int
+			var ifName string
+			BeforeEach(func() {
+				ipNum = 1
+				ifName = constant.ClusterDefaultInterfaceName
+				podT = &corev1.Pod{
+					TypeMeta: metav1.TypeMeta{
+						Kind:       "Pod",
+						APIVersion: corev1.SchemeGroupVersion.String(),
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name: subnetName,
+						UID:  uuid.NewUUID(),
+					},
+					Spec: corev1.PodSpec{
+						NodeName: "node",
+					},
+				}
+				podSelector = &metav1.LabelSelector{MatchLabels: podT.Labels}
+			})
+
+			It("inputs empty subnet name", func() {
+				ctx := context.TODO()
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, "", podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+				Expect(subnetIPPool).To(BeNil())
+			})
+
+			It("The value of input ipNum is less than 0 ", func() {
+				ctx := context.TODO()
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, -1, constant.IPv4, true, ifName)
+				Expect(err).To(MatchError(constant.ErrWrongInput))
+				Expect(subnetIPPool).To(BeNil())
+			})
+
+			It("inputs non-existent Subnet", func() {
+				ctx := context.TODO()
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(apierrors.IsNotFound(err)).To(BeTrue())
+				Expect(subnetIPPool).To(BeNil())
+			})
+
+			It("avoids modifying the terminating Subnet", func() {
+				now := metav1.Now()
+				subnetT.SetDeletionTimestamp(&now)
+
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(err).To(MatchError(constant.ErrWrongInput))
+				Expect(subnetIPPool).To(BeNil())
+			})
+
+			It("inputs IP's Version is IPv4", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnetIPPool).NotTo(BeNil())
+				Expect(*subnetIPPool.Spec.IPVersion).To(Equal(constant.IPv4))
+			})
+
+			It("inputs IP's Version is IPv6", func() {
+				ctx := context.TODO()
+				ipVersion := constant.IPv6
+				subnet := "abcd:1234::/120"
+				subnetT.Spec.IPVersion = &ipVersion
+				subnetT.Spec.Subnet = subnet
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, ipVersion, true, ifName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(subnetIPPool).NotTo(BeNil())
+				Expect(*subnetIPPool.Spec.IPVersion).To(Equal(constant.IPv6))
+			})
+
+			It("failed to set owner reference due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				patches := gomonkey.ApplyFuncReturn(controllerutil.SetControllerReference, constant.ErrUnknown)
+				defer patches.Reset()
+
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(subnetIPPool).To(BeNil())
+			})
+
+			It("failed to create IPPool in subnet due to some unknown errors", func() {
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, subnetT)
+				Expect(err).NotTo(HaveOccurred())
+
+				patches := gomonkey.ApplyMethodReturn(fakeClient, "Create", constant.ErrUnknown)
+				defer patches.Reset()
+
+				subnetIPPool, err := subnetManager.AllocateEmptyIPPool(ctx, subnetName, podController, podSelector, ipNum, constant.IPv4, true, ifName)
+				Expect(err).To(MatchError(constant.ErrUnknown))
+				Expect(subnetIPPool).To(BeNil())
+			})
+		})
+
+		Describe("CheckScaleIPPool", func() {
+			var ipNum int
+			var ipPoolName string
+			var ipPoolT *spiderpoolv1.SpiderIPPool
+			var labels map[string]string
+
+			BeforeEach(func() {
+				ipNum = 1
+				ipPoolName = fmt.Sprintf("IPPool-%v", count)
+				ipPoolT = &spiderpoolv1.SpiderIPPool{
+					TypeMeta: metav1.TypeMeta{
+						Kind:       constant.SpiderIPPoolKind,
+						APIVersion: fmt.Sprintf("%s/%s", constant.SpiderpoolAPIGroup, constant.SpiderpoolAPIVersionV1),
+					},
+					ObjectMeta: metav1.ObjectMeta{
+						Name:   ipPoolName,
+						Labels: labels,
+					},
+					Spec: spiderpoolv1.IPPoolSpec{},
+				}
+			})
+			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, ipPoolT, deleteOption)
+				Expect(client.IgnoreNotFound(err)).NotTo(HaveOccurred())
+			})
+
+			It("inputs nil IPPool", func() {
+				ctx := context.TODO()
+				err := subnetManager.CheckScaleIPPool(ctx, nil, subnetName, ipNum)
+				Expect(err).To(MatchError(constant.ErrMissingRequiredParam))
+			})
+
+			It("The value of input ipNum is less than 0 ", func() {
+				ctx := context.TODO()
+				err := subnetManager.CheckScaleIPPool(ctx, ipPoolT, subnetName, -1)
+				Expect(err).To(MatchError(constant.ErrWrongInput))
+			})
+
+			It("inputs nil AutoDesiredIPCount", func() {
+				ipPoolT.Status.AutoDesiredIPCount = nil
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = subnetManager.CheckScaleIPPool(ctx, ipPoolT, subnetName, ipNum)
+				Expect(err).NotTo(HaveOccurred())
+
+				ippool, err := ipPoolManager.GetIPPoolByName(ctx, ipPoolName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ippool).NotTo(BeNil())
+				Expect(*ippool.Status.AutoDesiredIPCount).To(Equal(int64(ipNum)))
+			})
+
+			It("inputs not nil AutoDesiredIPCount, For example 5", func() {
+				ipPoolT.Status.AutoDesiredIPCount = pointer.Int64(5)
+				ctx := context.TODO()
+				err := fakeClient.Create(ctx, ipPoolT)
+				Expect(err).NotTo(HaveOccurred())
+
+				err = subnetManager.CheckScaleIPPool(ctx, ipPoolT, subnetName, ipNum)
+				Expect(err).NotTo(HaveOccurred())
+
+				ippool, err := ipPoolManager.GetIPPoolByName(ctx, ipPoolName)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(ippool).NotTo(BeNil())
+				Expect(*ippool.Status.AutoDesiredIPCount).To(Equal(int64(ipNum)))
+			})
+		})
+	})
+})