/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* 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 com.alibaba.citrus.service.upload;
import static com.alibaba.citrus.test.TestEnvStatic.*;
import static org.junit.Assert.*;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.citrus.service.upload.impl.cfu.DiskFileItem;
import com.alibaba.citrus.springext.support.context.XmlBeanFactory;
import com.alibaba.citrus.util.io.StreamUtil;
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import com.meterware.servletunit.InvocationContext;
import com.meterware.servletunit.ServletRunner;
import com.meterware.servletunit.ServletUnitClient;
import com.meterware.servletunit.UploadServletRunner;
import org.apache.commons.fileupload.FileItem;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.FileSystemResource;
/**
* 测试<code>UploadService</code>。
*
* @author Michael Zhou
*/
public class UploadServiceTests {
private static File 中文文件名;
private static BeanFactory factory;
private UploadService upload;
private ServletUnitClient client;
private HttpServletRequest request;
@BeforeClass
public static void initFactory() throws Exception {
factory = new XmlBeanFactory(new FileSystemResource(new File(srcdir, "services.xml")));
// 创建“中文文件名.txt”
中文文件名 = new File(destdir, "中文文件名.txt");
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(中文文件名), "GBK"), true);
for (int i = 0; i < 16; i++) {
out.println("我爱北京天安门");
}
out.flush();
out.close();
}
@Before
public void init() throws Exception {
upload = (UploadService) factory.getBean("uploadService");
// Servlet container
ServletRunner servletRunner = new FilterServletRunner();
servletRunner.registerServlet("myservlet", MyServlet.class.getName());
// Servlet client
client = servletRunner.newClient();
// 取得初始页面form.html
WebResponse response = client.getResponse(new GetMethodWebRequest("http://localhost/myservlet"));
WebForm form = response.getFormWithName("myform");
// 取得提交form的request
WebRequest request = form.getRequest();
request.setParameter("myparam", "中华人民共和国");
request.selectFile("myfile", new File(srcdir, "smallfile.txt"));
File nonAsciiFile = 中文文件名;
if (nonAsciiFile.exists()) {
request.selectFile("myfile_中文", nonAsciiFile);
} else {
fail("Could not find non-ascii filename: " + nonAsciiFile.getAbsolutePath()
+ ". Please make sure the OS charset is correctly set.");
}
InvocationContext invocationContext = client.newInvocation(request);
this.request = invocationContext.getRequest();
// 因为页面的content type是text/html; charset=UTF-8,
// 所以应该以UTF-8方式解析request。
this.request.setCharacterEncoding("UTF-8");
}
@Test
public void isMultipartContent() throws Exception {
assertTrue(upload.isMultipartContent(request));
// 初始页面的请求是一个普通的“application/x-www-form-urlencoded”请求。
WebRequest request = new GetMethodWebRequest("http://localhost/myservlet");
InvocationContext invocationContext = client.newInvocation(request);
assertFalse(upload.isMultipartContent(invocationContext.getRequest()));
}
@Test
public void upload() throws Exception {
FileItem[] items = upload.parseRequest(request);
assertEquals(4, items.length);
// 参数的顺序是根据form.html中的field的顺序来的
// 第一个参数:<input type="text" name="myparam"/>
assertEquals("myparam", items[0].getFieldName());
assertNull(items[0].getName());
assertTrue(items[0].isFormField());
assertTrue(items[0].isInMemory());
assertEquals("中华人民共和国", items[0].getString()); // 自动以UTF-8解码
// 第二个参数:<input type="file" name="myfile"/>
assertEquals("myfile", items[1].getFieldName());
assertEquals(new File(srcdir, "smallfile.txt"), new File(items[1].getName()));
assertFalse(items[1].isFormField());
// 对于file类型,不会自动用UTF-8解码,默认使用8859_1
assertEquals(new String("中华人民共和国".getBytes("GBK"), "8859_1"), items[1].getString());
assertEquals("中华人民共和国", items[1].getString("GBK"));
// 这么小的文件,应该放在内存中
assertTrue(items[1].isInMemory());
// 第三个参数:<input type="file" name="myfile_中文"/>
assertEquals("myfile_中文", items[2].getFieldName()); // 自动以UTF-8解码header
assertEquals(中文文件名, new File(items[2].getName())); // 自动以UTF-8解码header
assertFalse(items[2].isFormField());
// 这个文件比较大,应该在文件中
assertTrue(items[2].getSize() > 100);
assertFalse(items[2].isInMemory());
// 第四个参数:<input type="submit" name="submit" value="upload"/>
assertEquals("submit", items[3].getFieldName());
assertNull(items[3].getName());
assertTrue(items[3].isFormField());
assertTrue(items[3].isInMemory());
assertEquals("upload", items[3].getString()); // 自动以UTF-8解码
}
@Test
public void uploadOverrideRepository() throws Exception {
File repositoryPath = new File(destdir, "hello");
UploadParameters params = new UploadParameters();
params.setRepository(repositoryPath);
params.setSizeThreshold(0); // 强制写入文件
FileItem[] items = upload.parseRequest(request, params);
assertEquals(4, items.length);
File storeLocation = ((DiskFileItem) items[1]).getStoreLocation();
assertEquals(repositoryPath, storeLocation.getParentFile());
}
@Test(expected = UploadSizeLimitExceededException.class)
public void uploadOverrideSizeMax() {
UploadParameters params = new UploadParameters();
params.setSizeMax(1);
upload.parseRequest(request, params);
}
@Test(expected = UploadSizeLimitExceededException.class)
public void uploadOverrideFileSizeMax() {
UploadParameters params = new UploadParameters();
params.setSizeMax(1000000);
params.setFileSizeMax(1);
upload.parseRequest(request, params);
}
@Test
public void uploadOverrideThreshold() throws Exception {
UploadParameters params = new UploadParameters();
params.setSizeThreshold(0);
FileItem[] items = upload.parseRequest(request, params);
assertEquals(4, items.length);
// 参数的顺序是根据form.html中的field的顺序来的
// 第一个参数:<input type="text" name="myparam"/>
assertEquals("myparam", items[0].getFieldName());
assertNull(items[0].getName());
assertTrue(items[0].isFormField());
assertTrue(items[0].isInMemory()); // 当threshold为0时,form field永远在内存中
assertEquals("中华人民共和国", items[0].getString()); // 自动以UTF-8解码
// 第二个参数:<input type="file" name="myfile"/>
assertEquals("myfile", items[1].getFieldName());
assertEquals(new File(srcdir, "smallfile.txt"), new File(items[1].getName()));
assertFalse(items[1].isFormField());
// 对于file类型,不会自动用UTF-8解码,默认使用8859_1
assertEquals(new String("中华人民共和国".getBytes("GBK"), "8859_1"), items[1].getString());
assertEquals("中华人民共和国", items[1].getString("GBK"));
// 因为threshold是0, 所以上传文件总是保存在文件系统中
assertFalse(items[1].isInMemory());
// 第三个参数:<input type="file" name="myfile_中文"/>
assertEquals("myfile_中文", items[2].getFieldName()); // 自动以UTF-8解码header
assertEquals(中文文件名, new File(items[2].getName())); // 自动以UTF-8解码header
assertFalse(items[2].isFormField());
// file类型一定在文件中
assertTrue(items[2].getSize() > 100);
assertFalse(items[2].isInMemory());
// 第四个参数:<input type="submit" name="submit" value="upload"/>
assertEquals("submit", items[3].getFieldName());
assertNull(items[3].getName());
assertTrue(items[3].isFormField());
assertTrue(items[3].isInMemory()); // form field永远在内存中
assertEquals("upload", items[3].getString()); // 自动以UTF-8解码
}
@Test
public void fullConfig() {
upload = (UploadService) factory.getBean("upload2");
assertEquals(new File("/tmp/upload").toURI().toString(), upload.getRepository().toURI().toString());
assertEquals("100", upload.getSizeMax().toString());
assertEquals("200", upload.getFileSizeMax().toString());
assertEquals("300", upload.getSizeThreshold().toString());
assertEquals(true, upload.isKeepFormFieldInMemory());
assertArrayEquals(new String[] { "filename", "fname" }, upload.getFileNameKey());
}
@Test
public void toString_() {
FileItem[] items = upload.parseRequest(request);
assertEquals(4, items.length);
// 参数的顺序是根据form.html中的field的顺序来的
// 第一个参数:<input type="text" name="myparam"/>
assertEquals("中华人民共和国", items[0].toString());
// 第二个参数:<input type="file" name="myfile"/>
assertEquals(new File(srcdir, "smallfile.txt").getAbsolutePath(), items[1].toString());
// 第三个参数:<input type="file" name="myfile_中文"/>
assertEquals(中文文件名.getAbsolutePath(), items[2].toString());
// 第四个参数:<input type="submit" name="submit" value="upload"/>
assertEquals("upload", items[3].toString());
}
/**
* 过滤httpunit生成的request content:
* <ul>
* <li>过滤掉Content-Type header,因为在正式浏览器中不会出现这个。</li>
* <li>将filename="...\\..."中的双斜杠换成单斜杠,因为正式浏览器也不会出现双斜杠。</li>
* </ul>
*/
private static final class FilterServletRunner extends UploadServletRunner {
@Override
protected byte[] filter(WebRequest request, byte[] messageBody) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
BufferedReader reader = new BufferedReader(new StringReader(new String(messageBody, "ISO-8859-1")));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(baos, "ISO-8859-1"), true);
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Content-Type: text/plain; charset=")) {
continue;
}
if (line.indexOf("filename=") > 0) {
line = line.replaceAll("\\\\+", "\\\\");
}
writer.printf("%s\r\n", line); // 注意:此处非platform-specific换行。
}
writer.flush();
} catch (IOException e) {
fail(e.getMessage());
}
return baos.toByteArray();
}
}
public static class MyServlet extends HttpServlet {
private static final long serialVersionUID = 3258413932522648633L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
String html = StreamUtil.readText(new FileInputStream(new File(srcdir, "form.html")), "GBK", true);
out.println(html);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
doGet(request, response);
}
}
}