400 BAD_REQUEST. Can't catch Post request from RestTemplate.PostForEntity() call - spring

I have a Test method for testing to save a one-to-many cascade data into two tables: Customer and Address, but the controller is not able to catch the Post call in this cascade testing, however the controller can Post receive call from posting data only for the Customer table, without data for the ShippingAddress.
Here is the test case for posting cascade data for the Customer and ShippingAddress tables:
#Test
public void create_shipping_address_and_customer() throws Exception {
Customer newCustomer = new Customer("Alex", "Maxim", "alexmaxim#gmail.com", "43323222222");
ShippingAddress shippingAddress1 = new ShippingAddress("unit 1", "89 hanson road", "New York", "CA", "KKKDLDL");
newCustomer.addShippingAddress(shippingAddress1);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Customer> requestEntity = new HttpEntity<>(newCustomer, headers);
ResponseEntity<Customer> response = restTemplate.postForEntity("/customer/add", requestEntity, Customer.class);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
}
Error is:
[ERROR] Failures:
[ERROR] ShippingAddressControllerRestTemplateTest.create_shipping_address_and_customer:85 expected:<201 CREATED> but was:<400 BAD_REQUEST>
I have been stuck in this issue for more than a week, have tried to use exchange() method, still failed. Could anyone shred some light to me ?
Thanks

Related

How to perform Junit Test for DELETE method in Reactive Programming?

I am trying to use WebClient DELETE method. I am making synchronous call for DELETE method.
But, when I am using block() method to get the object. I am getting error.
#Test
public void deleteEmployeeSyncTest() {
log.info("Testing put employee request");
Map<String, String> headersMap = new HashMap<String, String>();
headersMap.put("user", "password");
MultiValueMap<String, String> queryParamsMap = new LinkedMultiValueMap<>();
queryParamsMap.put("idmProperty", Arrays.asList("queryparamavalue"));
Map<String, String> pathParamsMap = new HashMap<>();
pathParamsMap.put("id", "1");
WebClient.ResponseSpec deleteResponse =
restClient.deleteSync(clientIdm, restClientConfig.getEndpoints().get("idm"), "deleteEmployee",
headersMap, pathParamsMap, queryParamsMap);
Employee response = deleteResponse.bodyToMono(Employee.class).block();
log.info("Delete employee response results: {}", response);
//response.subscribe(result -> Assertions.assertNull(result));
}
It gives me error while getting response using block() method call. But, if I use subscribe() method call for Asynchronous transactions, it works.
Here is the error I am getting while running the test case.
org.springframework.web.reactive.function.client.WebClientResponseException$MethodNotAllowed: 405 Method Not Allowed from DELETE http://localhost:8080/test/delete/1?idmProperty=queryparamavalue
at org.springframework.web.reactive.function.client.WebClientResponseException.create(WebClientResponseException.java:204)

Spring Custom Exception hanlding

#ExceptionHandler(RecordAlreadyExistException.class)
public final ResponseEntity<Object> handleAlreadyExistRecordException(
RecordAlreadyExistException ex, WebRequest request) {
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse errorDetails = new ErrorResponse(
"Already registered user ? Did you forget your password ? Please contact anemail#gmail.com for all queries", details);
return new ResponseEntity(errorDetails, HttpStatus.NOT_FOUND);
}
Here is my scenario:
When the user already exists,
it should throw this custom exception.
I get the response code,
but not the body
(i.e. the error details I passed in the response entity are
not displayed in the browser).
Any idea?

How to use #MockBean and MockMvc to append some data with HTTP POST to a mocked repository

I have a controller with a POST action, that creates a new BLOGPOST and return all the BLOGPOSTS including the newly created one:
#Autowired
private BlogPostInMemRepository bpr;
#RequestMapping(method = RequestMethod.POST, path="/post",
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public #ResponseBody List<BlogPost> addPost(BlogPost post) {
bpr.addPost(post);
return bpr.getAllPosts();
}
The BlogPostInMemRepository code looks like this:
#Repository
public class BlogPostInMemRepository {
private List<BlogPost> posts = new ArrayList<BlogPost>(){{
add(new BlogPost(1, "Author1", "Post 1"));
add(new BlogPost(2, "Author2", "Post 2"));
}};
public List<BlogPost> getAllPosts(){
return posts;
}
public void addPost(BlogPost post){
posts.add(post);
}
}
My goal is to unit test the controller using #MockBean and MockMvc. The steps would be:
Mock the BlogPostInMemRepository injecting some initial data into it
Issue a post request with mockMvc.perform(post("/api/v1/post")
Get back the initial post with the new post successfully added.
My current tests:
#Test
public void post_whenValidParametersPassed_addsAndReturnsAllBlogPostsSuccessfully() throws Exception {
// given
BlogPost bp1 = new BlogPost(1, "John", "Post 1");
BlogPost bp2 = new BlogPost(2, "Jack", "Post 2");
List<BlogPost> posts = new ArrayList<BlogPost>(){{ add(bp1); add(bp2); }};
given(repo.getAllPosts()).willReturn(posts);
mockMvc.perform(post("/api/v1/post")
.contentType(APPLICATION_FORM_URLENCODED)
.param("id", "33")
.param("author", "Gibraltar")
.param("post", "There is now way!"))
.andExpect(status().isOk())
.andExpect(content().string("{... the whole string ...}"))
.andDo(print());
}
What I get is just the posts passed in: given(repo.getAllPosts()).willReturn(posts); - which is expected, of course.
QUESTION: how to actually inject the initial set of BLOGPOSTS, add one more with POST and get all of them back from a mocked repository?
If you are planning to mock the repository it does not really make much sense to follow your approach as the addPost will have no effect and getAllPosts would just assume it has been added. It seems a bit artificial and not bring any real value testing-wise.
What I would do here is to use a simple in-order verification:
InOrder inOrder = Mockito.inOrder(brp);
inOrder.verify(brp).addPost(any(Post.class));
inOrder.verify(brp).getAllPosts();
So to make sure the post is added before all of them are fetched from the repo.
Solved it by using doCallRealMethod() and when().thenCallRealMethod() - this seems to be the only way to inject controller data from "down-below (bottom-up)" using Mockito, as direct setters do not work on #MockBean's.
Code:
#Test
public void post_whenValidParametersPassedAndPreExistingBlogsPresent_addsAndReturnsAllBlogPostSuccessfully() throws Exception {
// given : initialize mock data
BlogPost bp1 = new BlogPost(1, "John", "Post 1");
BlogPost bp2 = new BlogPost(2, "Jack", "Post 2");
List<BlogPost> posts = new ArrayList<BlogPost>(){{ add(bp1); add(bp2); }};
// given : prep the mocked object
doCallRealMethod().when(repo).setPosts(posts);
doCallRealMethod().when(repo).addPost(any(BlogPost.class));
repo.setPosts(posts);
when(repo.getAllPosts()).thenCallRealMethod();
mockMvc.perform(post("/api/v1/post")
.contentType(APPLICATION_FORM_URLENCODED) //from MediaType
.param("id", "33")
.param("author", "Gibraltar")
.param("post", "There is now way!"))
.andExpect(status().isOk())
.andExpect(content().string("[" +
"{\"id\":1,\"author\":\"John\",\"post\":\"Post 1\"}," +
"{\"id\":2,\"author\":\"Jack\",\"post\":\"Post 2\"}," +
"{\"id\":33,\"author\":\"Gibraltar\",\"post\":\"There is now way!\"}" +
"]"))
.andDo(print());
}

java.lang.IllegalArgumentException: Comparison method violates its general contract! in Spring Rest Template

I am facing a weird issue while calling a REST url using Spring's RestTemplate.I am using Spring Boot.
The error is occurring only after approx 10 to 15 successful calls and thereafter erratically. I can smoothly exchange data before the error, in the first 1 to 15 calls approx. Url is like someresturl/param1/param2/param3.
public ResponseEntity<String> callRestUrl(CustomReqClass req) {
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
StringBuilder url = new StringBuilder("someresturl");
finishTaskUrl.append("/").append(param1).append("/").append(param2).append("/").append(param3);
ResponseEntity<String> response = null;
HttpEntity<CustomReqClass> request = new HttpEntity<CustomReqClass>(req, getHTTPHeaders());
try {
//first approach
response = restTemplate.postForEntity(url.toString(), request, String.class, Collections.<String, String>emptyMap());
//second approach
response = restTemplate.exchange(url.toString(), HttpMethod.POST, request, String.class);
} catch (Exception e) {
LOGGER.info("Error calling url" + e);
}
return response;
}
public MultiValueMap<String, String> getHTTPHeaders() {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Authorization", "Basic authabcdxyz");
headers.add("Content-Type", "application/json");
return headers;
}
Here I am autowiring restTemplate object in the class where I am using this.
I have tried both the above methods postForEntity and exchange of Rest template. Error is occurring for both.
The exception I am getting after first few successful attempts:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
As an additional thought, the above piece of code is being scheduled by Spring Scheduler mechanism. Is it possible internal threading used in scheduler is causing this issue?

RestTemplate - handle potential NullPointerException when response body is null

I'm writing client that calls some backend REST service. I'm sending Product object which will be saved in DB and returned in response body with generated productId.
public Long createProduct(Product product) {
RestTemplate restTemplate = new RestTemplate();
final String url = " ... ";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Product> productEntity = new HttpEntity<>(product, headers);
try {
ResponseEntity<Product> responseEntity = restTemplate.postForEntity(url, productEntity, Product.class);
Product product = responseEntity.getBody();
return product.getProductId();
} catch (HttpStatusCodeException e) {
logger.error("Create product failed: ", e);
throw new CustomException(e.getResponseBodyAsString(), e, e.getStatusCode().value());
}
This product.getProductId() looks like potential NullPointerException if product i.e. responseEntity.getBody() is null, should I handle it somehow?
I have looked examples over internet of using RestTemplate postFprEntity, getForEntity ... but didn't find any example that handle NPE. I suppose that if body of response cannot be set, it will be some exception thrown and status code 5xx.
Is it possible when response status code is 200, that body can be null?
Is it possible when response status code is 200, that body can be
null?
Yes, it is quite possible and totally depends on the server. Normally, some REST APIs and Spring REST Repositories will return 404 if resource is not found but better safe than sorry.
This product.getProductId() looks like potential NullPointerException
if product i.e. responseEntity.getBody() is null, should I handle it
somehow?
Of course you should.
You can check if responseEntity.hasBody() && responseEntity.getBody() != null. And from there either throw an Exception of your own or handle however you see fit.

Resources