This is an automated email from the ASF dual-hosted git repository.
Aias00 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 2dff2730ff test (plugin-base) : cover routing predicate boundary
cases. (#7390)
2dff2730ff is described below
commit 2dff2730ff399635b2bc657e21a903f391fb9df8
Author: JerryčAI <[email protected]>
AuthorDate: Mon Oct 12 11:08:49 2026 +0800
test (plugin-base) : cover routing predicate boundary cases. (#7390)
---
.../base/condition/judge/PredicateJudgeTest.java | 153 +++++++++++++++++++++
1 file changed, 153 insertions(+)
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/condition/judge/PredicateJudgeTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/condition/judge/PredicateJudgeTest.java
new file mode 100644
index 0000000000..1195d15bd9
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/condition/judge/PredicateJudgeTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.plugin.base.condition.judge;
+
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.MockedStatic;
+
+import java.time.LocalDateTime;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.mockStatic;
+
+/**
+ * Direct tests for routing condition predicates and their boundary cases.
+ */
+class PredicateJudgeTest {
+
+ @ParameterizedTest
+ @MethodSource("stringCases")
+ void testStringPredicate(final PredicateJudge judge, final String
expectedValue, final String realData, final boolean matches) {
+ assertEquals(matches, judge.judge(condition(ParamTypeEnum.HEADER,
expectedValue), realData));
+ }
+
+ private static Stream<Arguments> stringCases() {
+ return Stream.of(
+ Arguments.of(new EqualsPredicateJudge(), " value ", "value",
true),
+ Arguments.of(new EqualsPredicateJudge(), "value", "Value",
false),
+ Arguments.of(new EqualsPredicateJudge(), "value", " value ",
false),
+ Arguments.of(new EqualsPredicateJudge(), " ", "", true),
+ Arguments.of(new ContainsPredicateJudge(), " value ",
"a-value-b", true),
+ Arguments.of(new ContainsPredicateJudge(), "value", "VALUE",
false),
+ Arguments.of(new ContainsPredicateJudge(), "value", "", false),
+ Arguments.of(new StartsWithPredicateJudge(), " api ",
"api/v1", true),
+ Arguments.of(new StartsWithPredicateJudge(), "api", "/api",
false),
+ Arguments.of(new StartsWithPredicateJudge(), "api", "API",
false),
+ Arguments.of(new EndsWithPredicateJudge(), " .json ",
"result.json", true),
+ Arguments.of(new EndsWithPredicateJudge(), ".json",
"result.json.gz", false),
+ Arguments.of(new EndsWithPredicateJudge(), ".json",
"result.JSON", false),
+ Arguments.of(new MatchPredicateJudge(), " api/* ",
"prefix-api/*-suffix", true),
+ Arguments.of(new MatchPredicateJudge(), "api/*", "api/users",
false),
+ Arguments.of(new ExcludePredicateJudge(), " api/* ",
"prefix-api/*-suffix", false),
+ Arguments.of(new ExcludePredicateJudge(), "api/*",
"api/users", true),
+ Arguments.of(new PathPatternPredicateJudge(), " api/* ",
"prefix-api/*-suffix", true),
+ Arguments.of(new PathPatternPredicateJudge(), "api/*",
"api/users", false));
+ }
+
+ @ParameterizedTest
+ @MethodSource("pathCases")
+ void testPathPredicate(final PredicateJudge judge, final String pattern,
final String path, final boolean matches) {
+ assertEquals(matches, judge.judge(condition(ParamTypeEnum.URI,
pattern), path));
+ }
+
+ private static Stream<Arguments> pathCases() {
+ return Stream.of(
+ Arguments.of(new MatchPredicateJudge(), " /api/* ",
"/api/users", true),
+ Arguments.of(new MatchPredicateJudge(), "/api/*",
"/api/users/1", false),
+ Arguments.of(new MatchPredicateJudge(), "/api/**",
"/api/users/1", true),
+ Arguments.of(new MatchPredicateJudge(), "/api/**",
"/other/api/users", false),
+ Arguments.of(new MatchPredicateJudge(), "/api/{id}",
"/api/42", true),
+ Arguments.of(new MatchPredicateJudge(), "/api/**/detail",
"/api/users/42/detail", true),
+ Arguments.of(new ExcludePredicateJudge(), " /api/* ",
"/api/users", false),
+ Arguments.of(new ExcludePredicateJudge(), "/api/*",
"/api/users/1", true),
+ Arguments.of(new ExcludePredicateJudge(), "/api/**",
"/api/users/1", false),
+ Arguments.of(new ExcludePredicateJudge(), "/api/**",
"/other/api/users", true),
+ Arguments.of(new PathPatternPredicateJudge(), " /api/* ",
"/api/users", true),
+ Arguments.of(new PathPatternPredicateJudge(), "/api/*",
"/api/users/1", false),
+ Arguments.of(new PathPatternPredicateJudge(), "/api/**",
"/api/users/1", true),
+ Arguments.of(new PathPatternPredicateJudge(), "/api/**",
"/other/api/users", false),
+ Arguments.of(new PathPatternPredicateJudge(), "/api/{id}",
"/api/42", true),
+ Arguments.of(new PathPatternPredicateJudge(), "/api/{id}",
"/api/42/detail", false));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"' /api/[0-9]+ ', /api/42, true", " /api/[0-9]+, /api/name,
false",
+ "/api/[0-9]+, /api/42/detail, false", "/api/[0-9]+, prefix/api/42,
false", "/api/[0-9]+, /API/42, false"})
+ void testRegexMatchesWholeValue(final String pattern, final String
realData, final boolean matches) {
+ assertEquals(matches, new
RegexPredicateJudge().judge(condition(ParamTypeEnum.URI, pattern), realData));
+ }
+
+ @ParameterizedTest
+ @NullAndEmptySource
+ @ValueSource(strings = {" ", " ", "\t", "\r\n"})
+ void testBlankPredicate(final String realData) {
+ assertTrue(new BlankPredicateJudge().judge(new ConditionData(),
realData));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"value", " value ", "0"})
+ void testBlankPredicateRejectsText(final String realData) {
+ assertFalse(new BlankPredicateJudge().judge(new ConditionData(),
realData));
+ }
+
+ @ParameterizedTest
+ @CsvSource({"2026-01-01 11:59:59, false, true", "2026-01-01 12:00:00,
false, false", "2026-01-01 12:00:01, true, false"})
+ void testNamedTimePredicate(final String realData, final boolean after,
final boolean before) {
+ ConditionData conditionData = condition(ParamTypeEnum.HEADER, "
2026-01-01 12:00:00 ");
+ conditionData.setParamName("request-time");
+ assertEquals(after, new
TimerAfterPredicateJudge().judge(conditionData, realData));
+ assertEquals(before, new
TimerBeforePredicateJudge().judge(conditionData, realData));
+ }
+
+ @ParameterizedTest
+ @NullAndEmptySource
+ void testUnnamedTimePredicateUsesCurrentTime(final String paramName) {
+ LocalDateTime now = LocalDateTime.of(2026, 1, 1, 12, 0);
+ ConditionData conditionData = condition(ParamTypeEnum.HEADER,
"2026-01-01 12:00:00");
+ conditionData.setParamName(paramName);
+ try (MockedStatic<LocalDateTime> time =
mockStatic(LocalDateTime.class, CALLS_REAL_METHODS)) {
+ time.when(LocalDateTime::now).thenReturn(now);
+ assertFalse(new TimerAfterPredicateJudge().judge(conditionData,
"ignored"));
+ assertFalse(new TimerBeforePredicateJudge().judge(conditionData,
"ignored"));
+ conditionData.setParamValue(" 2026-01-01 11:59:59 ");
+ assertTrue(new TimerAfterPredicateJudge().judge(conditionData,
"ignored"));
+ assertFalse(new TimerBeforePredicateJudge().judge(conditionData,
"ignored"));
+ conditionData.setParamValue(" 2026-01-01 12:00:01 ");
+ assertFalse(new TimerAfterPredicateJudge().judge(conditionData,
"ignored"));
+ assertTrue(new TimerBeforePredicateJudge().judge(conditionData,
"ignored"));
+ }
+ }
+
+ private static ConditionData condition(final ParamTypeEnum type, final
String value) {
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(type.getName());
+ conditionData.setParamValue(value);
+ return conditionData;
+ }
+}