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.vfs2.provider;
18  
19  import java.io.Closeable;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.nio.charset.StandardCharsets;
25  import java.util.concurrent.atomic.AtomicBoolean;
26  
27  import org.apache.commons.lang3.ArrayUtils;
28  import org.apache.commons.lang3.StringUtils;
29  import org.apache.commons.lang3.function.FailableFunction;
30  import org.apache.commons.vfs2.FileContent;
31  import org.apache.commons.vfs2.FileObject;
32  import org.apache.commons.vfs2.FileSystemManager;
33  import org.apache.commons.vfs2.VFS;
34  import org.junit.Assert;
35  import org.junit.Test;
36  
37  /**
38   * {@code DefaultFileContentTest} tests for bug-VFS-614. This bug involves the stream implementation closing the stream
39   * after reading to the end of the buffer, which broke marking.
40   */
41  public class DefaultFileContentTest {
42      private static final String expected = "testing";
43  
44      /**
45       * Test VFS-724 should be done on a website which render a page with no content size. Note the getSize() is
46       * currently the value sent back by the server then zero usually means no content length attached.
47       */
48      @Test
49      public void testGetZeroContents() throws IOException {
50          final FileSystemManager fsManager = VFS.getManager();
51          try (final FileObject fo = fsManager.resolveFile(new File("."), "src/test/resources/test-data/size-0-file.bin");
52                  final FileContent content = fo.getContent()) {
53              Assert.assertEquals(0, content.getSize());
54              Assert.assertTrue(content.isEmpty());
55              Assert.assertEquals(StringUtils.EMPTY, content.getString(StandardCharsets.UTF_8));
56              Assert.assertEquals(StringUtils.EMPTY, content.getString(StandardCharsets.UTF_8.name()));
57              Assert.assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY, content.getByteArray());
58          }
59      }
60  
61      private void testInputStreamBufferSize(final int bufferSize) throws Exception {
62          final File temp = File.createTempFile("temp-file-name", ".tmp");
63          final FileSystemManager fileSystemManager = VFS.getManager();
64  
65          try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
66              file.getContent().getInputStream(bufferSize);
67          }
68      }
69  
70      @Test
71      public void testInputStreamBufferSize0() throws Exception {
72          testInputStreamBufferSize(0);
73      }
74  
75      @Test
76      public void testInputStreamBufferSize1() throws Exception {
77          testInputStreamBufferSize(1);
78      }
79  
80      @Test(expected = IllegalArgumentException.class)
81      public void testInputStreamBufferSizeNegative() throws Exception {
82          testInputStreamBufferSize(-2);
83      }
84  
85      @Test
86      public void testInputStreamClosedInADifferentThread() throws Exception {
87          testStreamClosedInADifferentThread(FileContent::getInputStream);
88      }
89  
90      @Test
91      public void testMarkingWhenReadingEOS() throws Exception {
92          final File temp = File.createTempFile("temp-file-name", ".tmp");
93          final FileSystemManager fileSystemManager = VFS.getManager();
94  
95          try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
96              try (OutputStream outputStream = file.getContent().getOutputStream()) {
97                  outputStream.write(expected.getBytes());
98                  outputStream.flush();
99              }
100             try (InputStream stream = file.getContent().getInputStream()) {
101                 int readCount = 0;
102                 if (stream.markSupported()) {
103                     for (int i = 0; i < 10; i++) {
104                         stream.mark(0);
105                         final byte[] data = new byte[100];
106                         readCount = stream.read(data, 0, 7);
107                         stream.read();
108                         Assert.assertEquals(7, readCount);
109                         Assert.assertEquals(expected, new String(data).trim());
110                         readCount = stream.read(data, 8, 10);
111                         Assert.assertEquals(-1, readCount);
112                         stream.reset();
113                     }
114                 }
115             }
116         }
117     }
118 
119     @Test
120     public void testMarkingWorks() throws Exception {
121         final File temp = File.createTempFile("temp-file-name", ".tmp");
122         final FileSystemManager fileSystemManager = VFS.getManager();
123 
124         try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
125             try (OutputStream outputStream = file.getContent().getOutputStream()) {
126                 outputStream.write(expected.getBytes());
127                 outputStream.flush();
128             }
129             try (InputStream stream = file.getContent().getInputStream()) {
130                 if (stream.markSupported()) {
131                     for (int i = 0; i < 10; i++) {
132                         stream.mark(0);
133                         final byte[] data = new byte[100];
134                         stream.read(data, 0, 7);
135                         stream.read();
136                         Assert.assertEquals(expected, new String(data).trim());
137                         stream.reset();
138                     }
139                 }
140             }
141         }
142     }
143 
144     private void testOutputStreamBufferSize(final int bufferSize) throws Exception {
145         final File temp = File.createTempFile("temp-file-name", ".tmp");
146         final FileSystemManager fileSystemManager = VFS.getManager();
147 
148         try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
149             file.getContent().getOutputStream(bufferSize).close();
150         }
151     }
152 
153     @Test
154     public void testOutputStreamBufferSize0() throws Exception {
155         testOutputStreamBufferSize(0);
156     }
157 
158     @Test
159     public void testOutputStreamBufferSize1() throws Exception {
160         testOutputStreamBufferSize(1);
161     }
162 
163     @Test(expected = IllegalArgumentException.class)
164     public void testOutputStreamBufferSizeNegative() throws Exception {
165         testOutputStreamBufferSize(-1);
166     }
167 
168     @Test(expected = IllegalArgumentException.class)
169     public void testOutputStreamBufferSizeNegativeWithAppendFlag() throws Exception {
170         final File temp = File.createTempFile("temp-file-name", ".tmp");
171         final FileSystemManager fileSystemManager = VFS.getManager();
172 
173         try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
174             file.getContent().getOutputStream(true, -1);
175         }
176     }
177 
178     @Test
179     public void testOutputStreamClosedInADifferentThread() throws Exception {
180         testStreamClosedInADifferentThread(FileContent::getOutputStream);
181     }
182 
183     private <T extends Closeable> void testStreamClosedInADifferentThread(final FailableFunction<FileContent, T, IOException> getStream) throws Exception {
184         final File temp = File.createTempFile("temp-file-name", ".tmp");
185         final FileSystemManager fileSystemManager = VFS.getManager();
186 
187         try (FileObject file = fileSystemManager.resolveFile(temp.getAbsolutePath())) {
188             final T stream = getStream.apply(file.getContent());
189             final AtomicBoolean check = new AtomicBoolean();
190             final Thread thread = new Thread(() -> {
191                 try {
192                     stream.close();
193                 } catch (final IOException exception) {
194                     // ignore
195                 }
196                 check.set(true);
197             });
198             thread.start();
199             thread.join();
200             Assert.assertTrue(check.get());
201         }
202     }
203 }