Bael 5265: OpenFeign and Spring Exception handler (#12468)
* Implemented cassandra batch query * Added netty version param * Reformatted correctly * Reformatted correctly * Reformatted correctly * Formatting fix resolved * Formatting fix resolved * Removed unused method * Refactored method for better readability * tab spaces corrected * Added http headers in feign * Updated code * Updated code * Removed unused code * Removed unused logger code * Implemented Interceptor and logging related code review * Added AuthService Code * Removed toString method * Removed unnecessary declaration * Removed new line * Added feign headers log as well * Moved to Authorisation package for better naming * spaces removed * @Override included * [Saikat]| Adding the OpenFeign exception default and customizable exception handler and test cases * [Saikat]| Test name updated * [Saikat]| Test name updated * [Saikat]| Removed unused import * [Saikat]| Refactored code * [Saikat]| Reformatted the test codes * [Saikat]| Removed unnecessary code * [Saikat]| Controller test fixed for data error * [Saikat]| Code review fixes * [Saikat]| Code review fixes * [Saikat]| Removed unnecessary annotation * [Saikat]| Added extends ResponseEntityExceptionHandler * [Saikat]| Code review implemented * [Saikat]| Indentation added * Removed empty line before method start Co-authored-by: saikat chakraborty <saikat.chakraborty@tesco.com>
This commit is contained in:
parent
e7c4294e3e
commit
8a79e04d39
|
@ -61,6 +61,12 @@
|
|||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
<version>2.33.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.config.FeignConfig;
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@FeignClient(name = "product-client-2", url = "http://localhost:8081/product/", configuration = FeignConfig.class)
|
||||
public interface ProductClient {
|
||||
|
||||
@RequestMapping(value = "{id}", method = RequestMethod.GET)
|
||||
Product getProduct(@PathVariable(value = "id") String id);
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.config;
|
||||
|
||||
import com.baeldung.cloud.openfeign.exception.BadRequestException;
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductNotFoundException;
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductServiceNotAvailableException;
|
||||
import feign.Response;
|
||||
import feign.codec.ErrorDecoder;
|
||||
|
||||
public class CustomErrorDecoder implements ErrorDecoder {
|
||||
|
||||
@Override
|
||||
public Exception decode(String methodKey, Response response) {
|
||||
switch (response.status()){
|
||||
case 400:
|
||||
return new BadRequestException();
|
||||
case 404:
|
||||
return new ProductNotFoundException("Product not found");
|
||||
case 503:
|
||||
return new ProductServiceNotAvailableException("Product Api is unavailable");
|
||||
default:
|
||||
return new Exception("Exception while getting product details");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.config;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
public class FeignConfig {
|
||||
|
||||
@Bean
|
||||
Logger.Level feignLoggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ErrorDecoder errorDecoder() {
|
||||
return new CustomErrorDecoder();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.controller;
|
||||
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.client.ProductClient;
|
||||
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
@RestController("product_controller2")
|
||||
@RequestMapping(value = "myapp2")
|
||||
public class ProductController {
|
||||
|
||||
private final ProductClient productClient;
|
||||
|
||||
@Autowired
|
||||
public ProductController(ProductClient productClient) {
|
||||
this.productClient = productClient;
|
||||
}
|
||||
|
||||
@GetMapping("/product/{id}")
|
||||
public Product getProduct(@PathVariable String id) {
|
||||
return productClient.getProduct(id);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.exception;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ErrorResponse {
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
|
||||
private Date timestamp;
|
||||
|
||||
@JsonProperty(value = "code")
|
||||
private int code;
|
||||
|
||||
@JsonProperty(value = "status")
|
||||
private String status;
|
||||
@JsonProperty(value = "message")
|
||||
private String message;
|
||||
@JsonProperty(value = "details")
|
||||
private String details;
|
||||
|
||||
public ErrorResponse() {
|
||||
}
|
||||
|
||||
public ErrorResponse(HttpStatus httpStatus, String message, String details) {
|
||||
timestamp = new Date();
|
||||
this.code = httpStatus.value();
|
||||
this.status = httpStatus.name();
|
||||
this.message = message;
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getDetails() {
|
||||
return details;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.exception;
|
||||
|
||||
import com.baeldung.cloud.openfeign.exception.BadRequestException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class ProductExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ExceptionHandler({ProductServiceNotAvailableException.class})
|
||||
public ResponseEntity<ErrorResponse> handleProductServiceNotAvailableException(ProductServiceNotAvailableException exception, WebRequest request) {
|
||||
return new ResponseEntity<>(new ErrorResponse(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
exception.getMessage(),
|
||||
request.getDescription(false)),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@ExceptionHandler({ProductNotFoundException.class})
|
||||
public ResponseEntity<ErrorResponse> handleProductNotFoundException(ProductNotFoundException exception, WebRequest request) {
|
||||
return new ResponseEntity<>(new ErrorResponse(
|
||||
HttpStatus.NOT_FOUND,
|
||||
exception.getMessage(),
|
||||
request.getDescription(false)),
|
||||
HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleGenericException(Exception exception, WebRequest request) {
|
||||
return new ResponseEntity<>(new ErrorResponse(
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
exception.getMessage(),
|
||||
request.getDescription(false)),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.exception;
|
||||
|
||||
public class ProductNotFoundException extends RuntimeException {
|
||||
|
||||
public ProductNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.exception;
|
||||
|
||||
public class ProductServiceNotAvailableException extends RuntimeException {
|
||||
|
||||
public ProductServiceNotAvailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.config.FeignConfig;
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@FeignClient(name = "product-client", url = "http://localhost:8081/product/", configuration = FeignConfig.class)
|
||||
public interface ProductClient {
|
||||
|
||||
@RequestMapping(value = "{id}", method = RequestMethod.GET)
|
||||
Product getProduct(@PathVariable(value = "id") String id);
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.config;
|
||||
|
||||
import feign.Logger;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
public class FeignConfig {
|
||||
|
||||
@Bean
|
||||
Logger.Level feignLoggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.controller;
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.client.ProductClient;
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController("product_controller1")
|
||||
@RequestMapping(value ="myapp1")
|
||||
public class ProductController {
|
||||
|
||||
private final ProductClient productClient;
|
||||
|
||||
@Autowired
|
||||
public ProductController(ProductClient productClient) {
|
||||
this.productClient = productClient;
|
||||
}
|
||||
|
||||
@GetMapping("/product/{id}")
|
||||
public Product getProduct(@PathVariable String id) {
|
||||
return productClient.getProduct(id);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.model;
|
||||
|
||||
public class Product {
|
||||
|
||||
private String id;
|
||||
|
||||
private String productName;
|
||||
|
||||
private double price;
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductNotFoundException;
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ProductServiceNotAvailableException;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class ProductClientUnitTest {
|
||||
|
||||
@Autowired
|
||||
private ProductClient productClient;
|
||||
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
@Before
|
||||
public void startWireMockServer() {
|
||||
wireMockServer = new WireMockServer(8081);
|
||||
configureFor("localhost", 8081);
|
||||
wireMockServer.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopWireMockServer() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductApiIsNotAvailable_whenGetProductCalled_thenThrowProductServiceNotAvailableException() {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse().withStatus(503)));
|
||||
|
||||
assertThrows(ProductServiceNotAvailableException.class, () -> productClient.getProduct(productId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductNotFound_whenGetProductCalled_thenThrowBadRequestException() {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse().withStatus(404)));
|
||||
|
||||
assertThrows(ProductNotFoundException.class, () -> productClient.getProduct(productId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.baeldung.cloud.openfeign.customizederrorhandling.controller;
|
||||
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.client.ProductClient;
|
||||
import com.baeldung.cloud.openfeign.customizederrorhandling.exception.ErrorResponse;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(ProductController.class)
|
||||
@ImportAutoConfiguration({FeignAutoConfiguration.class})
|
||||
public class ProductControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private ProductClient productClient;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
@Before
|
||||
public void startWireMockServer() {
|
||||
wireMockServer = new WireMockServer(8081);
|
||||
configureFor("localhost", 8081);
|
||||
wireMockServer.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopWireMockServer() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductApiIsNotAvailable_whenGetProductCalled_ThenReturnInternalServerError() throws Exception {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(WireMock.get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(HttpStatus.SERVICE_UNAVAILABLE.value())));
|
||||
|
||||
ErrorResponse expectedError = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
"Product Api is unavailable","uri=/myapp2/product/" + productId);
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/myapp2/product/" + productId))
|
||||
.andExpect(status().isInternalServerError()).andReturn();
|
||||
|
||||
ErrorResponse errorResponse = objectMapper.readValue(result.getResponse().getContentAsString(), ErrorResponse.class);
|
||||
|
||||
assertEquals(expectedError.getCode(), errorResponse.getCode());
|
||||
assertEquals(expectedError.getMessage(), errorResponse.getMessage());
|
||||
assertEquals(expectedError.getStatus(), errorResponse.getStatus());
|
||||
assertEquals(expectedError.getDetails(), errorResponse.getDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductIsNotFound_whenGetProductCalled_ThenReturnInternalServerError() throws Exception {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(WireMock.get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(HttpStatus.NOT_FOUND.value())));
|
||||
|
||||
ErrorResponse expectedError = new ErrorResponse(HttpStatus.NOT_FOUND,
|
||||
"Product not found","uri=/myapp2/product/" + productId);
|
||||
|
||||
MvcResult result = mockMvc.perform(get("/myapp2/product/" + productId))
|
||||
.andExpect(status().isNotFound()).andReturn();
|
||||
|
||||
ErrorResponse errorResponse = objectMapper.readValue(result.getResponse().getContentAsString(), ErrorResponse.class);
|
||||
|
||||
assertEquals(expectedError.getCode(), errorResponse.getCode());
|
||||
assertEquals(expectedError.getMessage(), errorResponse.getMessage());
|
||||
assertEquals(expectedError.getStatus(), errorResponse.getStatus());
|
||||
assertEquals(expectedError.getDetails(), errorResponse.getDetails());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.client;
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.model.Product;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import feign.FeignException;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class ProductClientUnitTest {
|
||||
|
||||
@Autowired
|
||||
private ProductClient productClient;
|
||||
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
@Before
|
||||
public void startWireMockServer() {
|
||||
wireMockServer = new WireMockServer(8081);
|
||||
configureFor("localhost", 8081);
|
||||
wireMockServer.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopWireMockServer() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductIsAvailable_whenGetProductCalled_thenReturnMatchingProduct() {
|
||||
String productId = "test";
|
||||
|
||||
String productResponse = "{ " +
|
||||
" \"id\":\"test\",\n" +
|
||||
" \"productName\":\"Watermelon\",\n" +
|
||||
" \"price\":12\n" +
|
||||
"}";
|
||||
|
||||
stubFor(get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(HttpStatus.OK.value())
|
||||
.withHeader("Content-Type", "application/json")
|
||||
.withBody(productResponse)));
|
||||
|
||||
Product product = productClient.getProduct(productId);
|
||||
|
||||
assertEquals(productId, product.getId());
|
||||
assertEquals("Watermelon", product.getProductName());
|
||||
assertEquals(12.00d, product.getPrice(), 0.00d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductApiIsNotAvailable_whenGetProductCalled_thenThrowFeignException() {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(HttpStatus.SERVICE_UNAVAILABLE.value())));
|
||||
|
||||
assertThrows(FeignException.class, () -> productClient.getProduct(productId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductIdNotFound_whenGetProductCalled_thenThrowFeignException() {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse()
|
||||
.withStatus(HttpStatus.NOT_FOUND.value())));
|
||||
|
||||
assertThrows(FeignException.class, () -> productClient.getProduct(productId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.controller;
|
||||
|
||||
import com.baeldung.cloud.openfeign.defaulterrorhandling.client.ProductClient;
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.cloud.openfeign.FeignAutoConfiguration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(ProductController.class)
|
||||
@ImportAutoConfiguration({FeignAutoConfiguration.class, TestControllerAdvice.class})
|
||||
@EnableWebMvc
|
||||
public class ProductControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private ProductClient productClient;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private WireMockServer wireMockServer;
|
||||
|
||||
@Before
|
||||
public void startWireMockServer() {
|
||||
wireMockServer = new WireMockServer(8081);
|
||||
configureFor("localhost", 8081);
|
||||
wireMockServer.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopWireMockServer() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenProductServiceIsnotAvailable_whenGetProductCalled_thenReturnInternalServerError() throws Exception {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(WireMock.get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse().withStatus(HttpStatus.SERVICE_UNAVAILABLE.value())));
|
||||
|
||||
mockMvc.perform(get("/myapp1/product/" + productId))
|
||||
.andExpect(status().is(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void givenProductIsNotFound_whenGetProductCalled_thenReturnBadeRequestError() throws Exception {
|
||||
String productId = "test";
|
||||
|
||||
stubFor(WireMock.get(urlEqualTo("/product/" + productId))
|
||||
.willReturn(aResponse().withStatus(HttpStatus.NOT_FOUND.value())));
|
||||
|
||||
mockMvc.perform(get("/myapp1/product/" +productId))
|
||||
.andExpect(status().is(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.cloud.openfeign.defaulterrorhandling.controller;
|
||||
|
||||
import feign.FeignException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class TestControllerAdvice {
|
||||
|
||||
@ExceptionHandler({FeignException.class})
|
||||
public ResponseEntity<Object> handleFeignException(FeignException exception) {
|
||||
return new ResponseEntity<>(exception.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue