From c614a19c88dcee6959dbd9af8deb981b53694580 Mon Sep 17 00:00:00 2001
From: veterancj <592016304@qq.com>
Date: Sat, 29 Jul 2023 23:08:46 +0800
Subject: [PATCH] feat:added polaris weighted round robin load balancer.
(#1062)
---
CHANGELOG.md | 1 +
.../AbstractPolarisLoadBalancer.java | 101 +++++++++++++++
...olarisLoadBalancerClientConfiguration.java | 10 ++
.../PolarisRingHashLoadBalancer.java | 72 +----------
.../PolarisWeightedRandomLoadBalancer.java | 72 +----------
...PolarisWeightedRoundRobinLoadBalancer.java | 45 +++++++
...ndomLoadBalancerAutoConfigurationTest.java | 12 ++
...PolarisWeightedRandomLoadBalancerTest.java | 43 +++++++
...risWeightedRoundRobinLoadBalancerTest.java | 120 ++++++++++++++++++
9 files changed, 346 insertions(+), 130 deletions(-)
create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisLoadBalancer.java
create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancer.java
create mode 100644 spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancerTest.java
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ea2a6304a..22fab005e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,3 +22,4 @@
- [fix:fix SCG report wrong service bug when using IP routing.](https://github.com/Tencent/spring-cloud-tencent/pull/1063)
- [fix:fix gray release examples bug.](https://github.com/Tencent/spring-cloud-tencent/pull/1066)
- [fix:fix router label feign interceptor order.](https://github.com/Tencent/spring-cloud-tencent/pull/1069)
+- [feat:added polaris weighted round robin load balancer.](https://github.com/Tencent/spring-cloud-tencent/pull/1062)
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisLoadBalancer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisLoadBalancer.java
new file mode 100644
index 000000000..50aa39ac3
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/AbstractPolarisLoadBalancer.java
@@ -0,0 +1,101 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.polaris.loadbalancer;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.tencent.cloud.common.metadata.MetadataContext;
+import com.tencent.cloud.common.pojo.PolarisServiceInstance;
+import com.tencent.polaris.api.pojo.DefaultServiceInstances;
+import com.tencent.polaris.api.pojo.Instance;
+import com.tencent.polaris.api.pojo.ServiceInstances;
+import com.tencent.polaris.api.pojo.ServiceKey;
+import com.tencent.polaris.router.api.core.RouterAPI;
+import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
+import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.DefaultResponse;
+import org.springframework.cloud.client.loadbalancer.EmptyResponse;
+import org.springframework.cloud.client.loadbalancer.Request;
+import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+
+/**
+ * Abstract Loadbalancer of Polaris.
+ *
+ * @author veteranchen
+ */
+public abstract class AbstractPolarisLoadBalancer implements ReactorServiceInstanceLoadBalancer {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractPolarisLoadBalancer.class);
+
+ private final String serviceId;
+
+ private final RouterAPI routerAPI;
+
+ private ObjectProvider supplierObjectProvider;
+
+ public AbstractPolarisLoadBalancer(String serviceId, ObjectProvider supplierObjectProvider, RouterAPI routerAPI) {
+ this.serviceId = serviceId;
+ this.supplierObjectProvider = supplierObjectProvider;
+ this.routerAPI = routerAPI;
+ }
+
+ private static ServiceInstances convertToPolarisServiceInstances(List serviceInstances) {
+ ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceInstances.get(0).getServiceId());
+ List polarisInstances = serviceInstances.stream()
+ .map(serviceInstance -> ((PolarisServiceInstance) serviceInstance).getPolarisInstance())
+ .collect(Collectors.toList());
+ return new DefaultServiceInstances(serviceKey, polarisInstances);
+ }
+
+ @Override
+ public Mono> choose(Request request) {
+ ServiceInstanceListSupplier supplier = supplierObjectProvider
+ .getIfAvailable(NoopServiceInstanceListSupplier::new);
+ return supplier.get(request).next().map(serviceInstances -> {
+ if (serviceInstances.isEmpty()) {
+ log.warn("No servers available for service: " + this.serviceId);
+ return new EmptyResponse();
+ }
+
+ ProcessLoadBalanceRequest req = new ProcessLoadBalanceRequest();
+ req.setDstInstances(convertToPolarisServiceInstances(serviceInstances));
+ req = setProcessLoadBalanceRequest(req);
+
+ try {
+ ProcessLoadBalanceResponse response = routerAPI.processLoadBalance(req);
+ return new DefaultResponse(new PolarisServiceInstance(response.getTargetInstance()));
+ }
+ catch (Exception e) {
+ log.warn("PolarisRoutingLoadbalancer error", e);
+ return new EmptyResponse();
+ }
+ });
+ }
+
+ protected abstract ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest req);
+}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerClientConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerClientConfiguration.java
index 934b95bd7..c86b08e29 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerClientConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerClientConfiguration.java
@@ -95,6 +95,16 @@ public class PolarisLoadBalancerClientConfiguration {
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), polarisSDKContextManager.getRouterAPI());
}
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.strategy", havingValue = "polarisWeightedRoundRobin")
+ public ReactorLoadBalancer polarisWeightedRoundRobinLoadBalancer(Environment environment,
+ LoadBalancerClientFactory loadBalancerClientFactory, PolarisSDKContextManager polarisSDKContextManager) {
+ String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
+ return new PolarisWeightedRoundRobinLoadBalancer(name,
+ loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), polarisSDKContextManager.getRouterAPI());
+ }
+
@Configuration(proxyBeanMethods = false)
@ConditionalOnReactiveDiscoveryEnabled
@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER)
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashLoadBalancer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashLoadBalancer.java
index 26684fea1..9b225d9bd 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashLoadBalancer.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisRingHashLoadBalancer.java
@@ -17,95 +17,37 @@
package com.tencent.cloud.polaris.loadbalancer;
-import java.util.List;
import java.util.Optional;
-import java.util.stream.Collectors;
-import com.tencent.cloud.common.metadata.MetadataContext;
-import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.config.consumer.LoadBalanceConfig;
-import com.tencent.polaris.api.pojo.DefaultServiceInstances;
-import com.tencent.polaris.api.pojo.Instance;
-import com.tencent.polaris.api.pojo.ServiceInstances;
-import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.Criteria;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
-import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.cloud.client.ServiceInstance;
-import org.springframework.cloud.client.loadbalancer.DefaultResponse;
-import org.springframework.cloud.client.loadbalancer.EmptyResponse;
-import org.springframework.cloud.client.loadbalancer.Request;
-import org.springframework.cloud.client.loadbalancer.Response;
-import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
-import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
/**
* PolarisRingHashLoadBalancer.
*
* @author sean yu
+ * @author veteranchen
*/
-public class PolarisRingHashLoadBalancer implements ReactorServiceInstanceLoadBalancer {
-
- private static final Logger log = LoggerFactory.getLogger(PolarisWeightedRandomLoadBalancer.class);
-
- private final String serviceId;
-
- private final RouterAPI routerAPI;
-
- private ObjectProvider supplierObjectProvider;
+public class PolarisRingHashLoadBalancer extends AbstractPolarisLoadBalancer {
public PolarisRingHashLoadBalancer(String serviceId,
ObjectProvider supplierObjectProvider,
RouterAPI routerAPI) {
- this.serviceId = serviceId;
- this.supplierObjectProvider = supplierObjectProvider;
- this.routerAPI = routerAPI;
- }
-
- private static ServiceInstances convertToPolarisServiceInstances(List serviceInstances) {
- ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceInstances.get(0).getServiceId());
- List polarisInstances = serviceInstances.stream()
- .map(serviceInstance -> ((PolarisServiceInstance) serviceInstance).getPolarisInstance())
- .collect(Collectors.toList());
- return new DefaultServiceInstances(serviceKey, polarisInstances);
+ super(serviceId, supplierObjectProvider, routerAPI);
}
@Override
- public Mono> choose(Request request) {
- ServiceInstanceListSupplier supplier = supplierObjectProvider
- .getIfAvailable(NoopServiceInstanceListSupplier::new);
+ protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest req) {
String hashKey = Optional.ofNullable(PolarisLoadBalancerRingHashKeyProvider.getHashKey()).orElse("");
- return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, hashKey));
- }
-
- private Response getInstanceResponse(List serviceInstances, String hashKey) {
- if (serviceInstances.isEmpty()) {
- log.warn("No servers available for service: " + this.serviceId);
- return new EmptyResponse();
- }
-
- ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
- request.setDstInstances(convertToPolarisServiceInstances(serviceInstances));
- request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_RING_HASH);
+ req.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_RING_HASH);
Criteria criteria = new Criteria();
criteria.setHashKey(hashKey);
- request.setCriteria(criteria);
-
- try {
- ProcessLoadBalanceResponse response = routerAPI.processLoadBalance(request);
- return new DefaultResponse(new PolarisServiceInstance(response.getTargetInstance()));
- }
- catch (Exception e) {
- log.warn("PolarisRoutingLoadbalancer error", e);
- return new EmptyResponse();
- }
+ req.setCriteria(criteria);
+ return req;
}
-
}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancer.java
index 775f44457..df5222068 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancer.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancer.java
@@ -17,88 +17,30 @@
package com.tencent.cloud.polaris.loadbalancer;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.tencent.cloud.common.metadata.MetadataContext;
-import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.config.consumer.LoadBalanceConfig;
-import com.tencent.polaris.api.pojo.DefaultServiceInstances;
-import com.tencent.polaris.api.pojo.Instance;
-import com.tencent.polaris.api.pojo.ServiceInstances;
-import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.Criteria;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
-import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.cloud.client.ServiceInstance;
-import org.springframework.cloud.client.loadbalancer.DefaultResponse;
-import org.springframework.cloud.client.loadbalancer.EmptyResponse;
-import org.springframework.cloud.client.loadbalancer.Request;
-import org.springframework.cloud.client.loadbalancer.Response;
-import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
-import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
/**
* Loadbalancer of Polaris.
*
* @author liaochuntao
+ * @author veteranchen
*/
-public class PolarisWeightedRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer {
-
- private static final Logger log = LoggerFactory.getLogger(PolarisWeightedRandomLoadBalancer.class);
-
- private final String serviceId;
-
- private final RouterAPI routerAPI;
-
- private ObjectProvider supplierObjectProvider;
+public class PolarisWeightedRandomLoadBalancer extends AbstractPolarisLoadBalancer {
public PolarisWeightedRandomLoadBalancer(String serviceId, ObjectProvider supplierObjectProvider, RouterAPI routerAPI) {
- this.serviceId = serviceId;
- this.supplierObjectProvider = supplierObjectProvider;
- this.routerAPI = routerAPI;
- }
-
- private static ServiceInstances convertToPolarisServiceInstances(List serviceInstances) {
- ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceInstances.get(0).getServiceId());
- List polarisInstances = serviceInstances.stream()
- .map(serviceInstance -> ((PolarisServiceInstance) serviceInstance).getPolarisInstance())
- .collect(Collectors.toList());
- return new DefaultServiceInstances(serviceKey, polarisInstances);
+ super(serviceId, supplierObjectProvider, routerAPI);
}
@Override
- public Mono> choose(Request request) {
- ServiceInstanceListSupplier supplier = supplierObjectProvider
- .getIfAvailable(NoopServiceInstanceListSupplier::new);
- return supplier.get(request).next().map(this::getInstanceResponse);
- }
-
- private Response getInstanceResponse(List serviceInstances) {
- if (serviceInstances.isEmpty()) {
- log.warn("No servers available for service: " + this.serviceId);
- return new EmptyResponse();
- }
-
- ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
- request.setDstInstances(convertToPolarisServiceInstances(serviceInstances));
- request.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM);
- request.setCriteria(new Criteria());
-
- try {
- ProcessLoadBalanceResponse response = routerAPI.processLoadBalance(request);
- return new DefaultResponse(new PolarisServiceInstance(response.getTargetInstance()));
- }
- catch (Exception e) {
- log.warn("PolarisRoutingLoadbalancer error", e);
- return new EmptyResponse();
- }
+ protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest req) {
+ req.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM);
+ req.setCriteria(new Criteria());
+ return req;
}
}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancer.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancer.java
new file mode 100644
index 000000000..acdd5dc66
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancer.java
@@ -0,0 +1,45 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.tencent.cloud.polaris.loadbalancer;
+
+import com.tencent.polaris.api.config.consumer.LoadBalanceConfig;
+import com.tencent.polaris.api.rpc.Criteria;
+import com.tencent.polaris.router.api.core.RouterAPI;
+import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+
+/**
+ * WeightedRoundRobin Loadbalancer of Polaris.
+ *
+ * @author veteranchen
+ */
+public class PolarisWeightedRoundRobinLoadBalancer extends AbstractPolarisLoadBalancer {
+
+ public PolarisWeightedRoundRobinLoadBalancer(String serviceId, ObjectProvider supplierObjectProvider, RouterAPI routerAPI) {
+ super(serviceId, supplierObjectProvider, routerAPI);
+ }
+
+ @Override
+ protected ProcessLoadBalanceRequest setProcessLoadBalanceRequest(ProcessLoadBalanceRequest req) {
+ req.setLbPolicy(LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_ROUND_ROBIN);
+ req.setCriteria(new Criteria());
+ return req;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerAutoConfigurationTest.java
index c45baf194..15fc6b9cb 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerAutoConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerAutoConfigurationTest.java
@@ -90,6 +90,18 @@ public class PolarisWeightedRandomLoadBalancerAutoConfigurationTest {
});
}
+ @Test
+ public void testPolarisWeightedRoundRobinInitialization() {
+ this.contextRunner.withPropertyValues("spring.cloud.polaris.loadbalancer.strategy=polarisWeightedRoundRobin")
+ .run(context -> {
+ assertThat(context).hasSingleBean(RestTemplate.class);
+ assertThatThrownBy(() -> {
+ context.getBean(RestTemplate.class).getForEntity("http://wrong.url", String.class);
+ }).isInstanceOf(Exception.class);
+ });
+ }
+
+
@Test
public void testPolarisRingHashInitialization() {
this.contextRunner
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerTest.java
index 4384081cd..51fd71b0d 100644
--- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerTest.java
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRandomLoadBalancerTest.java
@@ -23,6 +23,8 @@ import java.util.List;
import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import com.tencent.polaris.api.exception.ErrorCode;
+import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
@@ -42,6 +44,7 @@ import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_NAMESPACE;
@@ -117,4 +120,44 @@ public class PolarisWeightedRandomLoadBalancerTest {
Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getPort()).isEqualTo(8090);
}
+ @Test
+ public void chooseExceptionTest_thenReturnEmptyInstance() {
+
+ Request request = Mockito.mock(Request.class);
+ List mockInstanceList = new ArrayList<>();
+ mockInstanceList.add(new PolarisServiceInstance(testInstance));
+
+ ServiceInstanceListSupplier serviceInstanceListSupplier = Mockito.mock(ServiceInstanceListSupplier.class);
+ when(serviceInstanceListSupplier.get(request)).thenReturn(Flux.just(mockInstanceList));
+
+ when(supplierObjectProvider.getIfAvailable(any())).thenReturn(serviceInstanceListSupplier);
+
+ when(routerAPI.processLoadBalance(any())).thenThrow(new PolarisException(ErrorCode.API_TIMEOUT));
+
+ // request construct and execute invoke
+ PolarisWeightedRandomLoadBalancer polarisWeightedRandomLoadBalancer = new PolarisWeightedRandomLoadBalancer(LOCAL_SERVICE, supplierObjectProvider, routerAPI);
+ Mono> responseMono = polarisWeightedRandomLoadBalancer.choose(request);
+ ServiceInstance serviceInstance = responseMono.block().getServer();
+
+ // verify method has invoked
+ verify(supplierObjectProvider).getIfAvailable(any());
+
+ //result assert
+ Assertions.assertThat(serviceInstance).isNull();
+ }
+
+ @Test
+ public void chooseEmptySupplierTest_thenReturnEmptyInstance() {
+ ServiceInstanceListSupplier noopSupplier = new NoopServiceInstanceListSupplier();
+ when(supplierObjectProvider.getIfAvailable(any())).thenReturn(noopSupplier);
+
+ // request construct and execute invoke
+ PolarisWeightedRandomLoadBalancer polarisWeightedRandomLoadBalancer = new PolarisWeightedRandomLoadBalancer(LOCAL_SERVICE, supplierObjectProvider, routerAPI);
+ Mono> responseMono = polarisWeightedRandomLoadBalancer.choose();
+ ServiceInstance serviceInstance = responseMono.block().getServer();
+
+ //result assert
+ Assertions.assertThat(serviceInstance).isNull();
+ }
+
}
diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancerTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancerTest.java
new file mode 100644
index 000000000..70d5726ea
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisWeightedRoundRobinLoadBalancerTest.java
@@ -0,0 +1,120 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ *
+ */
+
+package com.tencent.cloud.polaris.loadbalancer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.tencent.cloud.common.pojo.PolarisServiceInstance;
+import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
+import com.tencent.polaris.api.pojo.Instance;
+import com.tencent.polaris.router.api.core.RouterAPI;
+import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.Request;
+import org.springframework.cloud.client.loadbalancer.Response;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+
+import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_NAMESPACE;
+import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_SERVICE;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test for {@link PolarisWeightedRandomLoadBalancer}.
+ *
+ * @author veteranchen
+ */
+@ExtendWith(MockitoExtension.class)
+public class PolarisWeightedRoundRobinLoadBalancerTest {
+
+ private static MockedStatic mockedApplicationContextAwareUtils;
+ private static Instance testInstance;
+ @Mock
+ private RouterAPI routerAPI;
+ @Mock
+ private ObjectProvider supplierObjectProvider;
+
+ @BeforeAll
+ static void beforeAll() {
+ mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
+ mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
+ .thenReturn("unit-test");
+
+ testInstance = Instance.createDefaultInstance("instance-id", LOCAL_NAMESPACE,
+ LOCAL_SERVICE, "host", 8090);
+ }
+
+ @AfterAll
+ static void afterAll() {
+ mockedApplicationContextAwareUtils.close();
+ }
+
+ @Test
+ public void chooseNormalLogicTest_thenReturnAvailablePolarisInstance() {
+
+ Request request = Mockito.mock(Request.class);
+ List mockInstanceList = new ArrayList<>();
+ mockInstanceList.add(new PolarisServiceInstance(testInstance));
+
+ ServiceInstanceListSupplier serviceInstanceListSupplier = Mockito.mock(ServiceInstanceListSupplier.class);
+ when(serviceInstanceListSupplier.get(request)).thenReturn(Flux.just(mockInstanceList));
+
+ when(supplierObjectProvider.getIfAvailable(any())).thenReturn(serviceInstanceListSupplier);
+
+ ProcessLoadBalanceResponse mockLbRes = new ProcessLoadBalanceResponse(testInstance);
+ when(routerAPI.processLoadBalance(any())).thenReturn(mockLbRes);
+
+ // request construct and execute invoke
+ PolarisWeightedRoundRobinLoadBalancer polarisWeightedRoundRobinLoadBalancer = new PolarisWeightedRoundRobinLoadBalancer(LOCAL_SERVICE, supplierObjectProvider, routerAPI);
+ Mono> responseMono = polarisWeightedRoundRobinLoadBalancer.choose(request);
+ ServiceInstance serviceInstance = responseMono.block().getServer();
+
+ // verify method has invoked
+ verify(supplierObjectProvider).getIfAvailable(any());
+
+ //result assert
+ Assertions.assertThat(serviceInstance).isNotNull();
+ Assertions.assertThat(serviceInstance instanceof PolarisServiceInstance).isTrue();
+
+ PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance;
+
+ Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getId()).isEqualTo("instance-id");
+ Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getNamespace()).isEqualTo(LOCAL_NAMESPACE);
+ Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getService()).isEqualTo(LOCAL_SERVICE);
+ Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getHost()).isEqualTo("host");
+ Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getPort()).isEqualTo(8090);
+ }
+
+}