1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.http.impl.nio;
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 import java.nio.charset.StandardCharsets;
37
38 import org.apache.hc.core5.http.ReadableByteChannelMock;
39 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
40 import org.apache.hc.core5.http.nio.SessionInputBuffer;
41 import org.junit.jupiter.api.AfterEach;
42 import org.junit.jupiter.api.Assertions;
43 import org.junit.jupiter.api.Test;
44
45
46
47
48 public class TestIdentityDecoder {
49
50 private File tmpfile;
51
52 protected File createTempFile() throws IOException {
53 this.tmpfile = File.createTempFile("testFile", ".txt");
54 return this.tmpfile;
55 }
56
57 @AfterEach
58 public void deleteTempFile() {
59 if (this.tmpfile != null && this.tmpfile.exists()) {
60 this.tmpfile.delete();
61 }
62 }
63
64 @Test
65 public void testBasicDecoding() throws Exception {
66 final ReadableByteChannel channel = new ReadableByteChannelMock(
67 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
68
69 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
70 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
71 final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
72
73 final ByteBuffer dst = ByteBuffer.allocate(1024);
74
75 int bytesRead = decoder.read(dst);
76 Assertions.assertEquals(6, bytesRead);
77 Assertions.assertEquals("stuff;", CodecTestUtils.convert(dst));
78 Assertions.assertFalse(decoder.isCompleted());
79 Assertions.assertEquals(6, metrics.getBytesTransferred());
80
81 dst.clear();
82 bytesRead = decoder.read(dst);
83 Assertions.assertEquals(10, bytesRead);
84 Assertions.assertEquals("more stuff", CodecTestUtils.convert(dst));
85 Assertions.assertFalse(decoder.isCompleted());
86 Assertions.assertEquals(16, metrics.getBytesTransferred());
87
88 dst.clear();
89 bytesRead = decoder.read(dst);
90 Assertions.assertEquals(-1, bytesRead);
91 Assertions.assertTrue(decoder.isCompleted());
92 Assertions.assertEquals(16, metrics.getBytesTransferred());
93
94 dst.clear();
95 bytesRead = decoder.read(dst);
96 Assertions.assertEquals(-1, bytesRead);
97 Assertions.assertTrue(decoder.isCompleted());
98 Assertions.assertEquals(16, metrics.getBytesTransferred());
99
100 Assertions.assertEquals("[identity; completed: true]", decoder.toString());
101 }
102
103 @Test
104 public void testDecodingFromSessionBuffer() throws Exception {
105 final ReadableByteChannel channel = new ReadableByteChannelMock(
106 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
107
108 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
109 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
110
111 inbuf.fill(channel);
112
113 Assertions.assertEquals(6, inbuf.length());
114
115 final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
116
117 final ByteBuffer dst = ByteBuffer.allocate(1024);
118
119 int bytesRead = decoder.read(dst);
120 Assertions.assertEquals(6, bytesRead);
121 Assertions.assertEquals("stuff;", CodecTestUtils.convert(dst));
122 Assertions.assertFalse(decoder.isCompleted());
123 Assertions.assertEquals(0, metrics.getBytesTransferred());
124
125 dst.clear();
126 bytesRead = decoder.read(dst);
127 Assertions.assertEquals(10, bytesRead);
128 Assertions.assertEquals("more stuff", CodecTestUtils.convert(dst));
129 Assertions.assertFalse(decoder.isCompleted());
130 Assertions.assertEquals(10, metrics.getBytesTransferred());
131
132 dst.clear();
133 bytesRead = decoder.read(dst);
134 Assertions.assertEquals(-1, bytesRead);
135 Assertions.assertTrue(decoder.isCompleted());
136 Assertions.assertEquals(10, metrics.getBytesTransferred());
137
138 dst.clear();
139 bytesRead = decoder.read(dst);
140 Assertions.assertEquals(-1, bytesRead);
141 Assertions.assertTrue(decoder.isCompleted());
142 Assertions.assertEquals(10, metrics.getBytesTransferred());
143
144 }
145
146 @Test
147 public void testBasicDecodingFile() throws Exception {
148 final ReadableByteChannel channel = new ReadableByteChannelMock(
149 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, StandardCharsets.US_ASCII);
150
151 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
152 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
153 final IdentityDecoder decoder = new IdentityDecoder(
154 channel, inbuf, metrics);
155
156 createTempFile();
157 try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
158 final FileChannel fchannel = testfile.getChannel();
159 long pos = 0;
160 while (!decoder.isCompleted()) {
161 final long bytesRead = decoder.transfer(fchannel, pos, 10);
162 if (bytesRead > 0) {
163 pos += bytesRead;
164 }
165 }
166
167 Assertions.assertEquals(testfile.length(), metrics.getBytesTransferred());
168 }
169 Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
170 CodecTestUtils.readFromFile(this.tmpfile));
171 }
172
173 @Test
174 public void testDecodingFileWithBufferedSessionData() throws Exception {
175 final ReadableByteChannel channel = new ReadableByteChannelMock(
176 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, StandardCharsets.US_ASCII);
177
178 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
179 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
180 final IdentityDecoder decoder = new IdentityDecoder(
181 channel, inbuf, metrics);
182
183 final int i = inbuf.fill(channel);
184 Assertions.assertEquals(7, i);
185
186 createTempFile();
187 try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
188 final FileChannel fchannel = testfile.getChannel();
189 long pos = 0;
190 while (!decoder.isCompleted()) {
191 final long bytesRead = decoder.transfer(fchannel, pos, 10);
192 if (bytesRead > 0) {
193 pos += bytesRead;
194 }
195 }
196
197
198 Assertions.assertEquals(testfile.length() - 7, metrics.getBytesTransferred());
199 }
200 Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
201 CodecTestUtils.readFromFile(this.tmpfile));
202 }
203
204 @Test
205 public void testDecodingFileWithOffsetAndBufferedSessionData() throws Exception {
206 final ReadableByteChannel channel = new ReadableByteChannelMock(
207 new String[] {"stuff; ", "more stuff; ", "a lot more stuff!"}, StandardCharsets.US_ASCII);
208
209 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
210 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
211 final IdentityDecoder decoder = new IdentityDecoder(
212 channel, inbuf, metrics);
213
214 final int i = inbuf.fill(channel);
215 Assertions.assertEquals(7, i);
216
217 final byte[] beginning = "beginning; ".getBytes(StandardCharsets.US_ASCII);
218
219 createTempFile();
220 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
221 try {
222 testfile.write(beginning);
223 } finally {
224 testfile.close();
225 }
226
227 testfile = new RandomAccessFile(this.tmpfile, "rw");
228 try {
229 final FileChannel fchannel = testfile.getChannel();
230 long pos = beginning.length;
231 while (!decoder.isCompleted()) {
232 if(testfile.length() < pos) {
233 testfile.setLength(pos);
234 }
235 final long bytesRead = decoder.transfer(fchannel, pos, 10);
236 if (bytesRead > 0) {
237 pos += bytesRead;
238 }
239 }
240
241
242 Assertions.assertEquals(testfile.length() - 7 - beginning.length, metrics.getBytesTransferred());
243 } finally {
244 testfile.close();
245 }
246
247 Assertions.assertEquals("beginning; stuff; more stuff; a lot more stuff!",
248 CodecTestUtils.readFromFile(this.tmpfile));
249 }
250
251 @Test
252 public void testDecodingFileWithLimit() throws Exception {
253 final ReadableByteChannel channel = new ReadableByteChannelMock(
254 new String[] {"stuff; more stuff; ", "a lot more stuff!"}, StandardCharsets.US_ASCII);
255
256 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
257 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
258 final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
259
260 final int i = inbuf.fill(channel);
261 Assertions.assertEquals(19, i);
262
263 createTempFile();
264 try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
265 final FileChannel fchannel = testfile.getChannel();
266 long pos = 0;
267
268
269 long bytesRead = decoder.transfer(fchannel, pos, 1);
270 Assertions.assertEquals(1, bytesRead);
271 Assertions.assertFalse(decoder.isCompleted());
272 Assertions.assertEquals(0, metrics.getBytesTransferred());
273 pos += bytesRead;
274
275 bytesRead = decoder.transfer(fchannel, pos, 2);
276 Assertions.assertEquals(2, bytesRead);
277 Assertions.assertFalse(decoder.isCompleted());
278 Assertions.assertEquals(0, metrics.getBytesTransferred());
279 pos += bytesRead;
280
281 bytesRead = decoder.transfer(fchannel, pos, 17);
282 Assertions.assertEquals(16, bytesRead);
283 Assertions.assertFalse(decoder.isCompleted());
284 Assertions.assertEquals(0, metrics.getBytesTransferred());
285 pos += bytesRead;
286
287
288 bytesRead = decoder.transfer(fchannel, pos, 1);
289 Assertions.assertEquals(1, bytesRead);
290 Assertions.assertFalse(decoder.isCompleted());
291 Assertions.assertEquals(1, metrics.getBytesTransferred());
292 pos += bytesRead;
293
294 bytesRead = decoder.transfer(fchannel, pos, 2);
295 Assertions.assertEquals(2, bytesRead);
296 Assertions.assertFalse(decoder.isCompleted());
297 Assertions.assertEquals(3, metrics.getBytesTransferred());
298 pos += bytesRead;
299
300 bytesRead = decoder.transfer(fchannel, pos, 15);
301 Assertions.assertEquals(14, bytesRead);
302 Assertions.assertFalse(decoder.isCompleted());
303 Assertions.assertEquals(17, metrics.getBytesTransferred());
304 pos += bytesRead;
305
306 bytesRead = decoder.transfer(fchannel, pos, 1);
307 Assertions.assertEquals(-1, bytesRead);
308 Assertions.assertTrue(decoder.isCompleted());
309 Assertions.assertEquals(17, metrics.getBytesTransferred());
310 }
311 Assertions.assertEquals("stuff; more stuff; a lot more stuff!",
312 CodecTestUtils.readFromFile(this.tmpfile));
313 }
314
315 @Test
316 public void testWriteBeyondFileSize() throws Exception {
317 final ReadableByteChannel channel = new ReadableByteChannelMock(
318 new String[] {"a"}, StandardCharsets.US_ASCII);
319
320 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
321 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
322 final IdentityDecoder decoder = new IdentityDecoder(
323 channel, inbuf, metrics);
324
325 createTempFile();
326 try (RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
327 Assertions.assertEquals(0, testfile.length());
328 final FileChannel fchannel = testfile.getChannel();
329 Assertions.assertThrows(IOException.class, () -> decoder.transfer(fchannel, 5, 10));
330 }
331 }
332
333 @Test
334 public void testInvalidConstructor() {
335 final ReadableByteChannel channel = new ReadableByteChannelMock(
336 new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII);
337
338 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
339 Assertions.assertThrows(NullPointerException.class, () -> new IdentityDecoder(null, null, null));
340 Assertions.assertThrows(NullPointerException.class, () -> new IdentityDecoder(channel, null, null));
341 Assertions.assertThrows(NullPointerException.class, () -> new IdentityDecoder(channel, inbuf, null));
342 }
343
344 @Test
345 public void testInvalidInput() throws Exception {
346 final String s = "stuff";
347 final ReadableByteChannel channel = new ReadableByteChannelMock(
348 new String[] {s}, StandardCharsets.US_ASCII);
349
350 final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII);
351 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
352 final IdentityDecoder decoder = new IdentityDecoder(channel, inbuf, metrics);
353
354 Assertions.assertThrows(NullPointerException.class, () -> decoder.read(null));
355 }
356
357 }