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          assertFalse("Must not exist", REPO.exists());
54          REPO.mkdir();
55      }
56  
57      @After
58      public void tearDown() {
59          for(File file : FileUtils.listFiles(REPO, null, true)) {
60              System.out.println("Found leftover file " + file);
61          }
62          REPO.delete();
63          assertFalse(REPO + " is not empty", REPO.exists());
64      }
65  
66      /**
67       * Content type for regular form items.
68       */
69      private static final String textContentType = "text/plain";
70  
71      /**
72       * Very low threshold for testing memory versus disk options.
73       */
74      private static final int threshold = 16;
75  
76      /**
77       * Helper method to test creation of a field when a repository is used.
78       */
79      public void testInMemoryObject(byte[] testFieldValueBytes, File repository) {
80          FileItem item = createFileItem(testFieldValueBytes, repository);
81  
82          // Check state is as expected
83          assertTrue("Initial: in memory", item.isInMemory());
84          assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length);
85          compareBytes("Initial", item.get(), testFieldValueBytes);
86          item.delete();
87      }
88  
89      /**
90       * Helper method to test creation of a field.
91       */
92      private void testInMemoryObject(byte[] testFieldValueBytes) {
93          testInMemoryObject(testFieldValueBytes, REPO);
94      }
95  
96      /**
97       * Test creation of a field for which the amount of data falls below the
98       * configured threshold.
99       */
100     @Test
101     public void testBelowThreshold() throws Exception {
102         // Create the FileItem
103         byte[] testFieldValueBytes = createContentBytes(threshold - 1);
104         testInMemoryObject(testFieldValueBytes);
105     }
106 
107     /**
108      * Test creation of a field for which the amount of data equals the
109      * configured threshold.
110      */
111     @Test
112     public void testThreshold() throws Exception {
113         // Create the FileItem
114         byte[] testFieldValueBytes = createContentBytes(threshold);
115         testInMemoryObject(testFieldValueBytes);
116     }
117 
118     /**
119      * Test creation of a field for which the amount of data falls above the
120      * configured threshold.
121      */
122     @Test
123     public void testAboveThreshold() throws Exception {
124         // Create the FileItem
125         byte[] testFieldValueBytes = createContentBytes(threshold + 1);
126         FileItem item = createFileItem(testFieldValueBytes);
127 
128         // Check state is as expected
129         assertFalse("Initial: in memory", item.isInMemory());
130         assertEquals("Initial: size", item.getSize(), testFieldValueBytes.length);
131         compareBytes("Initial", item.get(), testFieldValueBytes);
132 
133         item.delete();
134     }
135 
136     /**
137      * Test serialization and deserialization when repository is not null.
138      */
139     @Test
140     public void testValidRepository() throws Exception {
141         // Create the FileItem
142         byte[] testFieldValueBytes = createContentBytes(threshold);
143         testInMemoryObject(testFieldValueBytes, REPO);
144     }
145 
146     /**
147      * Test deserialization fails when repository is not valid.
148      */
149     @Test(expected=IOException.class)
150     public void testInvalidRepository() throws Exception {
151         // Create the FileItem
152         byte[] testFieldValueBytes = createContentBytes(threshold);
153         File repository = new File(System.getProperty("java.io.tmpdir"), "file");
154         FileItem item = createFileItem(testFieldValueBytes, repository);
155         deserialize(serialize(item));
156     }
157 
158     /**
159      * Test deserialization fails when repository contains a null character.
160      */
161     @Test(expected=IOException.class)
162     public void testInvalidRepositoryWithNullChar() throws Exception {
163         // Create the FileItem
164         byte[] testFieldValueBytes = createContentBytes(threshold);
165         File repository = new File(System.getProperty("java.io.tmpdir"), "\0");
166         FileItem item = createFileItem(testFieldValueBytes, repository);
167         deserialize(serialize(item));
168     }
169 
170     /**
171      * Compare content bytes.
172      */
173     private void compareBytes(String text, byte[] origBytes, byte[] newBytes) {
174         assertNotNull("origBytes must not be null", origBytes);
175         assertNotNull("newBytes must not be null", newBytes);
176         assertEquals(text + " byte[] length", origBytes.length, newBytes.length);
177         for (int i = 0; i < origBytes.length; i++) {
178             assertEquals(text + " byte[" + i + "]", origBytes[i], newBytes[i]);
179         }
180     }
181 
182     /**
183      * Create content bytes of a specified size.
184      */
185     private byte[] createContentBytes(int size) {
186         StringBuilder buffer = new StringBuilder(size);
187         byte count = 0;
188         for (int i = 0; i < size; i++) {
189             buffer.append(count+"");
190             count++;
191             if (count > 9) {
192                 count = 0;
193             }
194         }
195         return buffer.toString().getBytes();
196     }
197 
198     /**
199      * Create a FileItem with the specfied content bytes and repository.
200      */
201     private FileItem createFileItem(byte[] contentBytes, File repository) {
202         FileItemFactory factory = new DiskFileItemFactory(threshold, repository);
203         String textFieldName = "textField";
204 
205         FileItem item = factory.createItem(
206                 textFieldName,
207                 textContentType,
208                 true,
209                 "My File Name"
210         );
211         try {
212             OutputStream os = item.getOutputStream();
213             os.write(contentBytes);
214             os.close();
215         } catch(IOException e) {
216             fail("Unexpected IOException" + e);
217         }
218 
219         return item;
220 
221     }
222 
223     /**
224      * Create a FileItem with the specfied content bytes.
225      */
226     private FileItem createFileItem(byte[] contentBytes) {
227         return createFileItem(contentBytes, REPO);
228     }
229 
230     /**
231      * Do serialization
232      */
233     private ByteArrayOutputStream serialize(Object target) throws Exception {
234         ByteArrayOutputStream baos = new ByteArrayOutputStream();
235         ObjectOutputStream oos = new ObjectOutputStream(baos);
236         oos.writeObject(target);
237         oos.flush();
238         oos.close();
239         return baos;
240     }
241 
242     /**
243      * Do deserialization
244      */
245     private Object deserialize(ByteArrayOutputStream baos) throws Exception {
246         Object result = null;
247         ByteArrayInputStream bais =
248                 new ByteArrayInputStream(baos.toByteArray());
249         ObjectInputStream ois = new ObjectInputStream(bais);
250         result = ois.readObject();
251         bais.close();
252 
253         return result;
254     }
255 }