/*******************************************************************************
* Copyright (c) 2013 GigaSpaces Technologies Ltd. All rights reserved
*
* 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.cloudifysource.rest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.time.DateUtils;
import org.cloudifysource.dsl.internal.CloudifyConstants;
import org.cloudifysource.dsl.internal.CloudifyMessageKeys;
import org.cloudifysource.dsl.rest.response.Response;
import org.cloudifysource.dsl.rest.response.UploadResponse;
import org.cloudifysource.rest.controllers.RestErrorException;
import org.cloudifysource.rest.controllers.UploadController;
import org.cloudifysource.rest.repo.UploadRepo;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import com.j_spaces.kernel.PlatformVersion;
/**
* A test for {@link UploadController}
* @author yael
*
*/
//Swap the default JUnit4 with the spring specific SpringJUnit4ClassRunner.
//This will allow spring to inject the application context
@RunWith(SpringJUnit4ClassRunner.class)
//Setup the configuration of the application context and the web mvc layer
@ContextConfiguration({"classpath:META-INF/spring/applicationContext.xml",
"classpath:META-INF/spring/webmvc-config-upload-test.xml" })
public class UploadControllerTest extends ControllerTest {
private static final Logger logger = Logger.getLogger(UploadControllerTest.class.getName());
private static final String UPLOAD_RESOURCES_PATH = "src" + File.separator + "test" + File.separator
+ "resources" + File.separator + "upload";
private static final String TEST_FILE_PATH = UPLOAD_RESOURCES_PATH + File.separator + "test.txt";
private static final String TEST_FILE1_PATH = UPLOAD_RESOURCES_PATH + File.separator + "test1.txt";
private static final String UPLOADED_FILE_NAME = "upload.zip";
private static final String UPLOAD_URI = "/upload/" + UPLOADED_FILE_NAME;
private String versionedUploadUri;
private HashMap<String, HashMap<RequestMethod, HandlerMethod>> controllerMapping;
private UploadController controller;
private UploadRepo uploadRepo;
private static final int TEST_UPLOAD_SIZE_LIMIT_BYTES = 10;
private static final int TEST_CLEANUP_TIMOUT_MILLIS = 3000;
@Before
public void init() throws NoSuchMethodException, RestErrorException {
String version = PlatformVersion.getVersion();
versionedUploadUri = "/" + version + UPLOAD_URI;
controller = applicationContext.getBean(UploadController.class);
uploadRepo = applicationContext.getBean(UploadRepo.class);
uploadRepo.init();
uploadRepo.setBaseDir(new File(CloudifyConstants.REST_FOLDER));
uploadRepo.createUploadDir();
controllerMapping = new HashMap<String, HashMap<RequestMethod, HandlerMethod>>();
HashMap<RequestMethod, HandlerMethod> map = new HashMap<RequestMethod, HandlerMethod>();
HandlerMethod method = new HandlerMethod(controller, "upload", String.class, MultipartFile.class);
map.put(RequestMethod.POST, method);
controllerMapping.put(versionedUploadUri, map);
}
@Override
public HandlerMethod getExpectedMethod(final String requestUri, final RequestMethod requestMethod) {
HashMap<RequestMethod, HandlerMethod> hashMap = controllerMapping.get(requestUri);
Assert.assertNotNull(hashMap);
return hashMap.get(requestMethod);
}
private UploadResponse uploadFile(final File file, final String testName)
throws Exception {
logger.log(Level.FINE,
"[" + testName + "] - trying to upload file " + file.getName()
+ ", repo upload size limit in bytes: " + uploadRepo.getUploadSizeLimitBytes()
+ ", repo cleanup timeout in millis: " + uploadRepo.getCleanupTimeoutMillis());
MockHttpServletResponse response;
try {
response = testPostFile(versionedUploadUri, file);
} catch (Exception e) {
logger.log(Level.WARNING, "upload response thrown an exception: " + e.getMessage());
throw e;
}
logger.log(Level.FINE, "upload response's content: " + response.getContentAsString());
ObjectMapper objectMapper = new ObjectMapper();
Response<UploadResponse> readValue = objectMapper.readValue(response.getContentAsString(),
new TypeReference<Response<UploadResponse>>() { });
UploadResponse uploadResponse = readValue.getResponse();
return uploadResponse;
}
@Test
public void testUpload() throws Exception {
File file = new File(TEST_FILE_PATH);
UploadResponse uploadResponse = uploadFile(file, "testUpload");
String uploadKey = uploadResponse.getUploadKey();
logger.log(Level.FINE, "file has been uploaded. the upload key is " + uploadKey);
Assert.assertNotNull(uploadKey);
assertUploadedFileExists(file, uploadKey);
}
@Test
public void testUploadDifferentName() throws Exception {
File file = new File(TEST_FILE1_PATH);
UploadResponse uploadResponse = uploadFile(file, "testUploadDifferentName");
String uploadKey = uploadResponse.getUploadKey();
Assert.assertNotNull(uploadKey);
assertUploadedFileExists(file, uploadKey);
}
@Test
public void testUploadExceededSizeLimitFile() throws Exception {
logger.log(Level.FINE, "set the upload size limit to " + TEST_UPLOAD_SIZE_LIMIT_BYTES + " bytes.");
uploadRepo.setUploadSizeLimitBytes(TEST_UPLOAD_SIZE_LIMIT_BYTES);
File uploadFile = new File(TEST_FILE_PATH);
MockHttpServletResponse response = null;
long fileSize = uploadFile.length();
logger.log(Level.FINE,
"trying to upload file of size " + fileSize
+ " expecting " + CloudifyMessageKeys.UPLOAD_FILE_SIZE_LIMIT_EXCEEDED.getName());
try {
response = testPostFile(versionedUploadUri, uploadFile);
Assert.fail("Tring to upload a file of zise " + fileSize + "expected to failed. response "
+ response.getContentAsString());
} catch (RestErrorException e) {
Map<String, Object> errorDescription = e.getErrorDescription();
String status = (String) errorDescription.get("status");
Assert.assertEquals("error", status);
String errorMsg = (String) errorDescription.get("error");
Assert.assertEquals(CloudifyMessageKeys.UPLOAD_FILE_SIZE_LIMIT_EXCEEDED.getName(), errorMsg);
Object[] args = (Object[]) errorDescription.get("error_args");
Object[] expectedArgs = {UPLOADED_FILE_NAME, fileSize, uploadRepo.getUploadSizeLimitBytes()};
Assert.assertArrayEquals(expectedArgs, args);
} finally {
logger.log(Level.FINE,
"setting the upload size limit back to "
+ CloudifyConstants.DEFAULT_UPLOAD_SIZE_LIMIT_BYTES + " bytes.");
uploadRepo.setUploadSizeLimitBytes(CloudifyConstants.DEFAULT_UPLOAD_SIZE_LIMIT_BYTES);
}
}
@Test
public void testUploadTimeout() throws Exception {
int cleanupTimeoutMillis = uploadRepo.getCleanupTimeoutMillis();
logger.log(Level.FINE, "setting the cleanup timeout " + TEST_CLEANUP_TIMOUT_MILLIS + " millis.");
uploadRepo.resetTimeout(TEST_CLEANUP_TIMOUT_MILLIS);
try {
File file = new File(TEST_FILE_PATH);
UploadResponse uploadResponse = uploadFile(file, "testUploadTimeout");
String uploadKey = uploadResponse.getUploadKey();
logger.log(Level.FINE, "successfully uploaded file " + file.getName() + " upload key is " + uploadKey);
Assert.assertNotNull(uploadKey);
File uploadedFile = assertUploadedFileExists(file, uploadKey);
String parentPath = uploadedFile.getParentFile().getAbsolutePath();
logger.log(Level.INFO,
"sleeping for " + (TEST_CLEANUP_TIMOUT_MILLIS * 3) / DateUtils.MILLIS_PER_SECOND + " seconds");
Thread.sleep(TEST_CLEANUP_TIMOUT_MILLIS * 3);
File expectedToBeDeletedFolder = new File(parentPath);
logger.log(Level.FINE, "validate that the folder ["
+ expectedToBeDeletedFolder.getAbsolutePath() + "] was deleted:");
boolean exists = expectedToBeDeletedFolder.exists();
logger.log(Level.FINE, "The folder [" + expectedToBeDeletedFolder.getAbsolutePath()
+ "] (expected to be deleted at this point) " + (exists ? " exists" : " not exists."));
Assert.assertFalse(exists);
} finally {
logger.log(Level.FINE, "setting the cleanup timeout back to " + cleanupTimeoutMillis + " millis");
uploadRepo.resetTimeout(cleanupTimeoutMillis);
}
}
@Test
public void testUplaodFileNotExist() {
File file = new File("notExist.zip");
try {
uploadFile(file, "testUplaodFileNotExist");
Assert.fail("[testUplaodFileNotExist] - FileNotFoundException expected");
} catch (FileNotFoundException e) {
logger.log(Level.FINE, "cought exeption " + e.getMessage() + " as expected");
} catch (Exception e) {
Assert.fail("cought exception other than FileNotFoundException ["
+ e.getClass() + "] message: " + e.getMessage());
}
}
private File assertUploadedFileExists(final File expectedFile, final String uploadKey)
throws IOException {
File restTempDir = new File(CloudifyConstants.REST_FOLDER);
File uploadsFolder = new File(restTempDir, CloudifyConstants.UPLOADS_FOLDER_NAME);
File uploadedFileDir = new File(uploadsFolder, uploadKey);
logger.log(Level.FINE, "uploaded file's folder: " + uploadedFileDir.getAbsolutePath());
Assert.assertNotNull(uploadedFileDir);
logger.log(Level.FINE, "uploaded file's folder exists: " + uploadedFileDir.exists());
Assert.assertTrue(uploadedFileDir.exists());
logger.log(Level.FINE, "uploaded file's folder isDirectory: " + uploadedFileDir.isDirectory());
Assert.assertTrue(uploadedFileDir.isDirectory());
File uploadedFile = new File(uploadedFileDir, UPLOADED_FILE_NAME);
logger.log(Level.FINE, "uploaded file " + uploadedFile.getAbsolutePath()
+ (uploadedFile.exists() ? "" : " not") + " exists.");
Assert.assertTrue(uploadedFile.exists());
logger.log(Level.FINE, "uploaded file isFile: " + uploadedFile.isFile());
Assert.assertTrue(uploadedFile.isFile());
boolean contentEquals = FileUtils.contentEquals(expectedFile, uploadedFile);
logger.log(Level.FINE,
"uploaded file [" + uploadedFile.getAbsolutePath()
+ "] content is " + (contentEquals ? "" : "not")
+ " equal to the expected content [ of file - "
+ expectedFile.getAbsolutePath() + "]");
Assert.assertTrue(contentEquals);
return uploadedFile;
}
}