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