This is an automated email from the ASF dual-hosted git repository.

xiaoyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 1363524ad add p2cLoadBalancer (#4451)
1363524ad is described below

commit 1363524ad4a53b8f9c9f75a611ce1dae7c0eb8ee
Author: SeaChess <[email protected]>
AuthorDate: Thu Mar 9 18:03:22 2023 +0800

    add p2cLoadBalancer (#4451)
    
    Co-authored-by: xiaoyu <[email protected]>
---
 db/init/mysql/schema.sql                           |   1 +
 db/init/oracle/schema.sql                          |   3 +
 db/init/pg/create-table.sql                        |   1 +
 .../src/main/resources/sql-script/h2/schema.sql    |   1 +
 .../shenyu/common/enums/LoadBalanceEnum.java       |   7 +-
 .../shenyu/loadbalancer/entity/Upstream.java       |  95 ++++++++++++++++
 .../shenyu/loadbalancer/spi/P2cLoadBalancer.java   | 121 +++++++++++++++++++++
 ...org.apache.shenyu.loadbalancer.spi.LoadBalancer |   1 +
 .../loadbalancer/spi/P2cLoadBalancerTest.java      |  65 +++++++++++
 .../apache/shenyu/plugin/divide/DividePlugin.java  |  28 ++++-
 .../shenyu/plugin/divide/DividePluginTest.java     |  20 +++-
 11 files changed, 339 insertions(+), 4 deletions(-)

diff --git a/db/init/mysql/schema.sql b/db/init/mysql/schema.sql
index 1b6e693fe..94678e48e 100644
--- a/db/init/mysql/schema.sql
+++ b/db/init/mysql/schema.sql
@@ -1704,6 +1704,7 @@ INSERT INTO `shenyu_dict` VALUES ('1529402613195784193', 
'loadBalance', 'LOAD_BA
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784194', 'loadBalance', 
'LOAD_BALANCE', 'random', 'random', 'random', 1, 1, '2022-05-25 18:02:52', 
'2022-05-25 18:02:52');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784195', 'loadBalance', 
'LOAD_BALANCE', 'hash', 'hash', 'hash', 0, 1, '2022-05-25 18:02:52', 
'2022-05-25 18:02:52');
 INSERT INTO `shenyu_dict` VALUES ('1572621976689762307', 'loadBalance', 
'LOAD_BALANCE', 'leastActive', 'leastActive', 'leastActive', 3, 1, '2023-01-17 
18:02:52', '2023-01-17 18:02:52');
+INSERT INTO `shenyu_dict` VALUES ('1572621976689762308', 'loadBalance', 
'LOAD_BALANCE', 'p2c', 'p2c', 'p2c', 4, 1, '2023-03-07 22:12:12', '2023-03-07 
22:12:12');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784196', 'status', 
'DIVIDE_STATUS', 'close', 'false', 'close', 1, 1, '2022-05-25 18:02:52', 
'2022-05-25 18:02:52');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784197', 'status', 
'DIVIDE_STATUS', 'open', 'true', 'open', 0, 1, '2022-05-25 18:02:52', 
'2022-05-25 18:02:52');
 INSERT INTO `shenyu_dict` VALUES ('1529402613195784198', 'multiRuleHandle', 
'MULTI_RULE_HANDLE', 'multiple rule', '1', 'multiple rule', 1, 1, '2022-05-25 
18:02:52', '2022-05-25 18:02:52');
diff --git a/db/init/oracle/schema.sql b/db/init/oracle/schema.sql
index 12e724e05..0bec3c5f3 100644
--- a/db/init/oracle/schema.sql
+++ b/db/init/oracle/schema.sql
@@ -1087,6 +1087,9 @@ VALUES ('1545812228228259842', 'engine', 'engine', 
'MergeTree', 'MergeTree', '',
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ INTO SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
 VALUES ('1545812228228259843', 'loadBalance', 'LOAD_BALANCE', 'leastActive', 
'leastActive', 'leastActive', 3, 1);
 
+INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(shenyu_dict(type, dict_code, dict_name)) 
*/ INTO SHENYU_DICT (ID, TYPE, DICT_CODE, DICT_NAME, DICT_VALUE, "desc", SORT, 
ENABLED)
+VALUES ('1545812228228259844', 'loadBalance', 'LOAD_BALANCE', 'p2c', 'p2c', 
'p2c', 4, 1);
+
 
 /*plugin*/
 INSERT /*+ IGNORE_ROW_ON_DUPKEY_INDEX(plugin(id)) */ INTO plugin (id, name, 
role, sort, enabled) VALUES ('1','sign','Authentication',  20, '0', null);
diff --git a/db/init/pg/create-table.sql b/db/init/pg/create-table.sql
index f391b1024..6e5f8a170 100644
--- a/db/init/pg/create-table.sql
+++ b/db/init/pg/create-table.sql
@@ -2003,6 +2003,7 @@ INSERT INTO "public"."shenyu_dict" VALUES 
('1572621976689762306', 'engine', 'eng
 INSERT INTO "public"."shenyu_dict" VALUES ('1572621976689762307', 
'loadBalance', 'LOAD_BALANCE', 'leastActive', 'leastActive', 'leastActive', 3, 
1, '2023-01-17 18:02:52.924', '2023-01-17 18:02:52.924');
 INSERT INTO "public"."shenyu_dict" VALUES ('1630761573833920512', 'mapType', 
'mapType', 'all', 'all', '', 1, 1, '2023-03-01 10:47:11', '2023-03-01 
10:47:11');
 INSERT INTO "public"."shenyu_dict" VALUES ('1630761984393367552', 'mapType', 
'mapType', 'field', 'field', '', 1, 1, '2023-03-01 10:48:49', '2023-03-01 
10:48:49');
+INSERT INTO "public"."shenyu_dict" VALUES ('1572621976689762308', 
'loadBalance', 'LOAD_BALANCE', 'p2c', 'p2c', 'p2c', 4, 1, '2023-03-07 
22:15:16.846', '2023-03-07 22:15:16.846');
 
 -- ----------------------------
 -- Table structure for user_role
diff --git a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql 
b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
index 84c024835..3411f9c84 100755
--- a/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
+++ b/shenyu-admin/src/main/resources/sql-script/h2/schema.sql
@@ -500,6 +500,7 @@ INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, 
`dict_name`, `dict_v
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1572621976689762307', 
'loadBalance', 'LOAD_BALANCE', 'leastActive', 'leastActive', 'leastActive', 0, 
1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1630761573833920512', 
'mapType', 'mapType', 'all', 'all', '', 0, 1);
 INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1630761984393367552', 
'mapType', 'mapType', 'field', 'field', '', 1, 1);
+INSERT IGNORE INTO `shenyu_dict` (`id`, `type`,`dict_code`, `dict_name`, 
`dict_value`, `desc`, `sort`, `enabled`) VALUES ('1572621976689762308', 
'loadBalance', 'LOAD_BALANCE', 'p2c', 'p2c', 'p2c', 0, 1);
 
 /*plugin*/
 INSERT IGNORE INTO `plugin` (`id`, `name`, `role`, `sort`, `enabled`) VALUES 
('1','sign','Authentication',  20, '0');
diff --git 
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/LoadBalanceEnum.java
 
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/LoadBalanceEnum.java
index 82ce53059..657882843 100644
--- 
a/shenyu-common/src/main/java/org/apache/shenyu/common/enums/LoadBalanceEnum.java
+++ 
b/shenyu-common/src/main/java/org/apache/shenyu/common/enums/LoadBalanceEnum.java
@@ -40,7 +40,12 @@ public enum LoadBalanceEnum {
     /**
      * least activity load balance enum.
      */
-    LEAST_ACTIVITY(4, "leastActive", true);
+    LEAST_ACTIVITY(4, "leastActive", true),
+
+    /**
+     * pick of 2 choices load balance enum.
+     */
+    P2C(5, "p2c", true);
 
     private final int code;
 
diff --git 
a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java
 
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java
index 6a5827e3d..090bca801 100644
--- 
a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java
+++ 
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/Upstream.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.loadbalancer.entity;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  * this is upstream.
@@ -81,6 +82,26 @@ public final class Upstream {
      */
     private String version;
 
+    /**
+     * ewma value.
+     */
+    private long lag;
+
+    /**
+     * response stamp.
+     */
+    private long responseStamp;
+
+    /**
+     * Last selected timestamp.
+     */
+    private long lastPicked;
+
+    /**
+     * Total number of requests being processed.
+     */
+    private AtomicLong inflight = new AtomicLong(1);
+
     private Upstream(final Builder builder) {
         this.protocol = builder.protocol;
         this.url = builder.url;
@@ -254,6 +275,80 @@ public final class Upstream {
         this.version = version;
     }
 
+    /**
+     * Gets lag.
+     *
+     * @return the lag
+     */
+    public long getLag() {
+        return lag;
+    }
+
+    /**
+     * Sets lag.
+     * @param lag the lag
+     */
+    public void setLag(final long lag) {
+        this.lag = lag;
+    }
+
+    /**
+     * Gets inflight.
+     *
+     * @return the inflight
+     */
+
+    /**
+     * Gets responseStamp.
+     *
+     * @return the responseStamp
+     */
+    public long getResponseStamp() {
+        return responseStamp;
+    }
+
+    /**
+     * Sets responseStamp.
+     * @param responseStamp the responseStamp
+     */
+    public void setResponseStamp(final long responseStamp) {
+        this.responseStamp = responseStamp;
+    }
+
+    /**
+     * Gets lastPickedStamp.
+     *
+     * @return the lastPickedStamp
+     */
+    public long getLastPicked() {
+        return lastPicked;
+    }
+
+    /**
+     * Sets lastPickedStamp.
+     * @param lastPicked the lastPickedStamp
+     */
+    public void setLastPicked(final long lastPicked) {
+        this.lastPicked = lastPicked;
+    }
+
+    /**
+     * Gets inflight.
+     *
+     * @return the inflight
+     */
+    public AtomicLong getInflight() {
+        return inflight;
+    }
+
+    /**
+     * Sets inflight.
+     * @param inflight the inflight
+     */
+    public void setInflight(final AtomicLong inflight) {
+        this.inflight = inflight;
+    }
+
     /**
      * build request domain.
      *
diff --git 
a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancer.java
 
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancer.java
new file mode 100644
index 000000000..c3dfc1f07
--- /dev/null
+++ 
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancer.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.shenyu.loadbalancer.spi;
+
+import org.apache.shenyu.loadbalancer.entity.Upstream;
+import org.apache.shenyu.spi.Join;
+
+import java.util.List;
+import java.util.Random;
+
+/**
+ * p2c algorithm impl.
+ */
+@Join
+public class P2cLoadBalancer extends AbstractLoadBalancer {
+
+    /**
+     * maximum tolerance of idle time.
+     */
+    private static final int FORCE_GAP = 3 * 1000;
+
+    /**
+     * penalty value.
+     */
+    private static final int PENALTY = 250 * 1000;
+
+    /**
+     * pick times.
+     */
+    private static final int PICK_TIMES = 3;
+
+    private Random random = new Random();
+
+    /**
+     * pick of 2 choices to select upstream.
+     *
+     * @param upstreamList the upstream list
+     * @param ip           the ip
+     * @return selected upstream
+     */
+    @Override
+    protected Upstream doSelect(final List<Upstream> upstreamList, final 
String ip) {
+        long start = System.currentTimeMillis();
+        Upstream[] upstreams = pickTwoUpstreams(upstreamList);
+        Upstream picked;
+        Upstream unpicked;
+        if (load(upstreams[0]) > load(upstreams[1])) {
+            picked = upstreams[1];
+            unpicked = upstreams[0];
+        } else {
+            picked = upstreams[0];
+            unpicked = upstreams[1];
+        }
+        // If the failed node is not selected once in the forceGap period, it 
is forced to be selected once.
+        long pick = unpicked.getLastPicked();
+        if ((start - pick) > FORCE_GAP) {
+            unpicked.setLastPicked(start);
+            picked = unpicked;
+        }
+
+        if (picked != unpicked) {
+            picked.setLastPicked(start);
+        }
+        picked.getInflight().incrementAndGet();
+        return picked;
+    }
+
+    /**
+     * select two nodes randomly.
+     *
+     * @param upstreamList the upstream list
+     * @return two upstream
+     */
+    private Upstream[] pickTwoUpstreams(final List<Upstream> upstreamList) {
+        Upstream[] upstreams = new Upstream[2];
+        for (int i = 0; i < PICK_TIMES; i++) {
+            int a = random.nextInt(upstreamList.size());
+            int b = random.nextInt(upstreamList.size() - 1);
+            // prevent random nodes from being the same.
+            if (b >= a) {
+                b += 1;
+            }
+            upstreams[0] = upstreamList.get(a);
+            upstreams[1] = upstreamList.get(b);
+            if (upstreams[0].isHealthy() && upstreams[1].isHealthy()) {
+                break;
+            }
+        }
+        return upstreams;
+    }
+
+    /**
+     * calculate load.
+     *
+     * @param upstream the upstream
+     * @return load
+     */
+    public long load(final Upstream upstream) {
+        long lag = (long) (Math.sqrt((double) upstream.getLag()) + 1);
+        long load = lag * upstream.getInflight().get();
+        if (load == 0) {
+            load = PENALTY;
+        }
+        return load;
+    }
+}
diff --git 
a/shenyu-loadbalancer/src/main/resources/META-INF/shenyu/org.apache.shenyu.loadbalancer.spi.LoadBalancer
 
b/shenyu-loadbalancer/src/main/resources/META-INF/shenyu/org.apache.shenyu.loadbalancer.spi.LoadBalancer
index e74332f0c..12e623900 100644
--- 
a/shenyu-loadbalancer/src/main/resources/META-INF/shenyu/org.apache.shenyu.loadbalancer.spi.LoadBalancer
+++ 
b/shenyu-loadbalancer/src/main/resources/META-INF/shenyu/org.apache.shenyu.loadbalancer.spi.LoadBalancer
@@ -17,3 +17,4 @@ random=org.apache.shenyu.loadbalancer.spi.RandomLoadBalancer
 roundRobin=org.apache.shenyu.loadbalancer.spi.RoundRobinLoadBalancer
 hash=org.apache.shenyu.loadbalancer.spi.HashLoadBalancer
 leastActive=org.apache.shenyu.loadbalancer.spi.LeastActiveLoadBalance
+p2c=org.apache.shenyu.loadbalancer.spi.P2cLoadBalancer
\ No newline at end of file
diff --git 
a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancerTest.java
 
b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancerTest.java
new file mode 100644
index 000000000..fcd98f59c
--- /dev/null
+++ 
b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/spi/P2cLoadBalancerTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 org.apache.shenyu.loadbalancer.spi;
+
+import org.apache.shenyu.loadbalancer.entity.Upstream;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class P2cLoadBalancerTest {
+    private final List<Upstream> upstreamList = new ArrayList<>();
+
+    /**
+     * build upstream list.
+     */
+    public void buildUpstreamList() {
+        Upstream upstream1 = Upstream.builder()
+                .url("baidu.com")
+                .protocol("https://";)
+                .build();
+        Upstream upstream2 = Upstream.builder()
+                .url("pro.jd.com")
+                .protocol("https://";)
+                .build();
+        upstreamList.add(upstream1);
+        upstreamList.add(upstream2);
+    }
+
+    @Test
+    public void testResponseTimeBalancerSameLag() {
+        buildUpstreamList();
+        final P2cLoadBalancer p2cLoadBalancer = new P2cLoadBalancer();
+        Upstream upstream = p2cLoadBalancer.doSelect(upstreamList, 
"localhost");
+        Upstream upstream1 = p2cLoadBalancer.doSelect(upstreamList, 
"localhost");
+        Assertions.assertTrue((upstream.getUrl().equals("baidu.com") && 
upstream1.getUrl().equals("pro.jd.com"))
+                || upstream1.getUrl().equals("baidu.com") && 
upstream.getUrl().equals("pro.jd.com"));
+    }
+
+    @Test
+    public void testResponseTimeBalancerSameInflight() {
+        buildUpstreamList();
+        final P2cLoadBalancer p2cLoadBalancer = new P2cLoadBalancer();
+        upstreamList.get(0).setLag(1);
+        Upstream upstream = p2cLoadBalancer.doSelect(upstreamList, 
"localhost");
+        Upstream upstream1 = p2cLoadBalancer.doSelect(upstreamList, 
"localhost");
+        Assertions.assertTrue(upstream.getUrl().equals("baidu.com") && 
upstream1.getUrl().equals("pro.jd.com"));
+    }
+}
diff --git 
a/shenyu-plugin/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
 
b/shenyu-plugin/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
index 1cf21eada..091bc8407 100644
--- 
a/shenyu-plugin/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-divide/src/main/java/org/apache/shenyu/plugin/divide/DividePlugin.java
@@ -54,6 +54,8 @@ import java.util.Objects;
 public class DividePlugin extends AbstractShenyuPlugin {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(DividePlugin.class);
+
+    private static final String P2C = "p2c";
     
     private final DivideRuleHandle defaultRuleHandle = new DivideRuleHandle();
 
@@ -108,7 +110,8 @@ public class DividePlugin extends AbstractShenyuPlugin {
         exchange.getAttributes().put(Constants.RETRY_STRATEGY, 
StringUtils.defaultString(ruleHandle.getRetryStrategy(), 
RetryEnum.CURRENT.getName()));
         exchange.getAttributes().put(Constants.LOAD_BALANCE, 
StringUtils.defaultString(ruleHandle.getLoadBalance(), 
LoadBalanceEnum.RANDOM.getName()));
         exchange.getAttributes().put(Constants.DIVIDE_SELECTOR_ID, 
selector.getId());
-        return chain.execute(exchange);
+        return ruleHandle.getLoadBalance().equals(P2C) ? 
chain.execute(exchange).doOnSuccess(e -> responseTrigger(upstream
+        )).doOnError(throwable -> responseTrigger(upstream)) : 
chain.execute(exchange);
     }
 
     @Override
@@ -143,4 +146,27 @@ public class DividePlugin extends AbstractShenyuPlugin {
             return defaultRuleHandle;
         }
     }
+
+    private void responseTrigger(final Upstream upstream) {
+        long now = System.currentTimeMillis();
+        upstream.getInflight().decrementAndGet();
+        upstream.setResponseStamp(now);
+        long stamp = upstream.getResponseStamp();
+        long td = now - stamp;
+        if (td < 0) {
+            td = 0;
+        }
+        double w = Math.exp((double) -td / (double) 600);
+
+        long lag = now - upstream.getLastPicked();
+        if (lag < 0) {
+            lag = 0;
+        }
+        long oldLag = upstream.getLag();
+        if (oldLag == 0) {
+            w = 0;
+        }
+        lag = (int) ((double) oldLag * w + (double) lag * (1.0 - w));
+        upstream.setLag(lag);
+    }
 }
diff --git 
a/shenyu-plugin/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
 
b/shenyu-plugin/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
index b4a43af35..92e5a7614 100644
--- 
a/shenyu-plugin/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-divide/src/test/java/org/apache/shenyu/plugin/divide/DividePluginTest.java
@@ -27,6 +27,7 @@ import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.common.utils.GsonUtils;
 import org.apache.shenyu.common.utils.UpstreamCheckUtils;
 import org.apache.shenyu.loadbalancer.cache.UpstreamCacheManager;
+import org.apache.shenyu.loadbalancer.entity.Upstream;
 import org.apache.shenyu.loadbalancer.factory.LoadBalancerFactory;
 import org.apache.shenyu.plugin.api.ShenyuPluginChain;
 import org.apache.shenyu.plugin.api.context.ShenyuContext;
@@ -50,17 +51,20 @@ import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.InetSocketAddress;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
 import static org.mockito.Mockito.when;
@@ -206,6 +210,18 @@ public final class DividePluginTest {
         assertEquals(PluginEnum.DIVIDE.getCode(), dividePlugin.getOrder());
     }
 
+    @Test
+    public void responseTriggerTest() throws NoSuchMethodException, 
InstantiationException, IllegalAccessException, InvocationTargetException {
+        Upstream upstream = Upstream.builder()
+                .url("upstream")
+                .build();
+        assertEquals(0, upstream.getLag());
+        Method method = 
DividePlugin.class.getDeclaredMethod("responseTrigger", Upstream.class);
+        method.setAccessible(true);
+        method.invoke(DividePlugin.class.newInstance(), upstream);
+        assertNotEquals(0, upstream.getLag());
+    }
+
     /**
      * Init mock info.
      */

Reply via email to