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 testWriteBeyondFileSize() throws Exception {
261         final ReadableByteChannel channel = new ReadableByteChannelMock(
262                 new String[] {"a"}, 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         createTempFile();
270         final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
271         try {
272             Assert.assertEquals(0, testfile.length());
273             final FileChannel fchannel = testfile.getChannel();
274             try {
275                 decoder.transfer(fchannel, 5, 10);
276                 Assert.fail("expected IOException");
277             } catch(final IOException iox) {}
278         } finally {
279             testfile.close();
280         }
281     }
282 
283     @Test
284     public void testInvalidConstructor() {
285         final ReadableByteChannel channel = new ReadableByteChannelMock(
286                 new String[] {"stuff;", "more stuff"}, Consts.ASCII);
287 
288         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
289         try {
290             new IdentityDecoder(null, null, null);
291             Assert.fail("IllegalArgumentException should have been thrown");
292         } catch (final IllegalArgumentException ex) {
293             // ignore
294         }
295         try {
296             new IdentityDecoder(channel, null, null);
297             Assert.fail("IllegalArgumentException should have been thrown");
298         } catch (final IllegalArgumentException ex) {
299             // ignore
300         }
301         try {
302             new IdentityDecoder(channel, inbuf, null);
303             Assert.fail("IllegalArgumentException should have been thrown");
304         } catch (final IllegalArgumentException ex) {
305             // ignore
306         }
307     }
308 
309     @Test
310     public void testInvalidInput() throws Exception {
311         final String s = "stuff";
312         final ReadableByteChannel channel = new ReadableByteChannelMock(
313                 new String[] {s}, Consts.ASCII);
314 
315         final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, Consts.ASCII);
316         final HttpTransportMetricsImpl metrics = new HttpTransportMetricsImpl();
317         final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
318 
319         try {
320             decoder.read(null);
321             Assert.fail("IllegalArgumentException should have been thrown");
322         } catch (final IllegalArgumentException ex) {
323             // expected
324         }
325     }
326 
327 }