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.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.charset.StandardCharsets;
33 import java.util.Arrays;
34
35 import org.apache.hc.core5.http.WritableByteChannelMock;
36 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
37 import org.apache.hc.core5.http.message.BasicHeader;
38 import org.apache.hc.core5.http.nio.SessionOutputBuffer;
39 import org.junit.jupiter.api.Assertions;
40 import org.junit.jupiter.api.Test;
41 import org.mockito.ArgumentMatchers;
42 import org.mockito.Mockito;
43
44
45
46
47 public class TestChunkEncoder {
48
49 @Test
50 public void testBasicCoding() throws Exception {
51 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
52 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
53 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
54 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
55
56 encoder.write(CodecTestUtils.wrap("12345"));
57 encoder.write(CodecTestUtils.wrap("678"));
58 encoder.write(CodecTestUtils.wrap("90"));
59 encoder.complete();
60
61 outbuf.flush(channel);
62
63 final String s = channel.dump(StandardCharsets.US_ASCII);
64
65 Assertions.assertTrue(encoder.isCompleted());
66 Assertions.assertEquals("5\r\n12345\r\n3\r\n678\r\n2\r\n90\r\n0\r\n\r\n", s);
67 Assertions.assertEquals("[chunk-coded; completed: true]", encoder.toString());
68 }
69
70 @Test
71 public void testChunkNoExceed() throws Exception {
72 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
73 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 16);
74 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
75 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
76 encoder.write(CodecTestUtils.wrap("1234"));
77 encoder.complete();
78
79 outbuf.flush(channel);
80
81 final String s = channel.dump(StandardCharsets.US_ASCII);
82
83 Assertions.assertTrue(encoder.isCompleted());
84 Assertions.assertEquals("4\r\n1234\r\n0\r\n\r\n", s);
85 }
86
87 @Test
88 public void testLimitedChannel() throws Exception {
89 final WritableByteChannelMock channel = new WritableByteChannelMock(16, 16);
90 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(16, 16);
91 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
92 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
93
94
95 channel.write(CodecTestUtils.wrap("0123456789ABCDEF"));
96
97 outbuf.write(CodecTestUtils.wrap("0123456789ABCDEF"));
98
99 final ByteBuffer src = CodecTestUtils.wrap("0123456789ABCDEF");
100 Assertions.assertEquals(0, encoder.write(src));
101 Assertions.assertEquals(0, encoder.write(src));
102 Assertions.assertEquals(0, encoder.write(src));
103
104
105 channel.reset();
106 outbuf.flush(channel);
107 channel.reset();
108
109 Assertions.assertEquals(10, encoder.write(src));
110 channel.flush();
111 Assertions.assertEquals(6, encoder.write(src));
112 channel.flush();
113 Assertions.assertEquals(0, encoder.write(src));
114
115 outbuf.flush(channel);
116 final String s = channel.dump(StandardCharsets.US_ASCII);
117 Assertions.assertEquals("4\r\n0123\r\n4\r\n4567\r\n2\r\n89\r\n4\r\nABCD\r\n2\r\nEF\r\n", s);
118 }
119
120 @Test
121 public void testBufferFragments() throws Exception {
122 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(1024));
123 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 1024);
124 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
125 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 1024);
126
127 Assertions.assertEquals(16, encoder.write(CodecTestUtils.wrap("0123456789ABCDEF")));
128 Assertions.assertEquals(16, encoder.write(CodecTestUtils.wrap("0123456789ABCDEF")));
129 Assertions.assertEquals(16, encoder.write(CodecTestUtils.wrap("0123456789ABCDEF")));
130
131 Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
132
133 outbuf.flush(channel);
134 final String s = channel.dump(StandardCharsets.US_ASCII);
135 Assertions.assertEquals("10\r\n0123456789ABCDEF\r\n10\r\n0123456789ABCDEF\r\n" +
136 "10\r\n0123456789ABCDEF\r\n", s);
137 }
138
139 @Test
140 public void testChunkExceed() throws Exception {
141 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
142 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(16, 16);
143 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
144 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
145
146 final ByteBuffer src = CodecTestUtils.wrap("0123456789ABCDEF");
147
148 Assertions.assertEquals(16, encoder.write(src));
149 Assertions.assertEquals(0, src.remaining());
150
151 outbuf.flush(channel);
152 final String s = channel.dump(StandardCharsets.US_ASCII);
153 Assertions.assertEquals("4\r\n0123\r\n4\r\n4567\r\n4\r\n89AB\r\n4\r\nCDEF\r\n", s);
154
155 }
156
157 @Test
158 public void testCodingEmptyBuffer() throws Exception {
159 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
160 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
161 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
162 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
163
164 encoder.write(CodecTestUtils.wrap("12345"));
165 encoder.write(CodecTestUtils.wrap("678"));
166 encoder.write(CodecTestUtils.wrap("90"));
167
168 final ByteBuffer empty = ByteBuffer.allocate(100);
169 empty.flip();
170 encoder.write(empty);
171 encoder.write(null);
172
173 encoder.complete();
174
175 outbuf.flush(channel);
176
177 final String s = channel.dump(StandardCharsets.US_ASCII);
178
179 Assertions.assertTrue(encoder.isCompleted());
180 Assertions.assertEquals("5\r\n12345\r\n3\r\n678\r\n2\r\n90\r\n0\r\n\r\n", s);
181 }
182
183 @Test
184 public void testCodingCompleted() throws Exception {
185 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
186 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
187 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
188 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics);
189
190 encoder.write(CodecTestUtils.wrap("12345"));
191 encoder.write(CodecTestUtils.wrap("678"));
192 encoder.write(CodecTestUtils.wrap("90"));
193 encoder.complete();
194
195 Assertions.assertThrows(IllegalStateException.class, () -> encoder.write(CodecTestUtils.wrap("more stuff")));
196 Assertions.assertThrows(IllegalStateException.class, () -> encoder.complete());
197 }
198
199 @Test
200 public void testInvalidConstructor() {
201 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
202 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
203
204 Assertions.assertThrows(NullPointerException.class, () -> new ChunkEncoder(null, null, null));
205 Assertions.assertThrows(NullPointerException.class, () -> new ChunkEncoder(channel, null, null));
206 Assertions.assertThrows(NullPointerException.class, () -> new ChunkEncoder(channel, outbuf, null));
207 }
208
209 @Test
210 public void testTrailers() throws IOException {
211 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
212 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
213 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
214 final ChunkEncoder encoder = new ChunkEncoder(channel, outbuf, metrics, 0);
215 encoder.write(CodecTestUtils.wrap("1"));
216 encoder.write(CodecTestUtils.wrap("23"));
217 encoder.complete(Arrays.asList(new BasicHeader("E", ""), new BasicHeader("Y", "Z")));
218
219 outbuf.flush(channel);
220
221 final String s = channel.dump(StandardCharsets.US_ASCII);
222
223 Assertions.assertTrue(encoder.isCompleted());
224 Assertions.assertEquals("1\r\n1\r\n2\r\n23\r\n0\r\nE: \r\nY: Z\r\n\r\n", s);
225 Assertions.assertEquals("[chunk-coded; completed: true]", encoder.toString());
226 }
227 }