You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2021/09/16 02:15:45 UTC
[incubator-shenyu] branch master updated: add integraton test for
modifyResponse plugin (#2087)
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/incubator-shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new d041c41 add integraton test for modifyResponse plugin (#2087)
d041c41 is described below
commit d041c4122ba2ec194659c0f098ffc27d6e9de957
Author: 萧 <12...@qq.com>
AuthorDate: Thu Sep 16 10:15:35 2021 +0800
add integraton test for modifyResponse plugin (#2087)
* add integraton test for modifyResponse plugin
* Update ModifyResponsePluginTest.java
---
.../http/controller/HttpTestController.java | 22 +++
.../integratedtest/common/helper/HttpHelper.java | 17 +++
.../shenyu-integrated-test-http/pom.xml | 8 +
.../http/combination/ModifyResponsePluginTest.java | 162 +++++++++++++++++++++
.../modify/response/ModifyResponsePlugin.java | 25 +++-
5 files changed, 226 insertions(+), 8 deletions(-)
diff --git a/shenyu-examples/shenyu-examples-http/src/main/java/org/apache/shenyu/examples/http/controller/HttpTestController.java b/shenyu-examples/shenyu-examples-http/src/main/java/org/apache/shenyu/examples/http/controller/HttpTestController.java
index 6507993..7ef2078 100644
--- a/shenyu-examples/shenyu-examples-http/src/main/java/org/apache/shenyu/examples/http/controller/HttpTestController.java
+++ b/shenyu-examples/shenyu-examples-http/src/main/java/org/apache/shenyu/examples/http/controller/HttpTestController.java
@@ -17,7 +17,9 @@
package org.apache.shenyu.examples.http.controller;
+import com.google.common.collect.ImmutableMap;
import org.apache.shenyu.client.springmvc.annotation.ShenyuSpringMvcClient;
+import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.examples.http.dto.UserDTO;
import org.apache.shenyu.examples.http.result.ResultBean;
import org.springframework.web.bind.annotation.CookieValue;
@@ -30,6 +32,9 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
import java.util.HashMap;
import java.util.Map;
@@ -201,4 +206,21 @@ public class HttpTestController {
return response;
}
+ /**
+ * modify response.
+ * @param exchange exchange
+ * @return response
+ */
+ @GetMapping(path = "/modifyResponse")
+ public Mono<String> modifyResponse(final ServerWebExchange exchange) {
+ exchange.getResponse().getHeaders().add("useByModifyResponse", String.valueOf(true));
+ exchange.getResponse().getHeaders().add("setHeadersExist", String.valueOf(true));
+ exchange.getResponse().getHeaders().add("replaceHeaderKeys", String.valueOf(true));
+ exchange.getResponse().getHeaders().add("removeHeaderKeys", String.valueOf(true));
+ final Map<String, Boolean> body = ImmutableMap.<String, Boolean>builder()
+ .put("originReplaceBodyKeys", true)
+ .put("removeBodyKeys", true)
+ .build();
+ return Mono.just(GsonUtils.getInstance().toJson(body));
+ }
}
diff --git a/shenyu-integrated-test/shenyu-integrated-test-common/src/main/java/org/apache/shenyu/integratedtest/common/helper/HttpHelper.java b/shenyu-integrated-test/shenyu-integrated-test-common/src/main/java/org/apache/shenyu/integratedtest/common/helper/HttpHelper.java
index efde273..119c757 100644
--- a/shenyu-integrated-test/shenyu-integrated-test-common/src/main/java/org/apache/shenyu/integratedtest/common/helper/HttpHelper.java
+++ b/shenyu-integrated-test/shenyu-integrated-test-common/src/main/java/org/apache/shenyu/integratedtest/common/helper/HttpHelper.java
@@ -114,4 +114,21 @@ public class HttpHelper {
LOG.info("getFromGateway({}) resp({})", path, respBody);
return GSON.fromJson(respBody, type);
}
+
+ /**
+ * Send a get http request to shenyu gateway with headers.
+ *
+ * @param path path
+ * @param headers headers
+ * @return response from gateway
+ * @throws IOException IO exception
+ */
+ public Response getResponseFromGateway(final String path, final Map<String, Object> headers) throws IOException {
+ Request.Builder requestBuilder = new Request.Builder().url(GATEWAY_END_POINT + path);
+ if (!CollectionUtils.isEmpty(headers)) {
+ headers.forEach((key, value) -> requestBuilder.addHeader(key, String.valueOf(value)));
+ }
+ Request request = requestBuilder.build();
+ return client.newCall(request).execute();
+ }
}
diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/pom.xml b/shenyu-integrated-test/shenyu-integrated-test-http/pom.xml
index 2806aed..903ab82 100644
--- a/shenyu-integrated-test/shenyu-integrated-test-http/pom.xml
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/pom.xml
@@ -87,6 +87,14 @@
</dependency>
<!-- apache shenyu param_mapping plugin end-->
+ <!-- apache shenyu param_mapping plugin start-->
+ <dependency>
+ <groupId>org.apache.shenyu</groupId>
+ <artifactId>shenyu-spring-boot-starter-plugin-modify-response</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- apache shenyu param_mapping plugin end-->
+
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
diff --git a/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/ModifyResponsePluginTest.java b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/ModifyResponsePluginTest.java
new file mode 100644
index 0000000..a7ab900
--- /dev/null
+++ b/shenyu-integrated-test/shenyu-integrated-test-http/src/test/java/org/apache/shenyu/integrated/test/http/combination/ModifyResponsePluginTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.integrated.test.http.combination;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.gson.JsonObject;
+import okhttp3.Headers;
+import okhttp3.Response;
+import org.apache.shenyu.common.dto.ConditionData;
+import org.apache.shenyu.common.dto.convert.rule.impl.ModifyResponseRuleHandle;
+import org.apache.shenyu.common.dto.convert.rule.impl.ParamMappingHandle;
+import org.apache.shenyu.common.enums.OperatorEnum;
+import org.apache.shenyu.common.enums.ParamTypeEnum;
+import org.apache.shenyu.common.enums.PluginEnum;
+import org.apache.shenyu.common.utils.GsonUtils;
+import org.apache.shenyu.common.utils.JsonUtils;
+import org.apache.shenyu.integratedtest.common.AbstractPluginDataInit;
+import org.apache.shenyu.integratedtest.common.helper.HttpHelper;
+import org.apache.shenyu.web.controller.PluginController;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.HashMap;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * ModifyResponsePluginTest.
+ */
+public class ModifyResponsePluginTest extends AbstractPluginDataInit {
+
+ private static final String ADD_HEADER = "addHeader";
+
+ private static final String SET_HEADERS_EXIST = "setHeadersExist";
+
+ private static final String SET_HEADER_NOT_EXIST = "setHeaderNotExist";
+
+ private static final String REPLACE_HEADER_KEYS = "replaceHeaderKeys";
+
+ private static final String REMOVE_HEADER_KEYS = "removeHeaderKeys";
+
+ private static final String ADD_BODY_KEYS = "addBodyKeys";
+
+ private static final String ORIGIN_REPLACE_BODY_KEYS = "originReplaceBodyKeys";
+
+ private static final String REPLACE_BODY_KEYS = "replaceBodyKeys";
+
+ private static final String REMOVE_BODY_KEYS = "removeBodyKeys";
+
+ private static final int EXCEPT_STATUS_CODE = 201;
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ String pluginResult = initPlugin(PluginEnum.MODIFY_RESPONSE.getName(), "{\"ruleHandlerPageType\":\"custom\"}");
+ assertThat(pluginResult, is("success"));
+ String selectorAndRulesResult = initSelectorAndRules(PluginEnum.MODIFY_RESPONSE.getName(), "", buildSelectorConditionList(), buildRuleLocalDataList());
+ assertThat(selectorAndRulesResult, is("success"));
+ }
+
+ private static List<ConditionData> buildSelectorConditionList() {
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(ParamTypeEnum.URI.getName());
+ conditionData.setOperator(OperatorEnum.MATCH.getAlias());
+ conditionData.setParamValue("/http/test/modifyResponse");
+ return Collections.singletonList(conditionData);
+ }
+
+ private static List<PluginController.RuleLocalData> buildRuleLocalDataList() {
+ List<PluginController.RuleLocalData> ruleLocalDataList = new ArrayList<>();
+ ruleLocalDataList.add(buildRuleLocalData());
+ return ruleLocalDataList;
+ }
+
+ private static PluginController.RuleLocalData buildRuleLocalData() {
+ final ModifyResponseRuleHandle modifyResponseRuleHandle = new ModifyResponseRuleHandle();
+ modifyResponseRuleHandle.setAddHeaders(ImmutableMap.<String, String>builder().put(ADD_HEADER, "true").build());
+ modifyResponseRuleHandle.setSetHeaders(ImmutableMap.<String, String>builder().put(SET_HEADERS_EXIST, "false").put(SET_HEADER_NOT_EXIST, "true").build());
+ modifyResponseRuleHandle.setReplaceHeaderKeys(ImmutableMap.<String, String>builder().put(REPLACE_HEADER_KEYS, "false").build());
+ modifyResponseRuleHandle.setRemoveHeaderKeys(ImmutableSet.<String>builder().add(REMOVE_HEADER_KEYS).build());
+ modifyResponseRuleHandle.setStatusCode(EXCEPT_STATUS_CODE);
+ modifyResponseRuleHandle.setRemoveBodyKeys(ImmutableSet.<String>builder().add(REMOVE_BODY_KEYS).build());
+
+ final ParamMappingHandle.ParamMapInfo addBodyKeysHandler = new ParamMappingHandle.ParamMapInfo();
+ addBodyKeysHandler.setPath("$");
+ addBodyKeysHandler.setKey(ADD_BODY_KEYS);
+ addBodyKeysHandler.setValue("true");
+ modifyResponseRuleHandle.setAddBodyKeys(Collections.singletonList(addBodyKeysHandler));
+
+ final ParamMappingHandle.ParamMapInfo replaceBodyKeysHandler = new ParamMappingHandle.ParamMapInfo();
+ replaceBodyKeysHandler.setPath("$");
+ replaceBodyKeysHandler.setKey(ORIGIN_REPLACE_BODY_KEYS);
+ replaceBodyKeysHandler.setValue(REPLACE_BODY_KEYS);
+ modifyResponseRuleHandle.setReplaceBodyKeys(Collections.singletonList(replaceBodyKeysHandler));
+
+ final Set<String> removeBodyKeysHandler = new HashSet<>();
+ removeBodyKeysHandler.add("$.removeBodyKeys");
+ modifyResponseRuleHandle.setRemoveBodyKeys(removeBodyKeysHandler);
+
+ PluginController.RuleLocalData ruleLocalData = new PluginController.RuleLocalData();
+ ruleLocalData.setRuleHandler(JsonUtils.toJson(modifyResponseRuleHandle));
+ ConditionData conditionData = new ConditionData();
+ conditionData.setParamType(ParamTypeEnum.URI.getName());
+ conditionData.setOperator(OperatorEnum.EQ.getAlias());
+ conditionData.setParamValue("/http/test/modifyResponse");
+ ruleLocalData.setConditionDataList(Collections.singletonList(conditionData));
+ return ruleLocalData;
+ }
+
+ @AfterClass
+ public static void clean() throws IOException {
+ cleanPluginData(PluginEnum.MODIFY_RESPONSE.getName());
+ }
+
+ @Test
+ public void test() throws IOException {
+ final Response response = HttpHelper.INSTANCE.getResponseFromGateway("/http/test/modifyResponse", new HashMap<>(0));
+ assertNotNull(response);
+ assertEquals(EXCEPT_STATUS_CODE, response.code());
+
+ final Headers headers = response.headers();
+ assertTrue(Boolean.parseBoolean(headers.get(ADD_HEADER)));
+ assertFalse(Boolean.parseBoolean(headers.get(SET_HEADERS_EXIST)));
+ assertTrue(Boolean.parseBoolean(headers.get(SET_HEADER_NOT_EXIST)));
+ assertFalse(Boolean.parseBoolean(headers.get(REPLACE_HEADER_KEYS)));
+ assertFalse(headers.toMultimap().containsKey(REMOVE_HEADER_KEYS));
+
+ final JsonObject body = GsonUtils.getInstance().fromJson(Objects.requireNonNull(response.body()).string(), JsonObject.class);
+ assertTrue(body.get(ADD_BODY_KEYS).getAsBoolean());
+ assertNull(body.get(ORIGIN_REPLACE_BODY_KEYS));
+ assertTrue(body.get(REPLACE_BODY_KEYS).getAsBoolean());
+ }
+}
diff --git a/shenyu-plugin/shenyu-plugin-modify-response/src/main/java/org/apache/shenyu/plugin/modify/response/ModifyResponsePlugin.java b/shenyu-plugin/shenyu-plugin-modify-response/src/main/java/org/apache/shenyu/plugin/modify/response/ModifyResponsePlugin.java
index 16ff0d2..bba4aa1 100644
--- a/shenyu-plugin/shenyu-plugin-modify-response/src/main/java/org/apache/shenyu/plugin/modify/response/ModifyResponsePlugin.java
+++ b/shenyu-plugin/shenyu-plugin-modify-response/src/main/java/org/apache/shenyu/plugin/modify/response/ModifyResponsePlugin.java
@@ -40,8 +40,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.ServerCodecConfigurer;
-import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
+import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
@@ -51,6 +51,7 @@ import reactor.core.publisher.Mono;
import reactor.util.annotation.NonNull;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -66,8 +67,9 @@ public class ModifyResponsePlugin extends AbstractShenyuPlugin {
assert shenyuContext != null;
final ModifyResponseRuleHandle modifyResponseRuleHandle = ModifyResponsePluginDataHandler.CACHED_HANDLE.get().obtainHandle(CacheKeyUtils.INST.getKey(rule));
if (Objects.nonNull(modifyResponseRuleHandle)) {
- ServerHttpResponse response = exchange.getResponse();
- HttpHeaders httpHeaders = response.getHeaders();
+ ClientResponse response = exchange.getAttribute(Constants.CLIENT_RESPONSE_ATTR);
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.addAll(Objects.requireNonNull(response).headers().asHttpHeaders());
if (MapUtils.isNotEmpty(modifyResponseRuleHandle.getAddHeaders())) {
Map<String, String> addHeaderMap = modifyResponseRuleHandle.getAddHeaders();
addHeaderMap.forEach(httpHeaders::add);
@@ -80,10 +82,7 @@ public class ModifyResponsePlugin extends AbstractShenyuPlugin {
if (MapUtils.isNotEmpty(modifyResponseRuleHandle.getReplaceHeaderKeys())) {
Map<String, String> replaceHeaderMap = modifyResponseRuleHandle.getReplaceHeaderKeys();
- replaceHeaderMap.forEach((key, value) -> {
- httpHeaders.addAll(value, Objects.requireNonNull(httpHeaders.get(key)));
- httpHeaders.remove(key);
- });
+ replaceHeaderMap.forEach((key, value) -> httpHeaders.replace(key, Collections.singletonList(value)));
}
if (Objects.nonNull(modifyResponseRuleHandle.getRemoveHeaderKeys()) && !CollectionUtils.isEmpty(modifyResponseRuleHandle.getRemoveHeaderKeys())) {
@@ -92,8 +91,18 @@ public class ModifyResponsePlugin extends AbstractShenyuPlugin {
}
if (modifyResponseRuleHandle.getStatusCode() > 0) {
- response.setStatusCode(HttpStatus.valueOf(modifyResponseRuleHandle.getStatusCode()));
+ exchange.getResponse().setStatusCode(HttpStatus.valueOf(modifyResponseRuleHandle.getStatusCode()));
}
+
+ ClientResponse.Builder builder = ClientResponse.create(Objects.requireNonNull(exchange.getResponse().getStatusCode()),
+ ServerCodecConfigurer.create().getReaders());
+ Flux<DataBuffer> body = response.body(BodyExtractors.toDataBuffers());
+ ClientResponse modifyResponse = builder
+ .headers(headers -> headers.putAll(httpHeaders))
+ .body(body)
+ .cookies(cookies -> cookies.putAll(response.cookies()))
+ .build();
+ exchange.getAttributes().put(Constants.CLIENT_RESPONSE_ATTR, modifyResponse);
}
return chain.execute(exchange.mutate()