So I am getting a 400 for my HTTP response code when it should be 200. I am passing in a byte[] object to the endpoint but it doesn't seem to be adding the content-type correctly? Any suggestions?
#RequestMapping(value = "/test", method = RequestMethod.POST, consumes = "application/octet-stream")
public ResponseEntity<String> receiveCompressedBinary(#RequestHeader String site, #RequestHeader String customer,
#RequestHeader String table, #RequestBody byte[] binary, #RequestHeader String loadStatus) {
if(binary.length < maxFileSize) {
return new ResponseEntity<String>(HttpStatus.OK);
}
else{
return new ResponseEntity<String>(HttpStatus.PAYLOAD_TOO_LARGE);
}
}
My test:
#Test
public void testUploadCompressedBinaryInitialRunning() throws Exception{
File file = new File("src/test/resources/testFile.txt");
String site = "site";
String customer = "customer";
String table = "table";
String loadStatus = "INITIALRUNNING";
this.mockMvc.perform(post("/test").header("site",site).param("customer",customer).
param("table", table).content(compress(file)).param("loadStatus",loadStatus)
.with(user("user"))).andExpect(status().isOk());
this.mockMvc.perform(post("/uploadCompressedBinary")).andDo(print()).andExpect(status().isOk());
}
Compress method:
public static byte[] compress(File file) throws IOException {
if (file.length() == 0) {
return null;
}
FileInputStream fileInputStream = null;
byte[] fileInBytes = new byte[(int)file.length()];
try {
//convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(fileInBytes);
fileInputStream.close();
} catch (IOException e) {
System.out.println("Exception whilst compressing the file: " + e.getMessage());
}
ByteArrayOutputStream obj = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(obj);
gzip.write(fileInBytes);
gzip.close();
return obj.toByteArray();
}
UPDATE: Got past it, rather than .param, I should be using .header
It does not look like you are setting the content type when you are posting.
Try
this.mockMvc.perform(post("/test").header("site",site).param("customer",customer).
param("table", table).content(compress(file)).contentType("application/octet-stream").param("loadStatus",loadStatus)
.with(user("user"))).andExpect(status().isOk());
Related
I have a problem about writing a test to upload Image in Amazon s3 in Spring Boot.
I tried to write its test method but I got an error shown below.
How can I fix it?
Here is the method of Rest controller
#RestController
#RequestMapping("/api/v1/bookImage")
#RequiredArgsConstructor
public class ImageRestController {
#PostMapping
public ResponseEntity<String> uploadImage(#RequestParam("bookId") Long bookId, #RequestParam("file") MultipartFile file) {
final String uploadImg = imageStoreService.uploadImg(convert(file), bookId);
service.saveImage(bookId, uploadImg);
return ResponseEntity.ok(uploadImg);
}
private File convert(final MultipartFile multipartFile) {
// convert multipartFile to File
File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(multipartFile.getBytes());
return file;
} catch (IOException e) {
throw new RuntimeException("Failed to convert multipartFile to File");
}
}
Here is the method of imageService.
public String uploadImg(File file, Long bookId) {
s3amazon.putObject(BUCKET_NAME, bookId.toString(), file);
return baseUrl + bookId;
}
Here is the test method shown below.
#Test
void itShouldGetImagePath_WhenValidBookIdAndFile() throws Exception{
// given - precondition or setup
String bookId = "1";
String imagePath = "amazon-imagepath";
String baseUrl = String.format(imagePath + "/%s", bookId);
Long bookIdValue = 1L;
MockMultipartFile uploadFile = new MockMultipartFile("file", new byte[1]);
// when - action or the behaviour that we are going test
when(imageStoreService.uploadImg(convert(uploadFile), bookIdValue)).thenReturn(baseUrl); -> HERE IS THE ERROR
// then - verify the output
mvc.perform(MockMvcRequestBuilders.multipart("/api/v1/bookImage")
.file(uploadFile)
.param("bookId", bookId))
.andExpect((ResultMatcher) content().string(baseUrl))
.andExpect(status().isOk());
}
private File convert(final MultipartFile multipartFile) {
// convert multipartFile to File
File file = new File(Objects.requireNonNull(multipartFile.getOriginalFilename()));
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(multipartFile.getBytes());
return file;
} catch (IOException e) {
throw new RuntimeException("Failed to convert multipartFile to File");
}
}
Here is the error : Failed to convert multipartFile to File (java.lang.RuntimeException: Failed to convert multipartFile to Filejava.io.FileNotFoundException: )
How can I fix it?
Here is the solution shown below.
#Test
void itShouldGetImagePath_WhenValidBookIdAndFile() throws Exception{
// given - precondition or setup
String bookId = "1";
String imagePath = "amazon-imagepath";
String baseUrl = String.format(imagePath + "/%s", bookId);
Long bookIdValue = 1L;
String fileName = "sample.png";
MockMultipartFile uploadFile =
new MockMultipartFile("file", fileName, "image/png", "Some bytes".getBytes());
// when - action or the behaviour that we are going test
when(imageStoreService.uploadImg(convert(uploadFile), bookIdValue)).thenReturn(baseUrl);
doNothing().when(bookSaveService).saveImage(bookIdValue,baseUrl);
// then - verify the output
mvc.perform(MockMvcRequestBuilders.multipart("/api/v1/bookImage")
.file(uploadFile)
.param("bookId", bookId))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$").value(baseUrl))
.andExpect(content().string(baseUrl));
}
#RequestMapping(value = "/video/{clientID}/{fileName}", method = RequestMethod.GET)
public ResponseEntity<StreamingResponseBody> getClientVideo(#PathVariable(value = "clientID") Integer clientID, #PathVariable(value = "fileName") final String fileName) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
String absolutePath = new File(".").getAbsolutePath();
File file = new File(Paths.get(absolutePath).getParent() + "/" + clientID);
if (null != file) {
FilenameFilter beginswithm = new FilenameFilter() {
public boolean accept(File directory, String filename) {
return filename.contains("ClientVideo_"+fileName);
}
};
File[] files = file.listFiles(beginswithm);
if (null != files && files.length > 0) {
Resource resource = null;
for (final File f : files) {
headers.set("Content-Disposition", "inline; filename=" + f.getName());
StreamingResponseBody responseBody = new StreamingResponseBody() {
#Override
public void writeTo(OutputStream out) throws IOException {
out.write(Files.readAllBytes(f.toPath()));
out.flush();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(responseBody); //(responseBody, headers, HttpStatus.OK);
}
}
}
RecruiterResponseBean resBean = new RecruiterResponseBean();
resBean.setStatusMessage("Video is not present : " + Constants.FAILED);
resBean.setStatusCode(Constants.FAILED_CODE);
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
video streaming is working but it is very slow. how to increase the efficiency?
There is no problem with internet it is 10mbps. i am using tomcat 7 and Spring MVC[4.2.4]. should I change the tomcat capacity or how it can be solve? i am not getting in google.
#RequestMapping(value = "/video/{clientID}/{fileName}", method = RequestMethod.GET)
public ResponseEntity<StreamingResponseBody> getClientVideo(#PathVariable(value = "clientID") Integer clientID, #PathVariable(value = "fileName") final String fileName) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
String absolutePath = new File(".").getAbsolutePath();
File file = new File(Paths.get(absolutePath).getParent() + "/" + clientID);
if (null != file) {
FilenameFilter beginswithm = new FilenameFilter() {
public boolean accept(File directory, String filename) {
return filename.contains("ClientVideo_"+fileName);
}
};
File[] files = file.listFiles(beginswithm);
if (null != files && files.length > 0) {
Resource resource = null;
for (final File f : files) {
headers.set("Content-Disposition", "inline; filename=" + f.getName());
StreamingResponseBody responseBody = new StreamingResponseBody() {
#Override
public void writeTo(OutputStream out) throws IOException {
out.write(Files.readAllBytes(f.toPath()));
out.flush();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(responseBody); //(responseBody, headers, HttpStatus.OK);
}
}
}
RecruiterResponseBean resBean = new RecruiterResponseBean();
resBean.setStatusMessage("Video is not present : " + Constants.FAILED);
resBean.setStatusCode(Constants.FAILED_CODE);
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
I am using Spring MVC, I tried many methods but all are downloading the video. Above code is streaming the video, the problem is: in firefox it is streaming but in crome it is downloading. I want to play streaming video in crome also like below ex.
[Ex streaming video: http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4]
Do I need to add more Headers? [if so, which headers need to add?]
Or Did i miss anything?
This question is based on this question.
With provided comments, i had written three different tests to validate properly set content-types.
#Test
public void testGetImageJpg_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_JPG);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.jpg").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_JPEG))
.andExpect(content().bytes(expectedBytes));
}
#Test
public void testGetImagePng_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_PNG);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.png").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_PNG))
.andExpect(content().bytes(expectedBytes));
}
#Test
public void testGetImageGif_ShouldSucceed() throws Exception {
File testImage = new File(TestConstants.TEST_IMAGE_GIF);
byte[] expectedBytes = IOUtils.toByteArray(new FileInputStream(testImage));
when(service.getImage(anyString(), anyString())).thenReturn(testImage);
mockMvc.perform(get("/getImage/id/bla.gif").sessionAttrs(session))
.andExpect(status().isOk()).andExpect(content().contentType(MediaType.IMAGE_GIF))
.andExpect(content().bytes(expectedBytes));
}
This is my controller, where all tests succeed:
#RequestMapping(value="/getImage/{id}/{path}", produces = {"image/png","image/jpeg","image/gif"})
#ResponseBody
byte[] getImage(#PathVariable("id") String id,
#PathVariable("path") String path) throws ImageNotFoundException {
File imageFile = service.getImage(id, path);
InputStream in;
try {
in = new FileInputStream(imageFile);
return IOUtils.toByteArray(in);
} catch (IOException e) {
throw new ImageNotFoundException();
}
}
But when I change the order of produces value to
produces = {"image/jpeg","image/png","image/gif"}
The test for png is failing:
java.lang.AssertionError: Content type expected:<image/png> but was:<image/jpeg>
Im little confused, that changing the order of produces values leads to different results.
Does anyone observed this, is it a bug or did I miss something ?
How to write a integration test when I'm uploading a image to the server. I've already written a test following this question and it's answer but mine is not working properly. I used JSON to send the image and expected status OK. But I'm getting:
org.springframework.web.utill.NestedServletException:Request
Processing Failed;nested exception is java.lang.illigulArgument
or http status 400 or 415. I guess the meaning is same. Below I've given my test portion and controller class portion.
Test portion:
#Test
public void updateAccountImage() throws Exception{
Account updateAccount = new Account();
updateAccount.setPassword("test");
updateAccount.setNamefirst("test");
updateAccount.setNamelast("test");
updateAccount.setEmail("test");
updateAccount.setCity("test");
updateAccount.setCountry("test");
updateAccount.setAbout("test");
BufferedImage img;
img = ImageIO.read(new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\Penguins.jpg"));
WritableRaster raster = img .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
byte[] testImage = data.getData();
updateAccount.setImage(testImage);
when(service.updateAccountImage(any(Account.class))).thenReturn(
updateAccount);
MockMultipartFile image = new MockMultipartFile("image", "", "application/json", "{\"image\": \"C:\\Users\\Public\\Pictures\\Sample Pictures\\Penguins.jpg\"}".getBytes());
mockMvc.perform(
MockMvcRequestBuilders.fileUpload("/accounts/test/updateImage")
.file(image))
.andDo(print())
.andExpect(status().isOk());
}
Controller portion:
#RequestMapping(value = "/accounts/{username}/updateImage", method = RequestMethod.POST)
public ResponseEntity<AccountResource> updateAccountImage(#PathVariable("username") String username,
#RequestParam(value="image", required = false) MultipartFile image) {
AccountResource resource =new AccountResource();
if (!image.isEmpty()) {
try {
resource.setImage(image.getBytes());
resource.setUsername(username);
} catch (IOException e) {
e.printStackTrace();
}
}
Account account = accountService.updateAccountImage(resource.toAccount());
if (account != null) {
AccountResource res = new AccountResourceAsm().toResource(account);
return new ResponseEntity<AccountResource>(res, HttpStatus.OK);
} else {
return new ResponseEntity<AccountResource>(HttpStatus.EXPECTATION_FAILED);
}
}
If I write my controller this way It shows IllegalArgument in Junit trace but no problem in console and no mock print as well. So, I replace Controller with this:
#RequestMapping(value = "/accounts/{username}/updateImage", method = RequestMethod.POST)
public ResponseEntity<AccountResource> updateAccountImage(#PathVariable("username") String username,
#RequestBody AccountResource resource) {
resource.setUsername(username);
Account account = accountService.updateAccountImage(resource.toAccount());
if (account != null) {
AccountResource res = new AccountResourceAsm().toResource(account);
return new ResponseEntity<AccountResource>(res, HttpStatus.OK);
} else {
return new ResponseEntity<AccountResource>(HttpStatus.EXPECTATION_FAILED);
}
}
Than I have this output in console:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /accounts/test/updateImage
Parameters = {}
Headers = {Content-Type=[multipart/form-data;boundary=265001916915724]}
Handler:
Type = web.rest.mvc.AccountController
Method = public org.springframework.http.ResponseEntity<web.rest.resources.AccountResource> web.rest.mvc.AccountController.updateAccountImage(java.lang.String,web.rest.resources.AccountResource)
Async:
Was async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
MockHttpServletResponse:
Status = 415
Error message = null
Headers = {Accept=[application/octet-stream, text/plain;charset=ISO-8859-1, application/xml, text/xml, application/x-www-form-urlencoded, application/*+xml, multipart/form-data, application/json;charset=UTF-8, application/*+json;charset=UTF-8, */*]}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Now, I need to know how to solve this problem or should I take another approach and what is that.
The problem was because controller class is meant to receive multipart/form-data,but sent JSON data. There is another problem in this code. The controller returns the resource that having image inside. That causing processing failed. Right code is given below:
#test portion
Account updateAccount = new Account();
updateAccount.setPassword("test");
updateAccount.setNamefirst("test");
updateAccount.setNamelast("test");
updateAccount.setEmail("test");
updateAccount.setCity("test");
updateAccount.setCountry("test");
updateAccount.setAbout("test");
BufferedImage img;
img = ImageIO.read(new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\Penguins.jpg"));
WritableRaster raster = img .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
byte[] testImage = data.getData();
updateAccount.setImage(testImage);
FileInputStream fis = new FileInputStream("C:\\Users\\Public\\Pictures\\Sample Pictures\\Penguins.jpg");
MockMultipartFile image = new MockMultipartFile("image", fis);
HashMap<String, String> contentTypeParams = new HashMap<String, String>();
contentTypeParams.put("boundary", "265001916915724");
MediaType mediaType = new MediaType("multipart", "form-data", contentTypeParams);
when(service.updateAccountImage(any(Account.class))).thenReturn(
updateAccount);
mockMvc.perform(
MockMvcRequestBuilders.fileUpload("/accounts/test/updateImage")
.file(image)
.contentType(mediaType))
.andDo(print())
.andExpect(status().isOk());
Controller Portion:
#RequestMapping(value = "/{username}/updateImage", method = RequestMethod.POST)
public #ResponseBody
ResponseEntity<AccountResource> updateAccountImage(#PathVariable("username") String username,
#RequestParam("image") final MultipartFile file)throws IOException {
AccountResource resource =new AccountResource();
resource.setImage(file.getBytes());
resource.setUsername(username);
Account account = accountService.updateAccountImage(resource.toAccount());
if (account != null) {
AccountResource res = new AccountResourceAsm().toResource(account);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
return new ResponseEntity<AccountResource>(res,headers, HttpStatus.OK);
} else {
return new ResponseEntity<AccountResource>(HttpStatus.NO_CONTENT);
}
}
I can test this using apache.commons.httpClient library like shown below
#Test
public void testUpload() {
int statusCode = 0;
String methodResult = null;
String endpoint = SERVICE_HOST + "/upload/photo";
PostMethod post = new PostMethod(endpoint);
File file = new File("/home/me/Desktop/someFolder/image.jpg");
FileRequestEntity entity = new FileRequestEntity(file, "multipart/form-data");
post.setRequestEntity(entity);
try {
httpClient.executeMethod(post);
methodResult = post.getResponseBodyAsString();
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
statusCode = post.getStatusCode();
post.releaseConnection();
//...
}