View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.fileupload;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.ObjectInputStream;
30  import java.io.ObjectOutputStream;
31  import java.io.OutputStream;
32  
33  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
34  import org.apache.commons.io.FileUtils;
35  import org.junit.After;
36  import org.junit.Before;
37  import org.junit.Test;
38  
39  /**
40   * Serialization Unit tests for
41   *  {@link org.apache.commons.fileupload.disk.DiskFileItem}.
42   */
43  public class DiskFileItemSerializeTest {
44  
45      // Use a private repo to catch any files left over by tests
46      private static final File REPO = new File(System.getProperty("java.io.tmpdir"), "diskfileitemrepo");
47  
48      @Before
49      public void setUp() throws Exception {
50          if (REPO.exists()) {
51              FileUtils.deleteDirectory(REPO);
52          }
53          FileUtils.forceMkdir(REPO);
54      }
55  
56      @After
57      public void tearDown() throws IOException {
58          for(File file : FileUtils.listFiles(REPO, null, true)) {
59              System.out.println("Found leftover file " + file);
60          }
61          FileUtils.deleteDirectory(REPO);
62      }
63  
64      /**
65       * Content type for regular form items.
66       */
67      private static final String textContentType = "text/plain";
68  
69      /**
70       * Very low threshold for testing memory versus disk options.
71       */
72      private static final int threshold = 16;
73  
74      /**
75       * Helper method to test creation of a field when a repository is used.
76       */
77      public void testInMemoryObject(byte[] testFieldValueBytes, File repository) {
78          FileItem item = createFileItem(testFieldValueBytes, repository);
79  
80          // Check state is as expected
81          assertTrue("Initial: in memory", item.isInMemory());
82          assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length);
83          compareBytes("Initial", item.get(), testFieldValueBytes);
84          item.delete();
85      }
86  
87      /**
88       * Helper method to test creation of a field.
89       */
90      private void testInMemoryObject(byte[] testFieldValueBytes) {
91          testInMemoryObject(testFieldValueBytes, REPO);
92      }
93  
94      /**
95       * Test creation of a field for which the amount of data falls below the
96       * configured threshold.
97       */
98      @Test
99      public void testBelowThreshold() {
100         // Create the FileItem
101         byte[] testFieldValueBytes = createContentBytes(threshold - 1);
102         testInMemoryObject(testFieldValueBytes);
103     }
104 
105     /**
106      * Test creation of a field for which the amount of data equals the
107      * configured threshold.
108      */
109     @Test
110     public void testThreshold() {
111         // Create the FileItem
112         byte[] testFieldValueBytes = createContentBytes(threshold);
113         testInMemoryObject(testFieldValueBytes);
114     }
115 
116     /**
117      * Test creation of a field for which the amount of data falls above the
118      * configured threshold.
119      */
120     @Test
121     public void testAboveThreshold() {
122         // Create the FileItem
123         byte[] testFieldValueBytes = createContentBytes(threshold + 1);
124         FileItem item = createFileItem(testFieldValueBytes);
125 
126         // Check state is as expected
127         assertFalse("Initial: in memory", item.isInMemory());
128         assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length);
129         compareBytes("Initial", item.get(), testFieldValueBytes);
130 
131         item.delete();
132     }
133 
134     /**
135      * Test serialization and deserialization when repository is not null.
136      */
137     @Test
138     public void testValidRepository() {
139         // Create the FileItem
140         byte[] testFieldValueBytes = createContentBytes(threshold);
141         testInMemoryObject(testFieldValueBytes, REPO);
142     }
143 
144     /**
145      * Test deserialization fails when repository is not valid.
146      */
147     @Test(expected=IOException.class)
148     public void testInvalidRepository() throws Exception {
149         // Create the FileItem
150         byte[] testFieldValueBytes = createContentBytes(threshold);
151         File repository = new File(System.getProperty("java.io.tmpdir"), "file");
152         FileItem item = createFileItem(testFieldValueBytes, repository);
153         deserialize(serialize(item));
154     }
155 
156     /**
157      * Test deserialization fails when repository contains a null character.
158      */
159     @Test(expected=IOException.class)
160     public void testInvalidRepositoryWithNullChar() throws Exception {
161         // Create the FileItem
162         byte[] testFieldValueBytes = createContentBytes(threshold);
163         File repository = new File(System.getProperty("java.io.tmpdir"), "\0");
164         FileItem item = createFileItem(testFieldValueBytes, repository);
165         deserialize(serialize(item));
166     }
167 
168     /**
169      * Compare content bytes.
170      */
171     private void compareBytes(String text, byte[] origBytes, byte[] newBytes) {
172         assertNotNull("origBytes must not be null", origBytes);
173         assertNotNull("newBytes must not be null", newBytes);
174         assertEquals(text + " byte[] length", origBytes.length, newBytes.length);
175         for (int i = 0; i < origBytes.length; i++) {
176             assertEquals(text + " byte[" + i + "]", origBytes[i], newBytes[i]);
177         }
178     }
179 
180     /**
181      * Create content bytes of a specified size.
182      */
183     private byte[] createContentBytes(int size) {
184         StringBuilder buffer = new StringBuilder(size);
185         byte count = 0;
186         for (int i = 0; i < size; i++) {
187             buffer.append(count+"");
188             count++;
189             if (count > 9) {
190                 count = 0;
191             }
192         }
193         return buffer.toString().getBytes();
194     }
195 
196     /**
197      * Create a FileItem with the specfied content bytes and repository.
198      */
199     private FileItem createFileItem(byte[] contentBytes, File repository) {
200         FileItemFactory factory = new DiskFileItemFactory(threshold, repository);
201         String textFieldName = "textField";
202 
203         FileItem item = factory.createItem(
204                 textFieldName,
205                 textContentType,
206                 true,
207                 "My File Name"
208         );
209         try {
210             OutputStream os = item.getOutputStream();
211             os.write(contentBytes);
212             os.close();
213         } catch(IOException e) {
214             fail("Unexpected IOException" + e);
215         }
216 
217         return item;
218 
219     }
220 
221     /**
222      * Create a FileItem with the specfied content bytes.
223      */
224     private FileItem createFileItem(byte[] contentBytes) {
225         return createFileItem(contentBytes, REPO);
226     }
227 
228     /**
229      * Do serialization
230      */
231     private ByteArrayOutputStream serialize(Object target) throws Exception {
232         ByteArrayOutputStream baos = new ByteArrayOutputStream();
233         ObjectOutputStream oos = new ObjectOutputStream(baos);
234         oos.writeObject(target);
235         oos.flush();
236         oos.close();
237         return baos;
238     }
239 
240     /**
241      * Do deserialization
242      */
243     private Object deserialize(ByteArrayOutputStream baos) throws Exception {
244         Object result = null;
245         ByteArrayInputStream bais =
246                 new ByteArrayInputStream(baos.toByteArray());
247         ObjectInputStream ois = new ObjectInputStream(bais);
248         result = ois.readObject();
249         bais.close();
250 
251         return result;
252     }
253 }