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.fileupload2.core;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertTrue;
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.nio.charset.StandardCharsets;
25  
26  import org.junit.jupiter.api.Test;
27  
28  /**
29   * Tests the {@link ProgressListener}.
30   *
31   * @param <AFU> The subclass of FileUpload.
32   * @param <R>   The FileUpload request type.
33   * @param <I>   The FileItem type.
34   * @param <F>   The FileItemFactory type.
35   */
36  public abstract class AbstractProgressListenerTest<AFU extends AbstractFileUpload<R, I, F>, R, I extends FileItem<I>, F extends FileItemFactory<I>>
37          extends AbstractTest<AFU, R, I, F> {
38  
39      protected static class ProgressListenerImpl implements ProgressListener {
40  
41          private final long expectedContentLength;
42  
43          private final int expectedItems;
44  
45          private Long bytesRead;
46  
47          private Integer items;
48  
49          ProgressListenerImpl(final long contentLength, final int itemCount) {
50              expectedContentLength = contentLength;
51              expectedItems = itemCount;
52          }
53  
54          void checkFinished() {
55              assertEquals(expectedContentLength, bytesRead.longValue());
56              assertEquals(expectedItems, items.intValue());
57          }
58  
59          @Override
60          public void update(final long actualBytesRead, final long actualContentLength, final int actualItems) {
61              assertTrue(actualBytesRead >= 0 && actualBytesRead <= expectedContentLength);
62              assertTrue(actualContentLength == -1 || actualContentLength == expectedContentLength);
63              assertTrue(actualItems >= 0 && actualItems <= expectedItems);
64  
65              assertTrue(bytesRead == null || actualBytesRead >= bytesRead.longValue());
66              bytesRead = Long.valueOf(actualBytesRead);
67              assertTrue(items == null || actualItems >= items.intValue());
68              items = Integer.valueOf(actualItems);
69          }
70  
71      }
72  
73      protected void runTest(final int itemCount, final long contentLength, final R request) throws FileUploadException, IOException {
74          final var upload = newFileUpload();
75          final var listener = new ProgressListenerImpl(contentLength, itemCount);
76          upload.setProgressListener(listener);
77          final var iter = upload.getItemIterator(request);
78          for (var i = 0; i < itemCount; i++) {
79              final var idxI = i;
80              final var fileItemInput = iter.next();
81              try (final var inputStream = fileItemInput.getInputStream()) {
82                  for (var j = 0; j < 16_384 + i; j++) {
83                      final var idxJ = j;
84                      //
85                      // This used to be assertEquals((byte) j, (byte) istream.read()); but this seems to trigger a bug in JRockit, so we express the same like
86                      // this:
87                      //
88                      final var b1 = (byte) j;
89                      final var b2 = (byte) inputStream.read();
90                      assertEquals(b1, b2, () -> String.format("itemCount = %,d, i = %,d, j = %,d", itemCount, idxI, idxJ));
91                  }
92                  assertEquals(-1, inputStream.read());
93              }
94          }
95          assertTrue(!iter.hasNext());
96          listener.checkFinished();
97      }
98  
99      /**
100      * Parse a very long file upload by using a progress listener.
101      *
102      * @throws IOException Test failure.
103      */
104     @Test
105     public void testProgressListener() throws IOException {
106         final var numItems = 512;
107         final var baos = new ByteArrayOutputStream();
108         for (var i = 0; i < numItems; i++) {
109             final var header = "-----1234\r\n" + "Content-Disposition: form-data; name=\"field" + (i + 1) + "\"\r\n" + "\r\n";
110             baos.write(header.getBytes(StandardCharsets.US_ASCII));
111             for (var j = 0; j < 16384 + i; j++) {
112                 baos.write((byte) j);
113             }
114             baos.write("\r\n".getBytes(StandardCharsets.US_ASCII));
115         }
116         baos.write("-----1234--\r\n".getBytes(StandardCharsets.US_ASCII));
117         final var requestBytes = baos.toByteArray();
118 
119         var request = newMockHttpServletRequest(requestBytes, null, Constants.CONTENT_TYPE, null);
120         runTest(numItems, requestBytes.length, request);
121         request = newMockHttpServletRequest(requestBytes, -1L, Constants.CONTENT_TYPE, null);
122         runTest(numItems, requestBytes.length, request);
123     }
124 
125 }