PTAControllerTest.Java
#Test
public void testCreateProducerTeamAccess() throws Exception {
String expectedProducerId = "AGT02";
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
// Instantiate request DTO
ProducerTeamAccessPk newProducerTeamAccessPk = new ProducerTeamAccessPk(expectedProducerId, "ATL");
ProducerTeamAccessDto requestProducerTeamAccessDto = createMockProducerTeamAccessDto(newProducerTeamAccessPk);
ProducerTeamAccess createdProducerTeamAccess = producerTeamAccessMapper.map(requestProducerTeamAccessDto);
Mockito
.when(producerService.exists(Mockito.anyString()))
.thenReturn(true);
Mockito
.when(producerTeamAccessRepository.findById(ArgumentMatchers.any(ProducerTeamAccessPk.class)))
.thenReturn(Optional.of(createdProducerTeamAccess));
Mockito
.when(producerTeamAccessRepository.saveAndFlush(ArgumentMatchers.any(ProducerTeamAccess.class)))
.thenReturn(createdProducerTeamAccess);
Mockito
.doNothing()
.when(messageSender)
.sendCreated(Mockito.any(BaseDto.class));
String requestProducerTeamAccessDtoJson = objectMapper.writeValueAsString(requestProducerTeamAccessDto);
// remove keys that are not allowed to be set
DocumentContext doc = JsonPath.parse(requestProducerTeamAccessDtoJson);
doc.delete("links");
requestProducerTeamAccessDtoJson = doc.jsonString();
RequestBuilder request = RestDocumentationRequestBuilders
.post(controllerPath, expectedProducerId)
.content(requestProducerTeamAccessDtoJson)
.contentType(CustomMediaType.APPLICATION_AIM_API_V1_JSON_UTF8)
.accept(CustomMediaType.APPLICATION_AIM_API_V1_JSON_UTF8);
MvcResult result = this.mockMvc
.perform(request)
.andExpect(status().isCreated())
.andDo(document("{method-name}",
resourceDetails()
.description("To create a new ProducerTeamAccess resource, POST a JSON resource representation to the /producerTeamAccesss endpoint with the content being a single JSON object containing all of the required ProducerTeamAccess fields, and additionally any optional fields. You may include the TeamId field in your request, but it will be ignored, and instead will be saved with the newly created resource ID as assigned by the server. " +
"Upon acceptance and successful processing a request to create a new ProducerTeamAccess resource, the server will respond with a 201 Created and a Location header indicating the URI of the newly created ProducerTeamAccess resource.")
.summary("Create a ProducerTeamAccess resource")
.requestSchema(Schema.schema("ProducerTeamAccessDto"))
.tag(TAG),
pathParameters(
parameterWithName("producerId").description("producerId of the ProducerTeamAccess to create")),
getRequestProducerTeamAccessDto(false)))
.andReturn();
}
PTAService.java
public ProducerTeamAccessDto save(String producerId, ProducerTeamAccessCreateDto producerTeamAccessCreateDto) {
this.validate(producerId, producerTeamAccessCreateDto);
ProducerTeamAccess ProducerTeamAccessToSave = producerTeamAccessMapper.mapFromCreateDto(producerTeamAccessCreateDto);
ProducerTeamAccessToSave.setProducerId(producerId);
ProducerTeamAccessToSave.setCreatedById(UserSession.getUserId());
ProducerTeamAccessToSave.setDateAdded(Date.now());
ProducerTeamAccessToSave.setModifiedById(UserSession.getUserId());
ProducerTeamAccessToSave.setDateModified(Date.now());
ProducerTeamAccess newProducerTeamAccess = ProducerTeamAccessRepository.saveAndFlush(ProducerTeamAccessToSave);
return producerTeamAccessMapper.map(newProducerTeamAccess);
}
public ResponseEntity<Void> createProducerTeamAccess(
#PathVariable("producerId") String producerId,
#RequestBody ProducerTeamAccessCreateDto producerTeamAccessCreateDto, UriComponentsBuilder ucBuilder) {
logger.info("Creating ProducerTeamAccess.");
ProducerTeamAccessDto newProducerTeamAccessDto = producerTeamAccessService.save(producerId, producerTeamAccessCreateDto);
try {
messageSender.sendCreated(newProducerTeamAccessDto);
}
catch (Exception e) {
logger.error("Exception occured while sending the ProducerTeamAccess create message to the Queue");
}
// redirect to newly created ProducerTeamAccess record
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ucBuilder.path(controllerPath + "/{teamId}").buildAndExpand(newProducerTeamAccessDto.getTeamId()).toUri());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
Related
I want to return a token response in my controller, my rest controller method is calling two services which are implementing Rest Template post method to call external apis.
My tokenservice layer requires a parameter "code" to be passed into it.
When I try to write my rest controller method to implement my codeservice and only return string "code" back, the code is returned from the external Api.
But when I try to run the method implementing get code and return token in a single rest endpoint I get errors :
Stack trace:
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:785)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
Do I need to pass in both the Body(x-www-form-urlencoded and raw body) in a single call?
//RETRIEVE CODE SERVICE //
#Override
public String retrieveCode(String client_id, MUser mUser) {
String bUrl = "xxx";
String url = UriComponentsBuilder.fromUriString(bUrl)
.queryParam("clientId", client_id)
.build()
.toUriString();
HttpEntity<MUser> httpEntity = new HttpEntity<>(mUser, getHttpHeaders());
String code = "";
try {
ResponseEntity<MR> responseEntity = this.restTemplate.postForEntity(url, httpEntity, MR.class);
code = responseEntity.getBody().getCode();
} catch(HttpClientErrorException | HttpServerErrorException httpException) {
log.error("Could not retrieve code: {}" httpException.getMessage());
}
return code;
}
protected HttpHeaders getHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
return headers;
}
//TOKEN SERVICE //
#Override
public Token retrieveToken(String code, boolean c1, boolean c2) {
String url = UriComponentsBuilder.fromUriString(authProperties.getTokenUrl())
.build().toUriString();
HttpEntity<MultiValueMap<String, String>> entity = getHttpEntity(code, p1, p2);
ResponseEntity<Token> responseEntity = this.restTemplate.postForEntity(url, entity, Token.class);
return responseREntity.getBody();
}
protected Http<MultiValueMap<String, String>> getHttpEntity(String code, boolean c1, boolean c2Refresh) {
MultiValueMao<String, String> map = new LinkedMultiValueMap();
if(c1 || c2Refresh) {
map.add(CLIENT_ID, this.authTokenServiceConfig.getC1ClientId());
map.add(CLIENT_SECRET, this.authTokenServiceConfig.getC1ClientSecret());
} else {
map.add(CLEINT_ID, this.authTokenServiceConfig.getFClientId());
map.add(CLIENT_SECRET, this.authTokenServiceConfig.getFClientSecret());
}
map.add(CODE, code);
map.add(GRANT_TYPE, AUTHORIZATION_CODE);
map.add(REDIRECT_URI, authProperties.getRegisteredRedirectURL())
return new HttpEntity<>(map, getHttpHeaders());
}
protected HttpHeaders getHttpHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
return headers;
}
// REST CONTROLLER METHOD //
#PostMapping(value = "/mauth")
public Token mAuthorize(#RequestParam(required= true) String clientId, #RequestBody MUser mUser) {
String code = authService.retrieveCode(clientId, mUser);
Token token = authTokenService.retrieveToken(code, false, false); // when I comment this line out and return just the String code It works properly
return token;
}
enter image description here
i have a problem testing an endpoint which use #ModelAttribute I don't know very well how to test with this annotation and the test response is java.lang.AssertionError: Content type not set , here is the controller method:
#PostMapping
public ResponseEntity<?> createTestimonials(#ModelAttribute(name = "testimonialsCreationDto") #Valid TestimonialsCreationDto testimonialsCreationDto) {
try {
return ResponseEntity.status(HttpStatus.CREATED).body(iTestimonials.createTestimonials(testimonialsCreationDto));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(e.getMessage());
}
}
Here is the test:
#Test
void createTestimonials() throws Exception {
//Given
String name = "Testimonio 159";
String contentTestimonial = name + " content!";
TestimonialsCreationDto testimonialsCreationDto = new TestimonialsCreationDto();
testimonialsCreationDto.setName(name);
testimonialsCreationDto.setContent(contentTestimonial);
//When
mockMvc.perform(post("/testimonials")
.flashAttr("testimonialsCreationDto", testimonialsCreationDto)
.contentType(MediaType.MULTIPART_FORM_DATA)
.content(objectMapper.writeValueAsString(testimonialsCreationDto))
.characterEncoding("UTF-8"))
//Then
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.name", is(name)))
.andExpect(jsonPath("$.content", is(contentTestimonial)));
verify(testimonialsService).createTestimonials(any());
}
MockHttpServletRequest:
HTTP Method = POST
Request URI = /testimonials
Parameters = {}
Headers = [Content-Type:"multipart/form-data;charset=UTF-8", Content-Length:"74"]
Body = {"name":"Testimonio 159","image":null,"content":"Testimonio 159 content!"}
Session Attrs = {}
MockHttpServletResponse:
Status = 200 ---> IDK why response with 200 code
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Content type not set
You have to add path value to PostMapping :
#PostMapping(path = "/testimonials", produces = MediaType.MULTIPART_FORM_DATA)
Using Spring boot 2 and Spring mvc. I am trying to test my rest controller using mockMvc
#PostMapping(
value = "/attachment")
public ResponseEntity attachment(MultipartHttpServletRequest file, #RequestBody DocumentRequest body) {
Document document;
try {
document = documentService.process(file.getFile("file"), body);
} catch (IOException | NullPointerException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
return ResponseEntity.accepted().body(DocumentUploadSuccess.of(
document.getId(),
"Document Uploaded",
LocalDateTime.now()
));
}
I could attach the file successfully on my test but know I added a body and I can't receive both attached
#Test
#DisplayName("Upload Document")
public void testController() throws Exception {
byte[] attachedfile = IOUtils.resourceToByteArray("/request/document-text.txt");
MockMultipartFile mockMultipartFile = new MockMultipartFile("file", "",
"text/plain", attachedfile);
DocumentRequest documentRequest = new DocumentRequest();
documentRequest.setApplicationId("_APP_ID");
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.fileUpload("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest));
MvcResult result = mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isAccepted())
.andDo(MockMvcResultHandlers.print()).andReturn();
JsonNode response = objectMapper.readTree(result.getResponse().getContentAsString());
String id = response.get("id").asText();
Assert.assertTrue(documentRepository.findById(id).isPresent());
}
I got 415 status error
java.lang.AssertionError: Status expected:<202> but was:<415>
Expected :202
Actual :415
How could I fix it?
You're getting status 415: unsupported media type.
You needed to changed add contentType() of the request which the controller accepts.
If your controller accepts application/json:
MockHttpServletRequestBuilder builder =
MockMvcRequestBuilders
.multipart("/attachment")
.file(mockMultipartFile)
.content(objectMapper.writeValueAsString(documentRequest))
.contentType(MediaType.APPLICATION_JSON);// <<<
My application under tests has endpoint defined like below:
#ResponseBody
#RequestMapping(value = "maxsize", method = RequestMethod.POST)
public ResponseEntity<Void> changeMaxQuoteSize(#RequestBody DataRequest dataRequest,
#AuthenticationPrincipal UserProfile userProfile) {
orderManager.scheduleUpdateCurrencyConfigRules(dataRequest.getCurrency(),
(c) -> c.setMaxQuoteSize(dataRequest.getMaxSize()))
return ResponseEntity.status(HttpStatus.OK).build();
}
I want to sent message to it using rest-assured but my question is how to map request body to DataRequest object ?
I tried it that way:
class DateRq {
private String curpair;
private Double maxQuoteSize;
public DateRq(String curpair, Double maxQuoteSize) {
this.curpair = curpair;
this.maxQuoteSize = maxQuoteSize;
}
}
#Test
public void test() {
String endpoint = "http://127.0.0.1:8095/api/maxsize";
DateRq request = new DateRq(TICKER_SYMBOL, 5_000_000D);
Response response = RestAssured.given()
.when()
.body(request)
.post(endpoint);
assertEquals(200, response.getStatusCode());
}
but receive such error:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com...PMTest$DateRq and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
I tried with some kind of JSON but we didn't receive any response:
#Test
public void test() {
String endpoint = "http://127.0.0.1:8095/api/maxsize";
String request = new JSONObject()
.put("curpair", TICKER_SYMBOL)
.put("maxQuoteSize", 5_000_000D)
.toString();
Response response = RestAssured.given()
.when()
.body(request)
.post(endpoint);
assertEquals(200, response.getStatusCode());
}
Have you tried code like this?
DateRq request = new DateRq(TICKER_SYMBOL, 5_000_000D);
Response response = RestAssured.given()
.body(request)
.when()
.post(endpoint);
I have the following code:
#RequestMapping(
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE},
path = "api/api1",
method = RequestMethod.POST,
produces = MediaType.ALL_VALUE
)
public ResponseEntity<?> api1CallBack(#RequestBody String requestBody, HttpServletRequest request) throws IOException, GeneralSecurityException, URISyntaxException {
String response="{SOME_JSON}";
URI callbackURL = new URI("http://otherAPIEnv/api2");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setLocation(callbackURL);
return new ResponseEntity<String>(response,httpHeaders, HttpStatus.OK);
}
I tried the above code, but when I hit the api1 through my curl I get the response on the same machine, but I want the response to be redirected to api2 at otherAPIEnv machine.
Could someone please suggest how to achieve this kind of request and response?
When you send a request to a URL it should respond to the same otherwise client will be in waiting for it until it times out.
So, the approach should be different in this scenario.
First, in your main rest API you have to send a response code to release the client.
Then, in the API method you have to call another method asynchronously which calls api2 and performs the desired operation.
Here is a simple example.
#Autowired
API2Caller api2Caller;
#RequestMapping(
consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE},
path = "api/api1",
method = RequestMethod.POST,
produces = MediaType.ALL_VALUE
)
#ResponseStatus(HttpStatus.ACCEPTED)
public void api1CallBack(#RequestBody String requestBody, HttpServletRequest request) throws IOException, GeneralSecurityException, URISyntaxException {
api2Caller.callApi2(requestBody);
}
and the APICaller should look like following
#Component
public class API2Caller {
#Async
public SomeResultPojo callApi2() {
// use RestTemplate to call the api2
return restTemplate.postForObject("http://otherAPIEnv/api2", request, SomeResultPojo.class);
}
}
But you can choose your most comfortable way to perform asynchronous operation.
Look like a job for redirect.
String redirectMe() {
return "redirect:http://otherAPIEnv/api2"
}
As for the curl. You have POST mapping of the method so be sure to try it with curl -X POST... or change it to GET.
This the more modular and more generic way to do such kind of things:
public #ResponseBody ClientResponse updateDocStatus(MyRequest myRequest) {
ClientResponse clientResponse = new ClientResponse(CTConstants.FAILURE);
try {
HttpHeaders headers = prepareHeaders();
ClientRequest request = prepareRequestData(myRequest);
logger.info("cpa request is " + new Gson().toJson(request));
HttpEntity<ClientRequest> entity = new HttpEntity<ClientRequest>(request, headers);
String uri = cpaBaseUrl + updateDocUrl ;
ClientResponse serviceResponse = Utilities.sendHTTPRequest(uri, entity);
clientResponse = serviceResponse;
if (serviceResponse != null) {
if (CTConstants.SUCCESS.equalsIgnoreCase(serviceResponse.getStatus())) {
clientResponse.setStatus(CTConstants.SUCCESS);
clientResponse.setMessage(" update success.");
}
}
} catch (Exception e) {
logger.error("exception occurred ", e);
clientResponse.setStatus(CTConstants.ERROR);
clientResponse.setMessage(e.getMessage());
}
return clientResponse;
}
public static ClientResponse sendHTTPRequest(String uri, HttpEntity<ClientRequest> entity) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new SimpleClientHttpRequestFactory());
SimpleClientHttpRequestFactory rf = (SimpleClientHttpRequestFactory) restTemplate.getRequestFactory();
rf.setReadTimeout(CTConstants.SERVICE_TIMEOUT);
rf.setConnectTimeout(CTConstants.SERVICE_TIMEOUT);
ParameterizedTypeReference<ClientResponse> ptr = new ParameterizedTypeReference<ClientResponse>() {
};
ResponseEntity<ClientResponse> postForObject = restTemplate.exchange(uri, HttpMethod.POST, entity, ptr);
return postForObject.getBody();
}
You need to use redirect and modify the return type of your method
public String api1CallBack(#RequestBody String requestBody, HttpServletRequest request) throws IOException {
return "redirect:http://otherAPIEnv/api2";
}