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.charset.StandardCharsets;
36
37 import org.apache.hc.core5.http.WritableByteChannelMock;
38 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
39 import org.apache.hc.core5.http.nio.SessionOutputBuffer;
40 import org.apache.hc.core5.util.CharArrayBuffer;
41 import org.junit.jupiter.api.AfterEach;
42 import org.junit.jupiter.api.Assertions;
43 import org.junit.jupiter.api.Test;
44 import org.mockito.ArgumentMatchers;
45 import org.mockito.Mockito;
46
47
48
49
50 public class TestLengthDelimitedEncoder {
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 @AfterEach
60 public void deleteTempFile() {
61 if (this.tmpfile != null && this.tmpfile.exists()) {
62 this.tmpfile.delete();
63 }
64 }
65
66 @Test
67 public void testBasicCoding() throws Exception {
68 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
69 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
70 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
71
72 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
73 channel, outbuf, metrics, 16);
74 encoder.write(CodecTestUtils.wrap("stuff;"));
75 encoder.write(CodecTestUtils.wrap("more stuff"));
76
77 final String s = channel.dump(StandardCharsets.US_ASCII);
78
79 Assertions.assertTrue(encoder.isCompleted());
80 Assertions.assertEquals("stuff;more stuff", s);
81 Assertions.assertEquals("[content length: 16; pos: 16; completed: true]", encoder.toString());
82 }
83
84 @Test
85 public void testCodingBeyondContentLimit() throws Exception {
86 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
87 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
88 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
89
90 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
91 channel, outbuf, metrics, 16);
92 encoder.write(CodecTestUtils.wrap("stuff;"));
93 encoder.write(CodecTestUtils.wrap("more stuff; and a lot more stuff"));
94
95 final String s = channel.dump(StandardCharsets.US_ASCII);
96
97 Assertions.assertTrue(encoder.isCompleted());
98 Assertions.assertEquals("stuff;more stuff", s);
99 }
100
101 @Test
102 public void testCodingEmptyBuffer() throws Exception {
103 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
104 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
105 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
106
107 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
108 channel, outbuf, metrics, 16);
109 encoder.write(CodecTestUtils.wrap("stuff;"));
110
111 final ByteBuffer empty = ByteBuffer.allocate(100);
112 empty.flip();
113 encoder.write(empty);
114 encoder.write(null);
115
116 encoder.write(CodecTestUtils.wrap("more stuff"));
117
118 final String s = channel.dump(StandardCharsets.US_ASCII);
119
120 Assertions.assertTrue(encoder.isCompleted());
121 Assertions.assertEquals("stuff;more stuff", s);
122 }
123
124 @Test
125 public void testCodingCompleted() throws Exception {
126 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
127 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
128 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
129
130 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
131 channel, outbuf, metrics, 5);
132 encoder.write(CodecTestUtils.wrap("stuff"));
133
134 Assertions.assertThrows(IllegalStateException.class, () -> encoder.write(CodecTestUtils.wrap("more stuff")));
135 }
136
137 @Test
138 public void testInvalidConstructor() {
139 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
140 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
141 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
142
143 Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedEncoder(null, null, null, 10));
144 Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedEncoder(channel, null, null, 10));
145 Assertions.assertThrows(NullPointerException.class, () -> new LengthDelimitedEncoder(channel, outbuf, null, 10));
146 Assertions.assertThrows(IllegalArgumentException.class, () -> new LengthDelimitedEncoder(channel, outbuf, metrics, -10));
147 }
148
149 @Test
150 public void testCodingBeyondContentLimitFromFile() throws Exception {
151 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
152 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
153 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
154
155 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
156 channel, outbuf, metrics, 16);
157
158 createTempFile();
159 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
160 try {
161 testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
162 testfile.write("more stuff; and a lot more stuff".getBytes(StandardCharsets.US_ASCII));
163 } finally {
164 testfile.close();
165 }
166
167 testfile = new RandomAccessFile(this.tmpfile, "rw");
168 try {
169 final FileChannel fchannel = testfile.getChannel();
170 encoder.transfer(fchannel, 0, 20);
171 } finally {
172 testfile.close();
173 }
174
175 final String s = channel.dump(StandardCharsets.US_ASCII);
176
177 Assertions.assertTrue(encoder.isCompleted());
178 Assertions.assertEquals("stuff;more stuff", s);
179 }
180
181 @Test
182 public void testCodingEmptyFile() throws Exception {
183 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
184 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
185 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
186
187 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
188 channel, outbuf, metrics, 16);
189 encoder.write(CodecTestUtils.wrap("stuff;"));
190
191
192 createTempFile();
193 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
194 testfile.close();
195
196 testfile = new RandomAccessFile(this.tmpfile, "rw");
197 try {
198 final FileChannel fchannel = testfile.getChannel();
199 encoder.transfer(fchannel, 0, 20);
200 encoder.write(CodecTestUtils.wrap("more stuff"));
201 } finally {
202 testfile.close();
203 }
204
205 final String s = channel.dump(StandardCharsets.US_ASCII);
206
207 Assertions.assertTrue(encoder.isCompleted());
208 Assertions.assertEquals("stuff;more stuff", s);
209 }
210
211 @Test
212 public void testCodingCompletedFromFile() throws Exception {
213 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
214 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
215 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
216
217 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
218 channel, outbuf, metrics, 5);
219 encoder.write(CodecTestUtils.wrap("stuff"));
220
221 createTempFile();
222 try (final RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw")) {
223 testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
224 }
225
226 try (final RandomAccessFile file = new RandomAccessFile(this.tmpfile, "rw");
227 final FileChannel fchannel = file.getChannel()) {
228 Assertions.assertThrows(IllegalStateException.class, () -> encoder.transfer(fchannel, 0, 10));
229 }
230 }
231
232 @Test
233 public void testCodingFromFileSmaller() throws Exception {
234 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
235 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
236 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
237
238 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
239 channel, outbuf, metrics, 16);
240
241 createTempFile();
242 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
243 try {
244 testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
245 testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
246 } finally {
247 testfile.close();
248 }
249
250 testfile = new RandomAccessFile(this.tmpfile, "rw");
251 try {
252 final FileChannel fchannel = testfile.getChannel();
253 encoder.transfer(fchannel, 0, 20);
254 } finally {
255 testfile.close();
256 }
257 final String s = channel.dump(StandardCharsets.US_ASCII);
258
259 Assertions.assertTrue(encoder.isCompleted());
260 Assertions.assertEquals("stuff;more stuff", s);
261 }
262
263 @Test
264 public void testCodingFromFileFlushBuffer() throws Exception {
265 final WritableByteChannelMock channel = new WritableByteChannelMock(64);
266 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
267 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
268
269 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
270 channel, outbuf, metrics, 16);
271
272 final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
273 chbuffer.append("header");
274 outbuf.writeLine(chbuffer);
275
276 createTempFile();
277 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
278 try {
279 testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
280 testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
281 } finally {
282 testfile.close();
283 }
284
285 testfile = new RandomAccessFile(this.tmpfile, "rw");
286 try {
287 final FileChannel fchannel = testfile.getChannel();
288 encoder.transfer(fchannel, 0, 20);
289 } finally {
290 testfile.close();
291 }
292 final String s = channel.dump(StandardCharsets.US_ASCII);
293
294 Assertions.assertTrue(encoder.isCompleted());
295 Assertions.assertEquals("header\r\nstuff;more stuff", s);
296 }
297
298 @Test
299 public void testCodingFromFileChannelSaturated() throws Exception {
300 final WritableByteChannelMock channel = new WritableByteChannelMock(64, 4);
301 final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
302 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
303
304 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(
305 channel, outbuf, metrics, 16);
306
307 final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
308 chbuffer.append("header");
309 outbuf.writeLine(chbuffer);
310
311 createTempFile();
312 RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
313 try {
314 testfile.write("stuff".getBytes(StandardCharsets.US_ASCII));
315 } finally {
316 testfile.close();
317 }
318
319 testfile = new RandomAccessFile(this.tmpfile, "rw");
320 try {
321 final FileChannel fchannel = testfile.getChannel();
322 encoder.transfer(fchannel, 0, 20);
323 encoder.transfer(fchannel, 0, 20);
324 } finally {
325 testfile.close();
326 }
327 final String s = channel.dump(StandardCharsets.US_ASCII);
328
329 Assertions.assertFalse(encoder.isCompleted());
330 Assertions.assertEquals("head", s);
331 }
332
333 @Test
334 public void testCodingNoFragmentBuffering() throws Exception {
335 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
336 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
337 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
338
339 final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
340 chbuffer.append("header");
341 outbuf.writeLine(chbuffer);
342 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
343 100, 0);
344 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
345
346 Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
347 Mockito.verify(outbuf, Mockito.never()).write(ArgumentMatchers.<ByteBuffer>any());
348 Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
349
350 Assertions.assertEquals(13, metrics.getBytesTransferred());
351
352 outbuf.flush(channel);
353 final String s = channel.dump(StandardCharsets.US_ASCII);
354
355 Assertions.assertEquals("header\r\nstuff", s);
356 }
357
358 @Test
359 public void testCodingFragmentBuffering() throws Exception {
360 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
361 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
362 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
363
364 final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
365 chbuffer.append("header");
366 outbuf.writeLine(chbuffer);
367 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
368 100, 32);
369 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
370
371 Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
372 Mockito.verify(outbuf, Mockito.times(1)).write(ArgumentMatchers.<ByteBuffer>any());
373 Mockito.verify(outbuf, Mockito.never()).flush(channel);
374
375 Assertions.assertEquals(0, metrics.getBytesTransferred());
376
377 outbuf.flush(channel);
378 final String s = channel.dump(StandardCharsets.US_ASCII);
379
380 Assertions.assertEquals("header\r\nstuff", s);
381 }
382
383 @Test
384 public void testCodingFragmentBufferingMultipleFragments() throws Exception {
385 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
386 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
387 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
388
389 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
390 100, 32);
391 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
392 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
393 Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
394
395 Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
396 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
397 Mockito.verify(outbuf, Mockito.never()).flush(channel);
398
399 Assertions.assertEquals(0, metrics.getBytesTransferred());
400
401 outbuf.flush(channel);
402 final String s = channel.dump(StandardCharsets.US_ASCII);
403
404 Assertions.assertEquals("stuff-more stuff", s);
405 }
406
407 @Test
408 public void testCodingFragmentBufferingMultipleFragmentsBeyondContentLimit() throws Exception {
409 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
410 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
411 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
412
413 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
414 16, 32);
415 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
416 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
417 Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff; and a lot more stuff")));
418
419 Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
420 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
421 Mockito.verify(outbuf, Mockito.never()).flush(channel);
422
423 Assertions.assertEquals(0, metrics.getBytesTransferred());
424
425 outbuf.flush(channel);
426 final String s = channel.dump(StandardCharsets.US_ASCII);
427
428 Assertions.assertEquals("stuff-more stuff", s);
429 }
430
431 @Test
432 public void testCodingFragmentBufferingLargeFragment() throws Exception {
433 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
434 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
435 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
436
437 final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
438 chbuffer.append("header");
439 outbuf.writeLine(chbuffer);
440 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
441 100, 2);
442 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
443
444 Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
445 Mockito.verify(outbuf, Mockito.never()).write(ArgumentMatchers.<ByteBuffer>any());
446 Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
447
448 Assertions.assertEquals(13, metrics.getBytesTransferred());
449
450 outbuf.flush(channel);
451 final String s = channel.dump(StandardCharsets.US_ASCII);
452 Assertions.assertEquals("header\r\nstuff", s);
453 }
454
455 @Test
456 public void testCodingFragmentBufferingTinyFragments() throws Exception {
457 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
458 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
459 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
460
461 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
462 100, 1);
463 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
464 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
465 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
466 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
467 Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
468
469 Mockito.verify(channel, Mockito.times(5)).write(ArgumentMatchers.any());
470 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
471 Mockito.verify(outbuf, Mockito.times(3)).flush(channel);
472
473 Assertions.assertEquals(18, metrics.getBytesTransferred());
474
475 outbuf.flush(channel);
476 final String s = channel.dump(StandardCharsets.US_ASCII);
477
478 Assertions.assertEquals("stuff---more stuff", s);
479 }
480
481 @Test
482 public void testCodingFragmentBufferingTinyFragments2() throws Exception {
483 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
484 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
485 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
486
487 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
488 100, 2);
489 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
490 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
491 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
492 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
493 Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
494
495 Mockito.verify(channel, Mockito.times(4)).write(ArgumentMatchers.any());
496 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
497 Mockito.verify(outbuf, Mockito.times(2)).flush(channel);
498
499 Assertions.assertEquals(18, metrics.getBytesTransferred());
500
501 outbuf.flush(channel);
502 final String s = channel.dump(StandardCharsets.US_ASCII);
503
504 Assertions.assertEquals("stuff---more stuff", s);
505 }
506
507 @Test
508 public void testCodingFragmentBufferingTinyFragments3() throws Exception {
509 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
510 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
511 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
512
513 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
514 100, 3);
515 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
516 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
517 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
518 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
519 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
520 Assertions.assertEquals(2, encoder.write(CodecTestUtils.wrap("--")));
521 Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
522
523 Mockito.verify(channel, Mockito.times(4)).write(ArgumentMatchers.any());
524 Mockito.verify(outbuf, Mockito.times(5)).write(ArgumentMatchers.<ByteBuffer>any());
525 Mockito.verify(outbuf, Mockito.times(2)).flush(channel);
526
527 Assertions.assertEquals(21, metrics.getBytesTransferred());
528
529 outbuf.flush(channel);
530 final String s = channel.dump(StandardCharsets.US_ASCII);
531
532 Assertions.assertEquals("stuff------more stuff", s);
533 }
534
535 @Test
536 public void testCodingFragmentBufferingBufferFlush() throws Exception {
537 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
538 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
539 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
540
541 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
542 100, 8);
543 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
544 Assertions.assertEquals(6, encoder.write(CodecTestUtils.wrap("-stuff")));
545
546 Mockito.verify(channel, Mockito.times(1)).write(ArgumentMatchers.any());
547 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
548 Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
549
550 Assertions.assertEquals(8, metrics.getBytesTransferred());
551 Assertions.assertEquals(3, outbuf.length());
552
553 outbuf.flush(channel);
554 final String s = channel.dump(StandardCharsets.US_ASCII);
555
556 Assertions.assertEquals("stuff-stuff", s);
557 }
558
559 @Test
560 public void testCodingFragmentBufferingBufferFlush2() throws Exception {
561 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
562 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
563 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
564
565 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
566 100, 8);
567 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
568 Assertions.assertEquals(16, encoder.write(CodecTestUtils.wrap("-much more stuff")));
569
570 Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
571 Mockito.verify(outbuf, Mockito.times(1)).write(ArgumentMatchers.<ByteBuffer>any());
572 Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
573
574 Assertions.assertEquals(21, metrics.getBytesTransferred());
575 Assertions.assertEquals(0, outbuf.length());
576
577 outbuf.flush(channel);
578 final String s = channel.dump(StandardCharsets.US_ASCII);
579
580 Assertions.assertEquals("stuff-much more stuff", s);
581 }
582
583 @Test
584 public void testCodingFragmentBufferingChannelSaturated() throws Exception {
585 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64, 8));
586 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
587 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
588
589 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
590 100, 3);
591 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
592 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
593 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
594 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
595 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
596 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
597 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
598 Assertions.assertEquals(0, encoder.write(CodecTestUtils.wrap("-")));
599 Assertions.assertEquals(0, encoder.write(CodecTestUtils.wrap("more stuff")));
600
601 Mockito.verify(channel, Mockito.times(5)).write(ArgumentMatchers.any());
602 Mockito.verify(outbuf, Mockito.times(6)).write(ArgumentMatchers.<ByteBuffer>any());
603 Mockito.verify(outbuf, Mockito.times(4)).flush(channel);
604
605 Assertions.assertEquals(8, metrics.getBytesTransferred());
606
607 outbuf.flush(channel);
608 final String s = channel.dump(StandardCharsets.US_ASCII);
609
610 Assertions.assertEquals("stuff---", s);
611 Assertions.assertEquals(3, outbuf.length());
612 }
613
614 @Test
615 public void testCodingFragmentBufferingChannelSaturated2() throws Exception {
616 final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64, 8));
617 final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
618 final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
619
620 final LengthDelimitedEncoder encoder = new LengthDelimitedEncoder(channel, outbuf, metrics,
621 100, 8);
622 Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
623 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
624 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
625 Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("much more stuff")));
626
627 Mockito.verify(channel, Mockito.times(3)).write(ArgumentMatchers.any());
628 Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
629 Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
630
631 Assertions.assertEquals(8, metrics.getBytesTransferred());
632
633 outbuf.flush(channel);
634 final String s = channel.dump(StandardCharsets.US_ASCII);
635
636 Assertions.assertEquals("stuff--m", s);
637 Assertions.assertEquals(0, outbuf.length());
638 }
639
640 }