/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.uberfire.server; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URI; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.uberfire.io.IOService; import org.uberfire.java.nio.file.Path; import org.uberfire.server.util.FileServletUtil; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class FileUploadServletTest { //Parameters expected by the FileUploadServlet. private static final String PARAM_PATH = "path"; private static final String PARAM_FOLDER = "folder"; private static final String PARAM_FILENAME = "fileName"; private static final String TEST_ROOT_PATH = "default://master@test-repository/test-project/src/main/resources/test"; private static final String BOUNDARY = "---------------------------9051914041544843365972754266"; private static final String BOUNDARY_DELIMITER = "--"; private static final String CONTENT_TYPE = "multipart/form-data; boundary=\"" + BOUNDARY + "\""; /** * The Carriage Return ASCII character value. */ private static final byte CR = 0x0D; /** * The Line Feed ASCII character value. */ private static final byte LF = 0x0A; private static final String BREAK = new String(new char[]{CR, LF}); @Mock private IOService ioService; @InjectMocks private FileUploadServlet uploadServlet; /** * Tests the uploading of a file given the following parameters: * <p> * 1) a destination folder on the server side. * 2) a destination file name (with blank spaces). * @throws Exception */ @Test public void uploadByNameAndFolderWithSpaces() throws Exception { //test the upload of a file name with blank spaces into a given folder. String targetFileName = "File Name With Spaces.some extension"; String fileContent = "the local file content"; doUploadTestByNameAndFolder(targetFileName, TEST_ROOT_PATH, fileContent); } /** * Tests the uploading of a file given the following parameters: * <p> * 1) a destination folder on the server side. * 2) a destination file name (with NO blank spaces). * @throws Exception */ @Test public void uploadByNameAndFolderWithNoSpaces() throws Exception { //test the upload of a file name with NO blank spaces into a given folder. String targetFileName = "FileNameWithNoSpaces.someextension"; String fileContent = "the local file content"; doUploadTestByNameAndFolder(targetFileName, TEST_ROOT_PATH, fileContent); } /** * Tests the uploading of a file given the following parameters: * <p> * 1) a destination path, composed of a folder and a file name with blank spaces. * @throws Exception */ @Test public void uploadByPathWithSpaces() throws Exception { //test the upload of a file name with blank spaces into a given folder. String targetPath = TEST_ROOT_PATH + "/" + "File Name With Spaces.some extension"; String fileContent = "the local file content"; doUploadTestByPath(targetPath, fileContent); } /** * Tests the uploading of a file given the following parameters: * <p> * 1) a destination path, composed of a folder and a file name with no blank spaces. * @throws Exception */ @Test public void uploadByPathWithNoSpaces() throws Exception { //test the upload of a file name with blank spaces into a given folder. String targetPath = TEST_ROOT_PATH + "/" + "FileNameWithNoSpaces.someextension"; String fileContent = "the local file content"; doUploadTestByPath(targetPath, fileContent); } private void doUploadTestByNameAndFolder(String targetFileName, String targetFolderName, String fileContent) throws Exception { HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); String localFileName = "local_file_name.txt"; //not relevant for the test //mock the servlet parameters when(request.getParameter(PARAM_FOLDER)).thenReturn(targetFolderName); when(request.getParameter(PARAM_FILENAME)).thenReturn(targetFileName); //mock the servlet multipart request //local file name, and local file name content are not relevant String requestContent = mockMultipartRequestContent(localFileName, fileContent); ByteArrayInputStream inputStream = new ByteArrayInputStream(requestContent.getBytes()); MockServletInputStream servletInputStream = new MockServletInputStream(inputStream); when(request.getContentLength()).thenReturn(requestContent.getBytes().length); when(request.getContentType()).thenReturn(CONTENT_TYPE); when(request.getInputStream()).thenReturn(servletInputStream); //mock the servlet response writer ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream); when(response.getWriter()).thenReturn(printWriter); //FileUploadServlet uploadServlet = new FileUploadServlet(); uploadServlet.doPost(request, response); verify(request, times(1)).getParameter(PARAM_PATH); verify(request, times(2)).getParameter(PARAM_FOLDER); verify(request, times(1)).getParameter(PARAM_FILENAME); //Expected URI URI expectedURI = new URI(targetFolderName + "/" + FileServletUtil.encodeFileName(targetFileName)); verify(ioService, times(1)).get(eq(expectedURI)); verify(ioService, times(1)).exists(any(Path.class)); verify(ioService, times(1)).write(any(Path.class), eq(fileContent.getBytes())); printWriter.flush(); assertEquals("OK", new String(outputStream.toByteArray())); } private void doUploadTestByPath(String targetPath, String fileContent) throws Exception { HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(HttpServletResponse.class); String localFileName = "local_file_name.txt"; //not relevant for the test //mock the servlet parameters when(request.getParameter(PARAM_PATH)).thenReturn(targetPath); //mock the servlet multipart request //local file name, and local file name content are not relevant String requestContent = mockMultipartRequestContent(localFileName, fileContent); ByteArrayInputStream inputStream = new ByteArrayInputStream(requestContent.getBytes()); MockServletInputStream servletInputStream = new MockServletInputStream(inputStream); when(request.getContentLength()).thenReturn(requestContent.getBytes().length); when(request.getContentType()).thenReturn(CONTENT_TYPE); when(request.getInputStream()).thenReturn(servletInputStream); //mock the servlet response writer ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream); when(response.getWriter()).thenReturn(printWriter); uploadServlet.doPost(request, response); verify(request, times(2)).getParameter(PARAM_PATH); //Expected URI URI expectedURI = new URI(FileServletUtil.encodeFileNamePart(targetPath)); verify(ioService, times(1)).get(eq(expectedURI)); verify(ioService, times(1)).exists(any(Path.class)); verify(ioService, times(1)).write(any(Path.class), eq(fileContent.getBytes())); printWriter.flush(); assertEquals("OK", new String(outputStream.toByteArray())); } private String mockMultipartRequestContent(String localFileName, String fileContent) { String content = BOUNDARY_DELIMITER + BOUNDARY + BREAK + "Content-Disposition: form-data; name=\"file\"; filename=\"" + localFileName + "\"" + BREAK + "Content-Type: text/plain" + BREAK + BREAK + fileContent + BREAK + BOUNDARY_DELIMITER + BOUNDARY + BOUNDARY_DELIMITER + BREAK; return content; } private class MockServletInputStream extends ServletInputStream { InputStream content; public MockServletInputStream(InputStream content) { this.content = content; } @Override public int read() throws IOException { return content.read(); } @Override public int read(byte[] b) throws IOException { return content.read(b); } @Override public int read(byte[] b, int off, int len) throws IOException { return content.read(b, off, len); } @Override public long skip(long n) throws IOException { return content.skip(n); } @Override public int available() throws IOException { return content.available(); } @Override public void close() throws IOException { content.close(); } @Override public synchronized void mark(int readlimit) { content.mark(readlimit); } @Override public synchronized void reset() throws IOException { content.reset(); } @Override public boolean markSupported() { return content.markSupported(); } @Override public boolean isFinished() { try { return content.available() <= 0; } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean isReady() { return true; } @Override public void setReadListener(ReadListener readListener) { // TODO how to treat the listener? } } }