View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http.impl.nio.codecs;
29  
30  import java.io.File;
31  import java.io.IOException;
32  import java.io.RandomAccessFile;
33  import java.nio.ByteBuffer;
34  import java.nio.channels.FileChannel;
35  import java.nio.channels.ReadableByteChannel;
36  
37  import org.apache.http.Consts;
38  import org.apache.http.ReadableByteChannelMock;
39  import org.apache.http.impl.io.HttpTransportMetricsImpl;
40  import org.apache.http.impl.nio.reactor.SessionInputBufferImpl;
41  import org.apache.http.nio.reactor.SessionInputBuffer;
42  import org.apache.http.util.EncodingUtils;
43  import org.junit.After;
44  import org.junit.Assert;
45  import org.junit.Test;
46  
47  /**
48   * Simple tests for {@link LengthDelimitedDecoder}.
49   */
50  public class TestIdentityDecoder {
51  
52      private File tmpfile;
53  
54      protected File createTempFile() throws IOException {
55          this.tmpfile = File.createTempFile("testFile", ".txt");
56          return this.tmpfile;
57      }
58  
59      @After
60      public void deleteTempFile() {
61          if (this.tmpfile != null && this.tmpfile.exists()) {
62              this.tmpfile.delete();
63          }
64      }
65  
66      @Test
67      public void testBasicDecoding() throws Exception {
68          final ReadableByteChannel channel = new ReadableByteChannelMock(
69                  new String[] {"stuff;", "more stuff"}, Consts.ASCII);
70  
71          final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
72          final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
73          final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
74  
75          final ByteBuffer dst = ByteBuffer.allocate(1024);
76  
77          int bytesRead = decoder.read(dst);
78          Assert.assertEquals(6, bytesRead);
79          Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
80          Assert.assertFalse(decoder.isCompleted());
81          Assert.assertEquals(6, metrics.getBytesTransferred());
82  
83          dst.clear();
84          bytesRead = decoder.read(dst);
85          Assert.assertEquals(10, bytesRead);
86          Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
87          Assert.assertFalse(decoder.isCompleted());
88          Assert.assertEquals(16, metrics.getBytesTransferred());
89  
90          dst.clear();
91          bytesRead = decoder.read(dst);
92          Assert.assertEquals(-1, bytesRead);
93          Assert.assertTrue(decoder.isCompleted());
94          Assert.assertEquals(16, metrics.getBytesTransferred());
95  
96          dst.clear();
97          bytesRead = decoder.read(dst);
98          Assert.assertEquals(-1, bytesRead);
99          Assert.assertTrue(decoder.isCompleted());
100         Assert.assertEquals(16, metrics.getBytesTransferred());
101 
102         Assert.assertEquals("[identity; completed: true]", decoder.toString());
103     }
104 
105     @Test
106     public void testDecodingFromSessionBuffer() throws Exception {
107         final ReadableByteChannel channel = new ReadableByteChannelMock(
108                 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
109 
110         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
111         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
112 
113         inbuf.fill(channel);
114 
115         Assert.assertEquals(6, inbuf.length());
116 
117         final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
118 
119         final ByteBuffer dst = ByteBuffer.allocate(1024);
120 
121         int bytesRead = decoder.read(dst);
122         Assert.assertEquals(6, bytesRead);
123         Assert.assertEquals("stuff;", CodecTestUtils.convert(dst));
124         Assert.assertFalse(decoder.isCompleted());
125         Assert.assertEquals(0, metrics.getBytesTransferred()); // doesn't count if from session buffer
126 
127         dst.clear();
128         bytesRead = decoder.read(dst);
129         Assert.assertEquals(10, bytesRead);
130         Assert.assertEquals("more stuff", CodecTestUtils.convert(dst));
131         Assert.assertFalse(decoder.isCompleted());
132         Assert.assertEquals(10, metrics.getBytesTransferred());
133 
134         dst.clear();
135         bytesRead = decoder.read(dst);
136         Assert.assertEquals(-1, bytesRead);
137         Assert.assertTrue(decoder.isCompleted());
138         Assert.assertEquals(10, metrics.getBytesTransferred());
139 
140         dst.clear();
141         bytesRead = decoder.read(dst);
142         Assert.assertEquals(-1, bytesRead);
143         Assert.assertTrue(decoder.isCompleted());
144         Assert.assertEquals(10, metrics.getBytesTransferred());
145 
146     }
147 
148     @Test
149     public void testBasicDecodingFile() throws Exception {
150         final ReadableByteChannel channel = new ReadableByteChannelMock(
151                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, Consts.ASCII);
152 
153         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
154         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
155         final IdentityDecoder decoder = new IdentityDecoder(
156                 channel, inbuf, metrics);
157 
158         createTempFile();
159         final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
160         try {
161             final FileChannel fchannel = testfile.getChannel();
162             long pos = 0;
163             while (!decoder.isCompleted()) {
164                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
165                 if (bytesRead > 0) {
166                     pos += bytesRead;
167                 }
168             }
169 
170             Assert.assertEquals(testfile.length(), metrics.getBytesTransferred());
171         } finally {
172             testfile.close();
173         }
174         Assert.assertEquals("stuff; more stuff; a lot more stuff!",
175             CodecTestUtils.readFromFile(this.tmpfile));
176     }
177 
178     @Test
179     public void testDecodingFileWithBufferedSessionData() throws Exception {
180         final ReadableByteChannel channel = new ReadableByteChannelMock(
181                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, Consts.ASCII);
182 
183         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
184         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
185         final IdentityDecoder decoder = new IdentityDecoder(
186                 channel, inbuf, metrics);
187 
188         final int i = inbuf.fill(channel);
189         Assert.assertEquals(7, i);
190 
191         createTempFile();
192         final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
193         try {
194             final FileChannel fchannel = testfile.getChannel();
195             long pos = 0;
196             while (!decoder.isCompleted()) {
197                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
198                 if (bytesRead > 0) {
199                     pos += bytesRead;
200                 }
201             }
202 
203             // count everything except the initial 7 bytes that went to the session buffer
204             Assert.assertEquals(testfile.length() - 7, metrics.getBytesTransferred());
205         } finally {
206             testfile.close();
207         }
208         Assert.assertEquals("stuff; more stuff; a lot more stuff!",
209             CodecTestUtils.readFromFile(this.tmpfile));
210     }
211 
212     @Test
213     public void testDecodingFileWithOffsetAndBufferedSessionData() throws Exception {
214         final ReadableByteChannel channel = new ReadableByteChannelMock(
215                 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, Consts.ASCII);
216 
217         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
218         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
219         final IdentityDecoder decoder = new IdentityDecoder(
220                 channel, inbuf, metrics);
221 
222         final int i = inbuf.fill(channel);
223         Assert.assertEquals(7, i);
224 
225         final byte[] beginning = EncodingUtils.getAsciiBytes("beginning; ");
226 
227         createTempFile();
228         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
229         try {
230             testfile.write(beginning);
231         } finally {
232             testfile.close();
233         }
234 
235         testfile = new RandomAccessFile(this.tmpfile, "rw");
236         try {
237             final FileChannel fchannel = testfile.getChannel();
238             long pos = beginning.length;
239             while (!decoder.isCompleted()) {
240                 if(testfile.length() < pos) {
241                     testfile.setLength(pos);
242                 }
243                 final long bytesRead = decoder.transfer(fchannel, pos, 10);
244                 if (bytesRead > 0) {
245                     pos += bytesRead;
246                 }
247             }
248 
249             // count everything except the initial 7 bytes that went to the session buffer
250             Assert.assertEquals(testfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
251         } finally {
252             testfile.close();
253         }
254 
255         Assert.assertEquals("beginning; stuff; more stuff; a lot more stuff!",
256             CodecTestUtils.readFromFile(this.tmpfile));
257     }
258 
259     @Test
260     public void testDecodingFileWithLimit() throws Exception {
261         final ReadableByteChannel channel = new ReadableByteChannelMock(
262                 new String[] {"stuff; more stuff; ", "a lot more stuff!"}, Consts.ASCII);
263 
264         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
265         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
266         final IdentityDecoder decoder = new IdentityDecoder(
267                 channel, inbuf, metrics);
268 
269         final int i = inbuf.fill(channel);
270         Assert.assertEquals(19, i);
271 
272         createTempFile();
273         final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
274         try {
275             final FileChannel fchannel = testfile.getChannel();
276             long pos = 0;
277 
278             // transferred from buffer
279             long bytesRead = decoder.transfer(fchannel, pos, 1);
280             Assert.assertEquals(1, bytesRead);
281             Assert.assertFalse(decoder.isCompleted());
282             Assert.assertEquals(0, metrics.getBytesTransferred());
283             pos += bytesRead;
284 
285             bytesRead = decoder.transfer(fchannel, pos, 2);
286             Assert.assertEquals(2, bytesRead);
287             Assert.assertFalse(decoder.isCompleted());
288             Assert.assertEquals(0, metrics.getBytesTransferred());
289             pos += bytesRead;
290 
291             bytesRead = decoder.transfer(fchannel, pos, 17);
292             Assert.assertEquals(16, bytesRead);
293             Assert.assertFalse(decoder.isCompleted());
294             Assert.assertEquals(0, metrics.getBytesTransferred());
295             pos += bytesRead;
296 
297             // transferred from channel
298             bytesRead = decoder.transfer(fchannel, pos, 1);
299             Assert.assertEquals(1, bytesRead);
300             Assert.assertFalse(decoder.isCompleted());
301             Assert.assertEquals(1, metrics.getBytesTransferred());
302             pos += bytesRead;
303 
304             bytesRead = decoder.transfer(fchannel, pos, 2);
305             Assert.assertEquals(2, bytesRead);
306             Assert.assertFalse(decoder.isCompleted());
307             Assert.assertEquals(3, metrics.getBytesTransferred());
308             pos += bytesRead;
309 
310             bytesRead = decoder.transfer(fchannel, pos, 15);
311             Assert.assertEquals(14, bytesRead);
312             Assert.assertFalse(decoder.isCompleted());
313             Assert.assertEquals(17, metrics.getBytesTransferred());
314             pos += bytesRead;
315 
316             bytesRead = decoder.transfer(fchannel, pos, 1);
317             Assert.assertEquals(-1, bytesRead);
318             Assert.assertTrue(decoder.isCompleted());
319             Assert.assertEquals(17, metrics.getBytesTransferred());
320         } finally {
321             testfile.close();
322         }
323         Assert.assertEquals("stuff; more stuff; a lot more stuff!",
324                 CodecTestUtils.readFromFile(this.tmpfile));
325     }
326 
327     @Test
328     public void testWriteBeyondFileSize() throws Exception {
329         final ReadableByteChannel channel = new ReadableByteChannelMock(
330                 new String[] {"a"}, Consts.ASCII);
331 
332         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
333         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
334         final IdentityDecoder decoder = new IdentityDecoder(
335                 channel, inbuf, metrics);
336 
337         createTempFile();
338         final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
339         try {
340             Assert.assertEquals(0, testfile.length());
341             final FileChannel fchannel = testfile.getChannel();
342             try {
343                 decoder.transfer(fchannel, 5, 10);
344                 Assert.fail("expected IOException");
345             } catch(final IOException iox) {}
346         } finally {
347             testfile.close();
348         }
349     }
350 
351     @Test
352     public void testInvalidConstructor() {
353         final ReadableByteChannel channel = new ReadableByteChannelMock(
354                 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
355 
356         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
357         try {
358             new IdentityDecoder(null, null, null);
359             Assert.fail("IllegalArgumentException should have been thrown");
360         } catch (final IllegalArgumentException ex) {
361             // ignore
362         }
363         try {
364             new IdentityDecoder(channel, null, null);
365             Assert.fail("IllegalArgumentException should have been thrown");
366         } catch (final IllegalArgumentException ex) {
367             // ignore
368         }
369         try {
370             new IdentityDecoder(channel, inbuf, null);
371             Assert.fail("IllegalArgumentException should have been thrown");
372         } catch (final IllegalArgumentException ex) {
373             // ignore
374         }
375     }
376 
377     @Test
378     public void testInvalidInput() throws Exception {
379         final String s = "stuff";
380         final ReadableByteChannel channel = new ReadableByteChannelMock(
381                 new String[] {s}, Consts.ASCII);
382 
383         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
384         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
385         final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
386 
387         try {
388             decoder.read(null);
389             Assert.fail("IllegalArgumentException should have been thrown");
390         } catch (final IllegalArgumentException ex) {
391             // expected
392         }
393     }
394 
395 }