This is an automated email from the ASF dual-hosted git repository.
yu199195 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 86e544b074 Stabilize Sentinel integrated rate-limit assertions (#6374)
86e544b074 is described below
commit 86e544b074b010eb787e1e062a4d7048461b10f3
Author: aias00 <[email protected]>
AuthorDate: Tue Jun 9 10:22:28 2026 +0800
Stabilize Sentinel integrated rate-limit assertions (#6374)
The HTTP integrated Sentinel tests used back-to-back requests to prove one
successful pass and one rate-limited response. On slow CI, sequential requests
can cross Sentinel's one-second QPS window, leaving the expected limited
response absent even though the gateway behavior is correct.
This changes the trigger to concurrent requests and asserts over the
observed result set, preserving the same behavior coverage while removing
timing dependence from the test.
Constraint: Failure appeared in the master push for #6361 in build
(shenyu-integrated-test-http), after Sentinel fallback coverage was added.
Rejected: Increase sleeps or timeouts | would make the timing window larger
without making the assertion deterministic.
Rejected: Change Sentinel production cleanup | the failing surface is the
test trigger timing, and production cleanup changes would broaden risk
unnecessarily.
Confidence: medium
Scope-risk: narrow
Directive: Keep Sentinel rate-limit integration assertions
concurrency-based; sequential requests can cross QPS windows on loaded runners.
Tested: ./mvnw -f shenyu-integrated-test/pom.xml -pl
shenyu-integrated-test-http -am -DskipTests test-compile
Tested: git diff --check
Not-tested: Full Docker integrated-test-http run locally; required CI
images and supporting services were not prebuilt locally.
---
.../test/http/combination/SentinelPluginTest.java | 60 +++++++++++++++++-----
1 file changed, 46 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 210b3a2bc0..521e3adfd5 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
@@ -36,12 +36,15 @@ import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public final class SentinelPluginTest extends AbstractPluginDataInit {
@@ -57,34 +60,63 @@ public final class SentinelPluginTest extends
AbstractPluginDataInit {
}
@Test
- public void test() throws IOException {
+ public void test() throws IOException, ExecutionException,
InterruptedException {
String selectorAndRulesResult =
initSelectorAndRules(PluginEnum.SENTINEL.getName(), "",
buildSelectorConditionList(), buildRuleLocalDataList(null));
assertThat(selectorAndRulesResult, is("success"));
Type returnType = new TypeToken<Map<String, Object>>() {
}.getType();
- Map<String, Object> result =
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType);
- assertNotNull(result);
- assertEquals("pass", result.get("msg"));
- result = HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH,
returnType);
- assertEquals("You have been restricted, please try again later!",
result.get("message"));
+ 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);
+ assertThat(messages.contains("pass"), is(true));
+ assertThat(messages.contains("You have been restricted, please try
again later!"), is(true));
}
@Test
- public void testFallbackUri() throws IOException {
+ public void testFallbackUri() throws IOException, ExecutionException,
InterruptedException {
String selectorAndRulesResult =
initSelectorAndRules(PluginEnum.SENTINEL.getName(), "",
buildSelectorConditionList(),
buildRuleLocalDataList(TEST_SENTINEL_FALLBACK_PATH));
assertThat(selectorAndRulesResult, is("success"));
Type returnType = new TypeToken<Map<String, Object>>() {
}.getType();
- Map<String, Object> result =
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType);
- assertNotNull(result);
- assertEquals("pass", result.get("msg"));
- Map<String, Object> fallbackRet =
HttpHelper.INSTANCE.postGateway(TEST_SENTINEL_PATH, returnType);
- assertEquals(ShenyuResultEnum.SENTINEL_PLUGIN_FALLBACK.getCode(),
((Number) fallbackRet.get("code")).intValue());
- assertEquals(ShenyuResultEnum.SENTINEL_PLUGIN_FALLBACK.getMsg(),
fallbackRet.get("message"));
+ 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);
+ 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) {
+ Set<String> messages = new HashSet<>();
+ for (Map<String, Object> result : results) {
+ assertNotNull(result);
+ Object msg = result.containsKey("msg") ? result.get("msg") :
result.get("message");
+ if (msg instanceof String) {
+ messages.add((String) msg);
+ }
+ }
+ return messages;
+ }
+
+ private static Set<Integer> toCodes(final Map<String, Object>... results) {
+ Set<Integer> codes = new HashSet<>();
+ for (Map<String, Object> result : results) {
+ assertNotNull(result);
+ Object code = result.get("code");
+ if (code instanceof Number) {
+ codes.add(((Number) code).intValue());
+ }
+ }
+ return codes;
}
private static List<ConditionData> buildSelectorConditionList() {