This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new ea17cca  [SCB-861]490,590 response not properly used
ea17cca is described below

commit ea17cca3e2e35a2f2b779533189f242b0b1f9324
Author: liubao <[email protected]>
AuthorDate: Wed Aug 22 11:13:17 2018 +0800

    [SCB-861]490,590 response not properly used
---
 .../client/CodeFirstRestTemplateSpringmvc.java     |  5 ++
 .../demo/springmvc/client/SpringmvcClient.java     | 15 ++++--
 .../demo/springmvc/client/TestResponse.java        | 10 +---
 .../demo/springmvc/server/CodeFirstSpringmvc.java  | 22 ++++----
 .../src/main/resources/microservice.yaml           |  4 +-
 .../swagger/invocation/response/ResponsesMeta.java |  7 +--
 .../rest/client/http/DefaultHttpClientFilter.java  | 21 +++++++-
 .../client/http/TestDefaultHttpClientFilter.java   | 59 ++++++++++++++++++++--
 8 files changed, 108 insertions(+), 35 deletions(-)

diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
index af27ccd..e34b340 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
@@ -173,6 +173,7 @@ public class CodeFirstRestTemplateSpringmvc extends 
CodeFirstRestTemplate {
   }
 
   private void testFallback(RestTemplate template, String cseUrlPrefix) {
+    long start = System.currentTimeMillis();
     String result = template.getForObject(cseUrlPrefix + 
"/fallback/returnnull/hello", String.class);
     TestMgr.check(result, "hello");
     result = template.getForObject(cseUrlPrefix + 
"/fallback/returnnull/throwexception", String.class);
@@ -199,6 +200,10 @@ public class CodeFirstRestTemplateSpringmvc extends 
CodeFirstRestTemplate {
 
     result = template.getForObject(cseUrlPrefix + "/fallback/force/hello", 
String.class);
     TestMgr.check(result, "mockedreslut");
+
+    // This test case is fallback testing and will return null if failed.
+    // In order to check if failed due to some unexpected timeout exception, 
check the time.
+    TestMgr.check(System.currentTimeMillis() - start < 10000, true);
   }
 
   private void testResponseEntity(String microserviceName, RestTemplate 
template, String cseUrlPrefix) {
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
index 37aa870..3e5aa1c 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
@@ -54,12 +54,19 @@ public class SpringmvcClient {
   private static Controller controller;
 
   public static void main(String[] args) throws Exception {
-    Log4jUtils.init();
-    BeanUtils.init();
+    try {
+      Log4jUtils.init();
+      BeanUtils.init();
 
-    run();
+      run();
 
-    TestMgr.summary();
+      TestMgr.summary();
+    } catch (Throwable e) {
+      TestMgr.check("success", "failed");
+      System.err.println("-------------- test failed -------------");
+      e.printStackTrace();
+      System.err.println("-------------- test failed -------------");
+    }
   }
 
   public static void run() {
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
index 0cd6028..95db734 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
@@ -146,15 +146,7 @@ public class TestResponse {
     }
     Objects.requireNonNull(exception);
     // 2. CseException: bizKeeper exception
-    Throwable wrappedException = exception.getCause();
-    TestMgr.check(CseException.class, wrappedException.getClass());
-    // 3. InvocationException: decoder wrapping exception
-    wrappedException = wrappedException.getCause();
-    TestMgr.check(InvocationException.class, wrappedException.getClass());
-    TestMgr.check("InvocationException: code=490;msg=CommonExceptionData 
[message=Cse Internal Bad Request]",
-        wrappedException.getMessage());
-    // 4. InvalidFormatException: decode exception
-    Object cause = wrappedException.getCause();
+    Throwable cause = exception.getCause();
     TestMgr.check(InvalidFormatException.class, cause.getClass());
     TestMgr.check(
         "Cannot deserialize value of type `java.util.Date` from String 
\"returnOK\": not a valid representation "
diff --git 
a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
 
b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
index 6ec2bc5..0ab7487 100644
--- 
a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
+++ 
b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
@@ -22,7 +22,6 @@ import java.io.InputStream;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.http.HttpServletRequest;
@@ -51,6 +50,7 @@ import 
org.apache.servicecomb.swagger.extend.annotations.ResponseHeaders;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.context.ContextUtils;
 import org.apache.servicecomb.swagger.invocation.context.InvocationContext;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.apache.servicecomb.swagger.invocation.response.Headers;
 import org.slf4j.Logger;
@@ -270,42 +270,44 @@ public class CodeFirstSpringmvc {
     return result;
   }
 
+  // Using 490, 590 error code, the response type should be 
CommonExceptionData. Or we need
+  // complex ExceptionConverters to deal with exceptions thrown by Hanlders, 
etc.
   @RequestMapping(path = "/fallback/returnnull/{name}", method = 
RequestMethod.GET)
   @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, 
message = "xxx"),
-      @ApiResponse(code = 490, response = String.class, message = "xxx")})
+      @ApiResponse(code = 490, response = CommonExceptionData.class, message = 
"xxx")})
   public String fallbackReturnNull(@PathVariable(name = "name") String name) {
     if ("throwexception".equals(name)) {
-      throw new InvocationException(490, "490", "xxx");
+      throw new InvocationException(490, "490", new 
CommonExceptionData("xxx"));
     }
     return name;
   }
 
   @RequestMapping(path = "/fallback/throwexception/{name}", method = 
RequestMethod.GET)
   @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, 
message = "xxx"),
-      @ApiResponse(code = 490, response = String.class, message = "xxx")})
+      @ApiResponse(code = 490, response = CommonExceptionData.class, message = 
"xxx")})
   public String fallbackThrowException(@PathVariable(name = "name") String 
name) {
     if ("throwexception".equals(name)) {
-      throw new InvocationException(490, "490", "xxx");
+      throw new InvocationException(490, "490", new 
CommonExceptionData("xxx"));
     }
     return name;
   }
 
   @RequestMapping(path = "/fallback/fromcache/{name}", method = 
RequestMethod.GET)
   @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, 
message = "xxx"),
-      @ApiResponse(code = 490, response = String.class, message = "xxx")})
+      @ApiResponse(code = 490, response = CommonExceptionData.class, message = 
"xxx")})
   public String fallbackFromCache(@PathVariable(name = "name") String name) {
     if ("throwexception".equals(name)) {
-      throw new InvocationException(490, "490", "xxx");
+      throw new InvocationException(490, "490", new 
CommonExceptionData("xxx"));
     }
     return name;
   }
 
   @RequestMapping(path = "/fallback/force/{name}", method = RequestMethod.GET)
   @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, 
message = "xxx"),
-      @ApiResponse(code = 490, response = String.class, message = "xxx")})
+      @ApiResponse(code = 490, response = CommonExceptionData.class, message = 
"xxx")})
   public String fallbackForce(@PathVariable(name = "name") String name) {
     if ("throwexception".equals(name)) {
-      throw new InvocationException(490, "490", "xxx");
+      throw new InvocationException(490, "490", new 
CommonExceptionData("xxx"));
     }
     return name;
   }
@@ -317,7 +319,7 @@ public class CodeFirstSpringmvc {
 
   @RequestMapping(path = "/testenum/{name}", method = RequestMethod.GET)
   @ApiResponses(value = {@ApiResponse(code = 200, response = String.class, 
message = "200 normal"),
-      @ApiResponse(code = 490, response = String.class, message = "490 
exception")})
+      @ApiResponse(code = 490, response = CommonExceptionData.class, message = 
"490 exception")})
   public String testEnum(@RequestParam(name = "username") String username,
       @PathVariable(value = "name") NameType nameType) {
     return nameType.toString();
diff --git 
a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml 
b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
index 9c047c8..fba7554 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
+++ b/demo/demo-springmvc/springmvc-server/src/main/resources/microservice.yaml
@@ -54,11 +54,11 @@ servicecomb:
   uploads:
     directory: target
   rest:
-    address: 0.0.0.0:8080?sslEnabled=true
+    address: 0.0.0.0:8082?sslEnabled=true
     server:
       compression: true
   highway:
-    address: 0.0.0.0:7070?sslEnabled=true
+    address: 0.0.0.0:7072?sslEnabled=true
   handler:
     chain:
       Provider:
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
index 856e3f0..881cb81 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
@@ -53,7 +53,6 @@ public class ResponsesMeta {
   // 如果不传return类型进来,完全以swagger为标准,会导致生成的class不等于return
   public void init(SwaggerToClassGenerator swaggerToClassGenerator, Operation 
operation, Type returnType) {
     initSuccessResponse(returnType);
-    initInternalErrorResponse();
     initGlobalDefaultMapper();
 
     for (Entry<String, Response> entry : operation.getResponses().entrySet()) {
@@ -68,6 +67,8 @@ public class ResponsesMeta {
       responseMeta.init(swaggerToClassGenerator, entry.getValue());
     }
 
+    initInternalErrorResponse();
+
     if (defaultResponse == null) {
       // swagger中没有定义default,加上default专用于处理exception
       ResponseMeta responseMeta = new ResponseMeta();
@@ -86,8 +87,8 @@ public class ResponsesMeta {
   protected void initInternalErrorResponse() {
     ResponseMeta internalErrorResponse = new ResponseMeta();
     internalErrorResponse.setJavaType(COMMON_EXCEPTION_JAVA_TYPE);
-    responseMap.put(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, 
internalErrorResponse);
-    responseMap.put(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, 
internalErrorResponse);
+    responseMap.putIfAbsent(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, 
internalErrorResponse);
+    responseMap.putIfAbsent(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, 
internalErrorResponse);
   }
 
   protected void initGlobalDefaultMapper() {
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
index 60921c5..806a9c9 100644
--- 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
@@ -31,6 +31,9 @@ import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.context.HttpStatus;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.apache.servicecomb.swagger.invocation.response.ResponseMeta;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -91,8 +94,22 @@ public class DefaultHttpClientFilter implements 
HttpClientFilter {
       result = produceProcessor.decodeResponse(responseEx.getBodyBuffer(), 
responseMeta.getJavaType());
       return Response.create(responseEx.getStatusType(), result);
     } catch (Exception e) {
-      LOGGER.error("failed to decode response body, exception type is [{}]", 
e.getClass());
-      return Response.createConsumerFail(e);
+      LOGGER.error("failed to decode response body, exception is [{}]", 
e.getMessage());
+      String msg =
+          String.format("method %s, path %s, statusCode %d, reasonPhrase %s, 
response content-type %s is not supported",
+              swaggerRestOperation.getHttpMethod(),
+              swaggerRestOperation.getAbsolutePath(),
+              responseEx.getStatus(),
+              responseEx.getStatusType().getReasonPhrase(),
+              responseEx.getHeader(HttpHeaders.CONTENT_TYPE));
+      if (HttpStatus.isSuccess(responseEx.getStatus())) {
+        return Response.createConsumerFail(
+            new InvocationException(400, 
responseEx.getStatusType().getReasonPhrase(),
+                new CommonExceptionData(msg), e));
+      }
+      return Response.createConsumerFail(
+          new InvocationException(responseEx.getStatus(), 
responseEx.getStatusType().getReasonPhrase(),
+              new CommonExceptionData(msg), e));
     }
   }
 
diff --git 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
index d14bc1d..9c0028b 100644
--- 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
+++ 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
@@ -36,7 +36,6 @@ import 
org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
-import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.apache.servicecomb.swagger.invocation.response.ResponseMeta;
 import org.junit.Assert;
@@ -136,6 +135,54 @@ public class TestDefaultHttpClientFilter {
         result = handlerContext;
         invocation.getOperationMeta();
         result = operationMeta;
+        operationMeta.findResponseMeta(400);
+        result = responseMeta;
+        operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION);
+        result = swaggerRestOperation;
+        responseMeta.getJavaType();
+        result = SimpleType.constructUnsafe(Date.class);
+        responseEx.getStatus();
+        result = 400;
+        responseEx.getBodyBuffer();
+        result = new BufferImpl().appendString("abc");
+      }
+    };
+    new MockUp<DefaultHttpClientFilter>() {
+      @Mock
+      ProduceProcessor findProduceProcessor(RestOperationMeta restOperation, 
HttpServletResponseEx responseEx) {
+        return new ProduceJsonProcessor();
+      }
+    };
+
+    Response response = filter.extractResponse(invocation, responseEx);
+    Assert.assertEquals(400, response.getStatusCode());
+    Assert.assertEquals(InvocationException.class, 
response.<InvocationException>getResult().getClass());
+    InvocationException invocationException = response.getResult();
+    Assert.assertEquals(
+        "InvocationException: code=400;msg=CommonExceptionData [message=method 
null, path null, statusCode 400, reasonPhrase null, response content-type null 
is not supported]",
+        invocationException.getMessage());
+    Assert.assertEquals("Unrecognized token 'abc': was expecting ('true', 
'false' or 'null')\n"
+            + " at [Source: 
(org.apache.servicecomb.foundation.vertx.stream.BufferInputStream); line: 1, 
column: 7]",
+        invocationException.getCause().getMessage());
+    Assert.assertEquals(CommonExceptionData.class, 
invocationException.getErrorData().getClass());
+    CommonExceptionData commonExceptionData = (CommonExceptionData) 
invocationException.getErrorData();
+    Assert.assertEquals(
+        "method null, path null, statusCode 400, reasonPhrase null, response 
content-type null is not supported",
+        commonExceptionData.getMessage());
+  }
+
+  @Test
+  public void extractResult_decodeError200(@Mocked Invocation invocation, 
@Mocked ReadStreamPart part,
+      @Mocked OperationMeta operationMeta, @Mocked ResponseMeta responseMeta,
+      @Mocked RestOperationMeta swaggerRestOperation,
+      @Mocked HttpServletResponseEx responseEx) {
+    Map<String, Object> handlerContext = new HashMap<>();
+    new Expectations() {
+      {
+        invocation.getHandlerContext();
+        result = handlerContext;
+        invocation.getOperationMeta();
+        result = operationMeta;
         operationMeta.findResponseMeta(200);
         result = responseMeta;
         operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION);
@@ -156,18 +203,20 @@ public class TestDefaultHttpClientFilter {
     };
 
     Response response = filter.extractResponse(invocation, responseEx);
-    Assert.assertEquals(490, response.getStatusCode());
-    Assert.assertEquals(ExceptionFactory.CONSUMER_INNER_REASON_PHRASE, 
response.getReasonPhrase());
+    Assert.assertEquals(400, response.getStatusCode());
     Assert.assertEquals(InvocationException.class, 
response.<InvocationException>getResult().getClass());
     InvocationException invocationException = response.getResult();
-    Assert.assertEquals("InvocationException: code=490;msg=CommonExceptionData 
[message=Cse Internal Bad Request]",
+    Assert.assertEquals(
+        "InvocationException: code=400;msg=CommonExceptionData [message=method 
null, path null, statusCode 200, reasonPhrase null, response content-type null 
is not supported]",
         invocationException.getMessage());
     Assert.assertEquals("Unrecognized token 'abc': was expecting ('true', 
'false' or 'null')\n"
             + " at [Source: 
(org.apache.servicecomb.foundation.vertx.stream.BufferInputStream); line: 1, 
column: 7]",
         invocationException.getCause().getMessage());
     Assert.assertEquals(CommonExceptionData.class, 
invocationException.getErrorData().getClass());
     CommonExceptionData commonExceptionData = (CommonExceptionData) 
invocationException.getErrorData();
-    Assert.assertEquals("Cse Internal Bad Request", 
commonExceptionData.getMessage());
+    Assert.assertEquals(
+        "method null, path null, statusCode 200, reasonPhrase null, response 
content-type null is not supported",
+        commonExceptionData.getMessage());
   }
 
   @Test

Reply via email to