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 d0a0ddd2ab feature (plugin-mock) : support form request body
expressions. (#7394)
d0a0ddd2ab is described below
commit d0a0ddd2abc713f92be81f6a68320c4bad6fc682
Author: Jerry聊AI <[email protected]>
AuthorDate: Thu Oct 1 20:45:26 2026 +0800
feature (plugin-mock) : support form request body expressions. (#7394)
---
.../apache/shenyu/plugin/mock/api/MockRequest.java | 28 +++++++-
.../shenyu/plugin/mock/api/MockRequestTest.java | 79 ++++++++++++++++++++++
.../mock/generator/ExpressionGeneratorTest.java | 10 +++
3 files changed, 114 insertions(+), 3 deletions(-)
diff --git
a/shenyu-plugin/shenyu-plugin-mock/src/main/java/org/apache/shenyu/plugin/mock/api/MockRequest.java
b/shenyu-plugin/shenyu-plugin-mock/src/main/java/org/apache/shenyu/plugin/mock/api/MockRequest.java
index 0543e2f661..c38ffec367 100644
---
a/shenyu-plugin/shenyu-plugin-mock/src/main/java/org/apache/shenyu/plugin/mock/api/MockRequest.java
+++
b/shenyu-plugin/shenyu-plugin-mock/src/main/java/org/apache/shenyu/plugin/mock/api/MockRequest.java
@@ -19,6 +19,9 @@ package org.apache.shenyu.plugin.mock.api;
import org.apache.shenyu.common.utils.JsonUtils;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@@ -36,6 +39,8 @@ public final class MockRequest {
private Object json;
+ private Map<String, String> forms;
+
private MockRequest() {
}
@@ -88,13 +93,30 @@ public final class MockRequest {
}
/**
- * Gets form-body,not support now.
+ * Gets form-body.
*
* @return form-body
*/
public Map<String, String> getForms() {
- //todo
- throw new UnsupportedOperationException();
+ if (Objects.isNull(forms)) {
+ Map<String, String> parsedForms = new LinkedHashMap<>();
+ if (Objects.nonNull(body) && body.length > 0) {
+ String formBody = new String(body, StandardCharsets.UTF_8);
+ for (String pair : formBody.split("&")) {
+ if (pair.isEmpty()) {
+ continue;
+ }
+ int separator = pair.indexOf('=');
+ String encodedName = separator < 0 ? pair :
pair.substring(0, separator);
+ String encodedValue = separator < 0 ? "" :
pair.substring(separator + 1);
+ String name = URLDecoder.decode(encodedName,
StandardCharsets.UTF_8);
+ String value = URLDecoder.decode(encodedValue,
StandardCharsets.UTF_8);
+ parsedForms.putIfAbsent(name, value);
+ }
+ }
+ forms = parsedForms;
+ }
+ return forms;
}
/**
diff --git
a/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/api/MockRequestTest.java
b/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/api/MockRequestTest.java
new file mode 100644
index 0000000000..887fd88c13
--- /dev/null
+++
b/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/api/MockRequestTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.mock.api;
+
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Tests for {@link MockRequest}.
+ */
+public final class MockRequestTest {
+
+ @Test
+ public void testGetFormsDecodesUtf8FormBody() {
+ MockRequest request =
request("name=shenyu&message=hello+world&city=%E5%8C%97%E4%BA%AC&plus=%2B");
+
+ Map<String, String> forms = request.getForms();
+
+ assertEquals("shenyu", forms.get("name"));
+ assertEquals("hello world", forms.get("message"));
+ assertEquals("北京", forms.get("city"));
+ assertEquals("+", forms.get("plus"));
+ }
+
+ @Test
+ public void testGetFormsUsesFirstValueForDuplicateKeys() {
+ MockRequest request = request("name=first&name=second");
+
+ assertEquals("first", request.getForms().get("name"));
+ }
+
+ @Test
+ public void testGetFormsReturnsEmptyMapForEmptyOrMissingBody() {
+ MockRequest emptyBodyRequest = request("");
+ MockRequest missingBodyRequest = MockRequest.Builder.builder().build();
+
+ assertEquals(Map.of(), emptyBodyRequest.getForms());
+ assertEquals(Map.of(), missingBodyRequest.getForms());
+ }
+
+ @Test
+ public void testGetFormsCachesParsedMap() {
+ MockRequest request = request("name=shenyu");
+
+ assertSame(request.getForms(), request.getForms());
+ }
+
+ @Test
+ public void testGetFormsRejectsMalformedPercentEncoding() {
+ MockRequest request = request("name=%XX");
+
+ assertThrows(IllegalArgumentException.class, request::getForms);
+ }
+
+ private MockRequest request(final String body) {
+ return
MockRequest.Builder.builder().body(body.getBytes(StandardCharsets.UTF_8)).build();
+ }
+}
diff --git
a/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/generator/ExpressionGeneratorTest.java
b/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/generator/ExpressionGeneratorTest.java
index 4ef032b6b5..89583a4ce4 100644
---
a/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/generator/ExpressionGeneratorTest.java
+++
b/shenyu-plugin/shenyu-plugin-mock/src/test/java/org/apache/shenyu/plugin/mock/generator/ExpressionGeneratorTest.java
@@ -189,6 +189,16 @@ public class ExpressionGeneratorTest {
is("\"CHINA\""));
}
+ @Test
+ public void testGenerateDataFromUrlEncodedForm() {
+ MockRequest formRequest = MockRequest.Builder.builder()
+
.body("name=shenyu&message=hello+world".getBytes(StandardCharsets.UTF_8))
+ .build();
+
+ assertThat(generator.generate("expression|#req.forms['name']",
formRequest), is("\"shenyu\""));
+ assertThat(generator.generate("expression|#req.forms.message",
formRequest), is("\"hello world\""));
+ }
+
@Test
public void testGenerateDataFromReqConcurrently() throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);