From f07e39b8cf536b1499642a56ae17e0b1dfbe3c8b Mon Sep 17 00:00:00 2001 From: Nishant-Sehgal Date: Sun, 20 Oct 2019 15:04:17 +0530 Subject: [PATCH] MockSpringMvcServlet issue for @ControllerAdvice NoHandlerFoundException --- .../karate/demo/exception/ErrorResponse.java | 75 +++++++++++++++++++ .../exception/GlobalExceptionHandler.java | 38 ++++++++++ .../src/main/resources/application.properties | 4 +- .../java/demo/error/NoUrlErrorRunner.java | 13 ++++ .../src/test/java/demo/error/no-url.feature | 15 ++++ .../src/test/java/demo/MockDemoConfig.java | 9 +++ .../test/java/demo/MockSpringMvcServlet.java | 21 ++++++ 7 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 karate-demo/src/main/java/com/intuit/karate/demo/exception/ErrorResponse.java create mode 100644 karate-demo/src/main/java/com/intuit/karate/demo/exception/GlobalExceptionHandler.java create mode 100644 karate-demo/src/test/java/demo/error/NoUrlErrorRunner.java create mode 100644 karate-demo/src/test/java/demo/error/no-url.feature diff --git a/karate-demo/src/main/java/com/intuit/karate/demo/exception/ErrorResponse.java b/karate-demo/src/main/java/com/intuit/karate/demo/exception/ErrorResponse.java new file mode 100644 index 000000000..53be41988 --- /dev/null +++ b/karate-demo/src/main/java/com/intuit/karate/demo/exception/ErrorResponse.java @@ -0,0 +1,75 @@ +package com.intuit.karate.demo.exception; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ErrorResponse { + + @JsonProperty("status_code") + private int code; + @JsonProperty("uri_path") + private String path; + private String method; + @JsonProperty("error_message") + private String message; + + public ErrorResponse() { + } + + public ErrorResponse(int code, String path, String method, String message) { + this.code = code; + this.path = path; + this.method = method; + this.message = message; + } + + /** + * @return the code + */ + public int getCode() { + return code;} + + /** + * @param code the code to set + */ + public void setCode(int code) { + this.code = code;} + + /** + * @return the path + */ + public String getPath() { + return path;} + + /** + * @param path the path to set + */ + public void setPath(String path) { + this.path = path;} + + /** + * @return the method + */ + public String getMethod() { + return method;} + + /** + * @param method the method to set + */ + public void setMethod(String method) { + this.method = method;} + + /** + * @return the message + */ + public String getMessage() { + return message;} + + /** + * @param message the message to set + */ + public void setMessage(String message) { + this.message = message;} + + +} + diff --git a/karate-demo/src/main/java/com/intuit/karate/demo/exception/GlobalExceptionHandler.java b/karate-demo/src/main/java/com/intuit/karate/demo/exception/GlobalExceptionHandler.java new file mode 100644 index 000000000..6bdb048bd --- /dev/null +++ b/karate-demo/src/main/java/com/intuit/karate/demo/exception/GlobalExceptionHandler.java @@ -0,0 +1,38 @@ +package com.intuit.karate.demo.exception; + +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.context.request.ServletWebRequest; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.NoHandlerFoundException; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +/** + * @author nsehgal + * + */ +@ControllerAdvice +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + /** + * Adding these properties will make the following code active: + * spring.mvc.throw-exception-if-no-handler-found=true + * spring.resources.add-mappings=false + * + * @param ex + * @param headers + * @param status + * @param webRequest + * @return + */ + @Override + protected ResponseEntity handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) { + String uriPath = webRequest.getDescription(false).substring(4); + String message = "The URL you have reached is not in service at this time"; + String method = ((ServletWebRequest) webRequest).getRequest().getMethod(); + ErrorResponse errorResponse = new ErrorResponse(status.value(), uriPath, method, message); + return new ResponseEntity<>(errorResponse, status); + } +} diff --git a/karate-demo/src/main/resources/application.properties b/karate-demo/src/main/resources/application.properties index 000af3c37..addeb8654 100644 --- a/karate-demo/src/main/resources/application.properties +++ b/karate-demo/src/main/resources/application.properties @@ -1 +1,3 @@ -spring.jackson.default-property-inclusion=NON_NULL \ No newline at end of file +spring.jackson.default-property-inclusion=NON_NULL +spring.mvc.throw-exception-if-no-handler-found=true +spring.resources.add-mappings=false \ No newline at end of file diff --git a/karate-demo/src/test/java/demo/error/NoUrlErrorRunner.java b/karate-demo/src/test/java/demo/error/NoUrlErrorRunner.java new file mode 100644 index 000000000..9a0cd3483 --- /dev/null +++ b/karate-demo/src/test/java/demo/error/NoUrlErrorRunner.java @@ -0,0 +1,13 @@ +package demo.error; + +import com.intuit.karate.KarateOptions; +import demo.TestBase; + +/** + * + * @author nsehgal + */ +@KarateOptions(features = {"classpath:demo/error/no-url.feature"}) +public class NoUrlErrorRunner extends TestBase { + +} diff --git a/karate-demo/src/test/java/demo/error/no-url.feature b/karate-demo/src/test/java/demo/error/no-url.feature new file mode 100644 index 000000000..02a9fd4f8 --- /dev/null +++ b/karate-demo/src/test/java/demo/error/no-url.feature @@ -0,0 +1,15 @@ +Feature: No URLfound proper error response + + Background: + * url demoBaseUrl + * configure lowerCaseResponseHeaders = true + + Scenario: Invalid URL response + Given path '/hello' + When method get + Then status 404 + And match header content-type contains 'application/json' + And match header content-type contains 'charset=UTF-8' + And match response.status_code == 404 + And match response.method == 'GET' + And match response.error_message == 'The URL you have reached is not in service at this time' diff --git a/karate-mock-servlet/src/test/java/demo/MockDemoConfig.java b/karate-mock-servlet/src/test/java/demo/MockDemoConfig.java index 40f1b94e6..9df6f204b 100644 --- a/karate-mock-servlet/src/test/java/demo/MockDemoConfig.java +++ b/karate-mock-servlet/src/test/java/demo/MockDemoConfig.java @@ -35,6 +35,8 @@ import com.intuit.karate.demo.controller.SignInController; import com.intuit.karate.demo.controller.SoapController; import com.intuit.karate.demo.controller.UploadController; +import com.intuit.karate.demo.exception.GlobalExceptionHandler; + import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -109,4 +111,11 @@ public EchoController echoController() { return new EchoController(); } + // Global Exception Handler ... + @Bean + public GlobalExceptionHandler globalExceptionHandler() { + return new GlobalExceptionHandler(); + } + + } diff --git a/karate-mock-servlet/src/test/java/demo/MockSpringMvcServlet.java b/karate-mock-servlet/src/test/java/demo/MockSpringMvcServlet.java index 94baf6dd0..92c8f8f93 100644 --- a/karate-mock-servlet/src/test/java/demo/MockSpringMvcServlet.java +++ b/karate-mock-servlet/src/test/java/demo/MockSpringMvcServlet.java @@ -25,9 +25,12 @@ import com.intuit.karate.http.HttpRequestBuilder; import com.intuit.karate.mock.servlet.MockHttpClient; + import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; + +import org.springframework.boot.autoconfigure.web.WebMvcProperties; import org.springframework.mock.web.MockServletConfig; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; @@ -72,12 +75,30 @@ private static Servlet initServlet() { ServletConfig servletConfig = new MockServletConfig(); try { servlet.init(servletConfig); + customize(servlet); } catch (Exception e) { throw new RuntimeException(e); } return servlet; } + /** + * Checks if servlet is Dispatcher servlet implementation and then fetches the WebMvcProperties + * from spring container and configure the dispatcher servlet. + * + * @param servlet input servlet implementation + */ + private static void customize(Servlet servlet) { + if (servlet instanceof DispatcherServlet) { + DispatcherServlet dispatcherServlet = (DispatcherServlet) servlet; + WebMvcProperties mvcProperties = + dispatcherServlet.getWebApplicationContext().getBean(WebMvcProperties.class); + dispatcherServlet.setThrowExceptionIfNoHandlerFound(mvcProperties.isThrowExceptionIfNoHandlerFound()); + dispatcherServlet.setDispatchOptionsRequest(mvcProperties.isDispatchOptionsRequest()); + dispatcherServlet.setDispatchTraceRequest(mvcProperties.isDispatchTraceRequest()); + } + } + public static MockSpringMvcServlet getMock() { return new MockSpringMvcServlet(SERVLET, SERVLET_CONTEXT); }