I'm receiving a file using multipart/form-data like I'll show you right below (Using Spark, not SpringBoot):
#Override
public Object handle(Request request, Response response) throws Exception {
request.attribute("org.eclipse.jetty.multipartConfig", new MultipartConfigElement(""));
Part filePart = request.raw().getPart("file");
String regex = request.raw().getParameter("regex");
String fileName = filePart.getSubmittedFileName();
byte[] fileBytes = filePart.getInputStream().readAllBytes();
The thing is, I want to unit test this Controller, and in order to do so, I need a way to mock the request to have a multipart/form-data inside, or at least a way to use "when...theReturn" to mimic that part of code...
Any ideas?
Thanks in advance!
So I managed to find the answer to this question and I thought maybe I could help other people by answering it:
#Test
public void whenValidRegex_returnOkAndTotalAmount() throws Exception {
final Part file = mock(MultiPartInputStreamParser.MultiPart.class);
final Request mock = mock(Request.class); //Spark request
final Response mockResponse = mock(Response.class); //Spark response
final HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); //Javax servlet
when(mock.raw()).thenReturn(httpServletRequest);
when(file.getSubmittedFileName()).thenReturn("file.pdf");
when(mock.raw().getParameter("regex")).thenReturn(String.valueOf("SOME REGEX"));
when(mock.params("numPage")).thenReturn(String.valueOf("1"));
when(file.getInputStream()).thenReturn(IOUtils.toInputStream("ARGENTINIAN PESOS", Charset.defaultCharset())); //Here you are mocking the input stream you might get from the part file.
when(mock.raw().getPart("file")).thenReturn(file);
Now that you have the multipart/form-data mocked, you can continue your test mocking the service calls and such things.
Please ignore things that are from my specific code, like the "Page number" mocking, you don't need that.
Hope this helps for someone else.
Bye!
Related
I am developing a servlet for JAVA EE and keep getting this error "Error Viewerpage.index method has more than one entity. You must use only one entity parameter."
#ApplicationPath("REST2")
#Path("/viewer")
public class Viewerpage extends Application {
private GlobalConfiguration globalConfiguration;
private ViewerService viewerService;
#GET
#Path(value = "/viewer")
public Response index(String filename, String page, HttpServletResponse response) throws IOException {
// set headers before we write to response body
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.TEXT_HTML);
// render a page of a file based on a parameters from request
renderPage(filename, response.getOutputStream());
// complete response
response.flushBuffer();
String value = "redirect:index";
return Response.status(Response.Status.OK).entity(value).build();
}
private void renderPage(String filename, OutputStream outputStream) {
String filepath = "storage/" + filename;
// render first page
MemoryPageStreamFactory pageStreamFactory = new MemoryPageStreamFactory(outputStream);
HtmlViewOptions viewOptions = HtmlViewOptions.forEmbeddedResources(pageStreamFactory);
Viewer viewer = new Viewer(filepath);
viewer.view(viewOptions);
viewer.close();
}
}
Any ideas what cause this error?
When you declare a resource method, you can only have one parameter that is the request entity. The parameter without any annotations is considered the entity body. All other parameters must have some kind of annotation that specifies what it is and what should be injected. If they are query parameters, use #QueryParam. If it is a path parameter, use #PathParam. If it some other non-Param injectable (that is supported) e.g. HttpServletRequest, then use #Context. Other supported "Param" injectable types are #HeaderParam, #FormParam, #CookeParam, #MatrixParam, etc.
Think of the HTTP response that gets streamed to the client. You are sending it with
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(MediaType.TEXT_HTML);
renderPage(filename, response.getOutputStream());
response.flushBuffer();
But then, afterwards (when the response stream at most should be closed), you try to do something that looks like building a second response:
Response.status(Response.Status.OK).entity(value).build();
As every response can have only one set of header and body you cannot go back setting headers or sending a second response entity. That is what the error is about.
I consider myself a novice at unit-testing, completely new to Mockito and junit. I have to write unit-tests for some simple api-calls. But my test seems somewhat pointless to me, I can't tell where I am going wrong. I have added a method to an existing web-service, ManagerWS.java , See Below.
ManagerWS.java Method:
public String healthCheck(String userId) {
String healthCheckUrlEndpoint = this.baseUrl()+"/health";
logger.debug("Calling health check: {}", healthCheckUrlEndpoint);
HttpHeaders healthCheckHeaders = new HttpHeaders();
healthCheckHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
healthCheckHeaders.add(USER_KEY, userId);
healthCheckHeaders.add(TOKEN_NAME, TOKEN_VALUE);
healthCheckHeaders.add(Constants.ACCEPT_LANGUAGE_HEADER, LocaleContextHolder.getLocale().toString());
healthCheckHeaders.add(CORRELATION_HEADER, myService.get(AppLoggingMDCService.LOG_KEY_REQUEST_ID));
HttpEntity<Object> request = new HttpEntity<Object>(healthCheckHeaders);
ResponseEntity<String> response;
try {
response = makeRequest(HttpMethod.GET, healthCheckUrlEndpoint, request, String.class);
} catch (Exception e) {
logger.error("Exception encountered during health check", e);
throw e;
}
logger.debug("RESPONSE : http status: {} - body: {}", response.getStatusCode(), response.getBody());
return response.getStatusCode().toString();
}
The logic is simple. Construct the url, create headers and add headers to the request. make the request and extract the status-code from the response. Here is my test. NOTE: the class is using #RunWith(SpringRunner.class) and I am using #Mock for dependencies and #InjectMocks for the local instance ManagerWS. ManagerWS.java is the service calss being tested.
TEST-CLASS TEST-Method:
#Test
public void testHealthCheck() throws Exception {
//Given
managerWS = new ManagerWS(templateFactory, configParamService, mdcService, env);
String url = "http://baseurl/health";
HttpHeaders headers = new HttpHeaders();
HttpEntity<Object> request = new HttpEntity<Object>(headers);
ResponseEntity<String> response = new ResponseEntity<>(HttpStatus.OK);
//when
when(managerWS.makeRequest(HttpMethod.GET, url, request, String.class)).thenReturn(response);
String actualStatus = response.getStatusCode().toString();
//then
Assert.assertEquals("200",actualStatus);
}
To me this test seems stupid (for want of a batter word). I basicall set the status to give a "200" and assert that what i set is "200". That is not really making much sense.To me it literally does nothing. I tried using spy(ManagerWS.class). But I am literally grasping at straws without the full understanding.
SonarQube still complains with "Not covered by unit tests". I cam completely stumped as to how else to write this test. I also have to do similar tests for three other calls.
I am a total novice to testing and I cannot see my mistake. Please advise.
SonarQube still complains with "Not covered by unit tests".
Your unit test doesn't test from the entry point of the method to test : healthCheck(String), so it is not covered by unit tests.
Besides, you also mock the part of the method that you want to test :
when(managerWS.makeRequest(HttpMethod.GET, url, request, String.class)).thenReturn(response);
So indeed your approach looks wrong.
In fact, writing an unit test for this code looks wrong too or at least looks like a white box test with few value.
Why ?
Your logic depends on :
response = makeRequest(HttpMethod.GET, healthCheckUrlEndpoint, request, String.class);
But you can know if it works only at runtime, with a running HTTP Server.
So the single thing that you can do is mocking everything, spying the object under test and verifying that each statement in the implementation is performed : no readable test, no robust and few/no value.
Your method that relies essentially on side effect would make more sense to be tested with as an integration test :
ManagerWS managerWS; // real ManagerWS implementation without mock
#Test
public void healthCheck() throws Exception {
//Given
String url = "http://baseurl/health";
// When
String actual managerWS.healthCheck(url);
// Then
String expected = "...";
Assertions.assertEquals(expected, actual);
}
As a side note, if you used Spring, I would advise you to look at test slicing #WebMvcTest that focuses on the web part of the component under test. It allows mainly to test the HTTP part/logic (headers, request, response).
#RequestMapping(value = {"sms"},method = RequestMethod.POST)
public string rplyMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
Body body = new Body.Builder("Response message").build();
Message sms =
new Message.Builder().body(body).build();
MessagingResponse twiml = new MessagingResponse.Builder().message(sms).build();
response.setContentType("application/xml");
try {
response.getWriter().print(twiml.toXml());
} catch (TwiMLException e) {
e.printStackTrace();
}
}
This is how I handle the twilio response message.I want to get the content from the response message. and i want to store it in the database.How I can get the content from the response message.
Twilio developer evangelist here.
When Twilio makes a request to your application it sends the parameters encoded as application/x-www-form-urlencoded in the body of the POST request.
I've never written Java Spring MVC before, so excuse me if this isn't spot on, but I believe you can then read those parameters out of the body using the #RequestParam annotation.
#RequestMapping(value = {"sms"},method = RequestMethod.POST)
public string rplyMessage(
HttpServletRequest request,
HttpServletResponse response,
#RequestParam("Body") String message,
#RequestParam("From") String from
) throws IOException {
storeMessage(from, message);
// respond to the request
}
The message body and the number that sent it are the parameters "Body" and "From", you can see all the available request parameters here. So, for example with the message, you set the argument to #RequestParam to the name of the parameter, then you set the type and what you want the variable to be called within the method, thus: #RequestParam("Body") String message.
I don't know how you plan to use the database, but that's what I can tell you. You can read more about #RequestParam here and see some Twilio Java and Spring tutorials here.
Let me know if that helps at all.
I want send を伴う出力となって to backend java code via http get request.
My get call url is http://localhost:8080/test/getID?id=%E3%82%92%E4%BC%B4%E3%81%86%E5%87%BA%E5%8A%9B%E3%81%A8%E3%81%AA%E3%81%A3%E3%81%A6
Java code:
#RequestMapping(value = "/getCaseId")
public ModelAndView showCaseId(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String msg = request.getParameter("id");
System.out.println("URL:"+msg);
return new ModelAndView("showID", "idList", null);
}
Above piece of code prints URL:ãä¼´ãåºåã¨ãªã£ã¦.
So what's change i need to do get the exact Japanese text what i have passed from front end.
Try changing your msg line to:
String msg = new String(
request.getParameter("id").getBytes(StandardCharsets.ISO_8859_1),
StandardCharsets.UTF_8
);
If that will work it means that your application server (Tomcat? jetty?) is not configured correctly to handle UTF-8 in URLs.
If you use eclipse IDE, you need to check Text File encoding. Please check with the following figure.
The problem is that the submitted query string is getting mutilated on the way into your server-side script, because getParameter() uses ISO-8559-1 instead of UTF-8.
So i modified my code as below and now its working
#RequestMapping(value = "/getCaseId")
public ModelAndView showCaseId(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
String msg = new String(request.getParameter("id").getBytes("iso-8859-1"), "UTF-8")
System.out.println("URL:"+msg);
return new ModelAndView("showID", "idList", null);
}
I found this solution in http://help-forums.adobe.com/content/adobeforums/en/experience-manager-forum/adobe-experience-manager.topic.html/forum__lxgr-hi_i_am_havi.html.
Forgive me, but I may not be familiar with all the lingo necessary to ask this question properly.
I'm working on a fairly simple REST web service in Java using the org.apache.cxf.jaxrs.ext implementation of jax-rs. The method header is like this:
#GET
#Path("json/{fullAlias}")
#Produces({"application/json"})
public String json(#PathParam("fullAlias") String fullAlias, #Context MessageContext req)
where MessageContext is org.apache.cxf.jaxrs.ext.MessageContext.
There are two things I'm trying to accomplish that I can't seem to figure out:
Change the content-type if certain conditions are met (e.g. for an error)
Change the status code of the response
I've tried using changing the response by accessing it through the MessageContext:
HttpServletResponse response = req.getHttpServletResponse();
response.setContentType("text/plain")
response.setStatus("HttpServletResponse.SC_BAD_REQUEST);
But these changes have no bearing on the response sent; with or without the #Produces annotation, setting the content type inside the method doesn't affect the actual content type (With the annotation, it of course returns "application/json", without it defaults to "text/html").
I am returning a simple String as the body. I've entertained trying to return a javax.ws.rs.core.Response object to do what I want, but I don't know much about it.
How would I change the content type and/or the status codes from inside this method?
One approach is to throw a WebApplicationException, as described by Pace, which will work if you are looking to specifically handle an error condition. If you are looking to be able to change your content at any time for any reason, then you will want to take a look at returning a Response as the result of your service method rather than a String. Returning a Response gives you the greatest amount of control over how your service responds to the client request (it does require more code than returning a simple string).
Here is an example of how you would can make use of the Response object:
#GET
#Path("json/{fullAlias}")
public Response json(#PathParam("fullAlias") String fullAlias, #Context MessageContext req) {
...
if (success) {
ResponseBuilder rBuild = Response.ok(responseData, MediaType.APPLICATION_JSON);
return rBuild.build();
}
else {
ResponseBuilder rBuild = Response.status(Response.Status.BAD_REQUEST);
return rBuild.type(MediaType.TEXT_PLAIN)
.entity("error message")
.build();
}
}
I'm not sure if it's the best approach but I've done the following to solve your question #1.
public WebApplicationException createStatusException(String statusMessage) {
ResponseBuilder rb = Response.noContent();
rb = rb.type(MediaType.TEXT_PLAIN);
rb = rb.status(Status.BAD_REQUEST);
rb = rb.entity(statusMessage);
return new WebApplicationException(rb.build());
}
EDIT: I then threw the resulting WebApplicationException.
You can write your own Response Filter to change the content-type header.
#Provider
public class MimeAddingFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Content-Type", "image/png");
}
}
This filter will add the "image/png" content-type header. You can also change or remove headers in JAX-RS response filters.