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()