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

tuohai666 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 d17b29d42d Stabilize Sentinel CI assertion for PR 6375 (#6377)
d17b29d42d is described below

commit d17b29d42da729e1e5a8691c3fa19739b30811fb
Author: aias00 <[email protected]>
AuthorDate: Wed Jun 10 21:31:38 2026 +0800

    Stabilize Sentinel CI assertion for PR 6375 (#6377)
    
    The failed Actions job showed both concurrent Sentinel requests returning 
pass, which made the test depend on a two-request race landing inside an 
initialized rate-limit window. The test now sends a small bounded burst and 
retries briefly until it observes both the allowed response and the expected 
Sentinel rejection or fallback response.
    
    Constraint: GitHub Actions job 80239368085 failed in 
shenyu-integrated-test-http at SentinelPluginTest.test:76
    
    Rejected: Increase the assertion timeout with two requests | still depends 
on the same first-window race
    
    Rejected: Change Sentinel production configuration | failure is a test 
timing assumption, not a production behavior regression
    
    Confidence: high
    
    Scope-risk: narrow
    
    Directive: Keep this test asserting both pass and limited responses, but 
avoid exact request-count assumptions around Sentinel windows
    
    Tested: ./mvnw -f ./shenyu-integrated-test/pom.xml -pl 
shenyu-integrated-test-http -am -Pit -DskipTests test-compile
    
    Tested: ./mvnw -pl shenyu-plugin/shenyu-plugin-request 
-Dtest=org.apache.shenyu.plugin.request.RequestPluginTest test
    
    Tested: git diff --check
    
    Not-tested: Full Docker Compose shenyu-integrated-test-http run; local 
machine lacks most required CI service images
---
 .../test/http/combination/SentinelPluginTest.java  | 64 +++++++++++++++++-----
 1 file changed, 50 insertions(+), 14 deletions(-)

diff --git 
a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SentinelPluginTest.java
 
b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SentinelPluginTest.java
index 521e3adfd5..bdf78a6441 100644
--- 
a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SentinelPluginTest.java
+++ 
b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/SentinelPluginTest.java
@@ -35,6 +35,8 @@ import org.junit.jupiter.api.Test;
 
 import java.io.IOException;
 import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -49,10 +51,18 @@ import static 
org.junit.jupiter.api.Assertions.assertNotNull;
 
 public final class SentinelPluginTest extends AbstractPluginDataInit {
 
+    private static final int SENTINEL_REQUEST_BURST_SIZE = 6;
+
+    private static final int SENTINEL_REQUEST_ATTEMPTS = 5;
+
+    private static final long SENTINEL_REQUEST_ATTEMPT_INTERVAL_MILLIS = 200L;
+
     private static final String TEST_SENTINEL_PATH = 
"/http/test/sentinel/pass";
 
     private static final String TEST_SENTINEL_FALLBACK_PATH = 
"fallback:/fallback/sentinel";
 
+    private static final String TEST_SENTINEL_RESTRICTED_MESSAGE = "You have 
been restricted, please try again later!";
+
     @BeforeEach
     public void setup() throws IOException {
         String pluginResult = initPlugin(PluginEnum.SENTINEL.getName(), 
"{\"model\":\"black\"}");
@@ -67,13 +77,9 @@ public final class SentinelPluginTest extends 
AbstractPluginDataInit {
 
         Type returnType = new TypeToken<Map<String, Object>>() {
         }.getType();
-        Future<Map<String, Object>> first = this.getService().submit(() -> 
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType));
-        Future<Map<String, Object>> second = this.getService().submit(() -> 
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType));
-        Map<String, Object> firstResult = first.get();
-        Map<String, Object> secondResult = second.get();
-        Set<String> messages = toMessages(firstResult, secondResult);
+        Set<String> messages = collectMessagesUntil(returnType, "pass", 
TEST_SENTINEL_RESTRICTED_MESSAGE);
         assertThat(messages.contains("pass"), is(true));
-        assertThat(messages.contains("You have been restricted, please try 
again later!"), is(true));
+        assertThat(messages.contains(TEST_SENTINEL_RESTRICTED_MESSAGE), 
is(true));
     }
 
     @Test
@@ -84,18 +90,48 @@ public final class SentinelPluginTest extends 
AbstractPluginDataInit {
 
         Type returnType = new TypeToken<Map<String, Object>>() {
         }.getType();
-        Future<Map<String, Object>> first = this.getService().submit(() -> 
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType));
-        Future<Map<String, Object>> second = this.getService().submit(() -> 
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType));
-        Map<String, Object> firstResult = first.get();
-        Map<String, Object> secondResult = second.get();
-        Set<String> messages = toMessages(firstResult, secondResult);
-        Set<Integer> codes = toCodes(firstResult, secondResult);
+        List<Map<String, Object>> results = collectResultsUntil(returnType, 
"pass", ShenyuResultEnum.SENTINEL_PLUGIN_FALLBACK.getMsg());
+        Set<String> messages = toMessages(results);
+        Set<Integer> codes = toCodes(results);
         assertThat(messages.contains("pass"), is(true));
         
assertThat(codes.contains(ShenyuResultEnum.SENTINEL_PLUGIN_FALLBACK.getCode()), 
is(true));
         
assertThat(messages.contains(ShenyuResultEnum.SENTINEL_PLUGIN_FALLBACK.getMsg()),
 is(true));
     }
 
-    private static Set<String> toMessages(final Map<String, Object>... 
results) {
+    private List<Map<String, Object>> collectResultsUntil(final Type 
returnType,
+                                                          final String... 
expectedMessages)
+            throws ExecutionException, InterruptedException {
+        List<Map<String, Object>> results = new ArrayList<>();
+        Set<String> expected = new HashSet<>(Arrays.asList(expectedMessages));
+        for (int attempt = 0; attempt < SENTINEL_REQUEST_ATTEMPTS; attempt++) {
+            results.addAll(postSentinelRequestBurst(returnType));
+            if (toMessages(results).containsAll(expected)) {
+                return results;
+            }
+            Thread.sleep(SENTINEL_REQUEST_ATTEMPT_INTERVAL_MILLIS);
+        }
+        return results;
+    }
+
+    private Set<String> collectMessagesUntil(final Type returnType, final 
String... expectedMessages)
+            throws ExecutionException, InterruptedException {
+        return toMessages(collectResultsUntil(returnType, expectedMessages));
+    }
+
+    private List<Map<String, Object>> postSentinelRequestBurst(final Type 
returnType)
+            throws ExecutionException, InterruptedException {
+        List<Future<Map<String, Object>>> futures = new ArrayList<>();
+        for (int i = 0; i < SENTINEL_REQUEST_BURST_SIZE; i++) {
+            futures.add(this.getService().submit(() -> 
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType)));
+        }
+        List<Map<String, Object>> results = new ArrayList<>();
+        for (Future<Map<String, Object>> future : futures) {
+            results.add(future.get());
+        }
+        return results;
+    }
+
+    private static Set<String> toMessages(final List<Map<String, Object>> 
results) {
         Set<String> messages = new HashSet<>();
         for (Map<String, Object> result : results) {
             assertNotNull(result);
@@ -107,7 +143,7 @@ public final class SentinelPluginTest extends 
AbstractPluginDataInit {
         return messages;
     }
 
-    private static Set<Integer> toCodes(final Map<String, Object>... results) {
+    private static Set<Integer> toCodes(final List<Map<String, Object>> 
results) {
         Set<Integer> codes = new HashSet<>();
         for (Map<String, Object> result : results) {
             assertNotNull(result);

Reply via email to