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.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   * Simple tests for {@link IdentityEncoder}.
49   */
50  public class TestIdentityEncoder {
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 IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
73          Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
74          encoder.complete();
75  
76          Assertions.assertTrue(encoder.isCompleted());
77          Assertions.assertEquals(5, metrics.getBytesTransferred());
78  
79          outbuf.flush(channel);
80          final String s = channel.dump(StandardCharsets.US_ASCII);
81  
82          Assertions.assertEquals("stuff", s);
83          Assertions.assertEquals("[identity; completed: true]", encoder.toString());
84      }
85  
86      @Test
87      public void testCodingEmptySrcBuffer() throws Exception {
88          final WritableByteChannelMock channel = new WritableByteChannelMock(64);
89          final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
90          final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
91  
92          final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
93          encoder.write(CodecTestUtils.wrap("stuff"));
94  
95          final ByteBuffer empty = ByteBuffer.allocate(100);
96          empty.flip();
97          encoder.write(empty);
98          encoder.write(null);
99          encoder.complete();
100 
101         outbuf.flush(channel);
102         final String s = channel.dump(StandardCharsets.US_ASCII);
103 
104         Assertions.assertTrue(encoder.isCompleted());
105         Assertions.assertEquals("stuff", s);
106     }
107 
108     @Test
109     public void testCodingCompleted() throws Exception {
110         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
111         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
112         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
113 
114         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
115         encoder.write(CodecTestUtils.wrap("stuff"));
116         encoder.complete();
117 
118         Assertions.assertThrows(IllegalStateException.class, () -> encoder.write(CodecTestUtils.wrap("more stuff")));
119     }
120 
121     @Test
122     public void testInvalidConstructor() {
123         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
124         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
125 
126         Assertions.assertThrows(NullPointerException.class, () -> new IdentityEncoder(null, null, null));
127         Assertions.assertThrows(NullPointerException.class, () -> new IdentityEncoder(channel, null, null));
128         Assertions.assertThrows(NullPointerException.class, () -> new IdentityEncoder(channel, outbuf, null));
129     }
130 
131     @Test
132     public void testCodingFromFile() throws Exception {
133         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
134         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
135         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
136 
137         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
138 
139         createTempFile();
140         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
141         try {
142             testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
143             testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
144         } finally {
145             testfile.close();
146         }
147 
148         testfile = new RandomAccessFile(this.tmpfile, "rw");
149         try {
150             final FileChannel fchannel = testfile.getChannel();
151             encoder.transfer(fchannel, 0, 20);
152         } finally {
153             testfile.close();
154         }
155 
156         final String s = channel.dump(StandardCharsets.US_ASCII);
157 
158         Assertions.assertFalse(encoder.isCompleted());
159         Assertions.assertEquals("stuff;more stuff", s);
160     }
161 
162     @Test
163     public void testCodingEmptyFile() throws Exception {
164         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
165         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
166         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
167 
168         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
169         encoder.write(CodecTestUtils.wrap("stuff;"));
170 
171         //Create an empty file
172         createTempFile();
173         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
174         testfile.close();
175 
176         testfile = new RandomAccessFile(this.tmpfile, "rw");
177         try {
178             final FileChannel fchannel = testfile.getChannel();
179             encoder.transfer(fchannel, 0, 20);
180             encoder.write(CodecTestUtils.wrap("more stuff"));
181         } finally {
182             testfile.close();
183         }
184 
185         final String s = channel.dump(StandardCharsets.US_ASCII);
186 
187         Assertions.assertFalse(encoder.isCompleted());
188         Assertions.assertEquals("stuff;more stuff", s);
189     }
190 
191     @Test
192     public void testCodingFromFileSmaller() throws Exception {
193         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
194         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
195         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
196 
197         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
198 
199         createTempFile();
200         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
201         try {
202             testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
203             testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
204         } finally {
205             testfile.close();
206         }
207 
208         testfile = new RandomAccessFile(this.tmpfile, "rw");
209         try {
210             final FileChannel fchannel = testfile.getChannel();
211             encoder.transfer(fchannel, 0, 20);
212         } finally {
213             testfile.close();
214         }
215         final String s = channel.dump(StandardCharsets.US_ASCII);
216 
217         Assertions.assertFalse(encoder.isCompleted());
218         Assertions.assertEquals("stuff;more stuff", s);
219     }
220 
221     @Test
222     public void testCodingFromFileFlushBuffer() throws Exception {
223         final WritableByteChannelMock channel = new WritableByteChannelMock(64);
224         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
225         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
226 
227         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
228 
229         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
230         chbuffer.append("header");
231         outbuf.writeLine(chbuffer);
232 
233         createTempFile();
234         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
235         try {
236             testfile.write("stuff;".getBytes(StandardCharsets.US_ASCII));
237             testfile.write("more stuff".getBytes(StandardCharsets.US_ASCII));
238         } finally {
239             testfile.close();
240         }
241 
242         testfile = new RandomAccessFile(this.tmpfile, "rw");
243         try {
244             final FileChannel fchannel = testfile.getChannel();
245             encoder.transfer(fchannel, 0, 20);
246         } finally {
247             testfile.close();
248         }
249         final String s = channel.dump(StandardCharsets.US_ASCII);
250 
251         Assertions.assertFalse(encoder.isCompleted());
252         Assertions.assertEquals("header\r\nstuff;more stuff", s);
253     }
254 
255     @Test
256     public void testCodingFromFileChannelSaturated() throws Exception {
257         final WritableByteChannelMock channel = new WritableByteChannelMock(64, 4);
258         final SessionOutputBuffer outbuf = new SessionOutputBufferImpl(1024, 128);
259         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
260 
261         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics);
262 
263         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
264         chbuffer.append("header");
265         outbuf.writeLine(chbuffer);
266 
267         createTempFile();
268         RandomAccessFile testfile = new RandomAccessFile(this.tmpfile, "rw");
269         try {
270             testfile.write("stuff".getBytes(StandardCharsets.US_ASCII));
271         } finally {
272             testfile.close();
273         }
274 
275         testfile = new RandomAccessFile(this.tmpfile, "rw");
276         try {
277             final FileChannel fchannel = testfile.getChannel();
278             encoder.transfer(fchannel, 0, 20);
279             encoder.transfer(fchannel, 0, 20);
280         } finally {
281             testfile.close();
282         }
283         final String s = channel.dump(StandardCharsets.US_ASCII);
284 
285         Assertions.assertFalse(encoder.isCompleted());
286         Assertions.assertEquals("head", s);
287     }
288 
289     @Test
290     public void testCodingNoFragmentBuffering() throws Exception {
291         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
292         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
293         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
294 
295         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
296         chbuffer.append("header");
297         outbuf.writeLine(chbuffer);
298         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 0);
299         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
300 
301         Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
302         Mockito.verify(outbuf, Mockito.never()).write(ArgumentMatchers.<ByteBuffer>any());
303         Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
304 
305         Assertions.assertEquals(13, metrics.getBytesTransferred());
306 
307         outbuf.flush(channel);
308         final String s = channel.dump(StandardCharsets.US_ASCII);
309 
310         Assertions.assertEquals("header\r\nstuff", s);
311     }
312 
313     @Test
314     public void testCodingFragmentBuffering() throws Exception {
315         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
316         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
317         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
318 
319         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
320         chbuffer.append("header");
321         outbuf.writeLine(chbuffer);
322         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 32);
323         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
324 
325         Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
326         Mockito.verify(outbuf, Mockito.times(1)).write(ArgumentMatchers.<ByteBuffer>any());
327         Mockito.verify(outbuf, Mockito.never()).flush(channel);
328 
329         Assertions.assertEquals(0, metrics.getBytesTransferred());
330 
331         outbuf.flush(channel);
332         final String s = channel.dump(StandardCharsets.US_ASCII);
333 
334         Assertions.assertEquals("header\r\nstuff", s);
335     }
336 
337     @Test
338     public void testCodingFragmentBufferingMultipleFragments() throws Exception {
339         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
340         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
341         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
342 
343         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 32);
344         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
345         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
346         Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
347 
348         Mockito.verify(channel, Mockito.never()).write(ArgumentMatchers.any());
349         Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
350         Mockito.verify(outbuf, Mockito.never()).flush(channel);
351 
352         Assertions.assertEquals(0, metrics.getBytesTransferred());
353 
354         outbuf.flush(channel);
355         final String s = channel.dump(StandardCharsets.US_ASCII);
356 
357         Assertions.assertEquals("stuff-more stuff", s);
358     }
359 
360     @Test
361     public void testCodingFragmentBufferingLargeFragment() throws Exception {
362         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
363         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
364         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
365 
366         final CharArrayBuffer chbuffer = new CharArrayBuffer(16);
367         chbuffer.append("header");
368         outbuf.writeLine(chbuffer);
369         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 2);
370         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
371 
372         Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
373         Mockito.verify(outbuf, Mockito.never()).write(ArgumentMatchers.<ByteBuffer>any());
374         Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
375 
376         Assertions.assertEquals(13, metrics.getBytesTransferred());
377 
378         outbuf.flush(channel);
379         final String s = channel.dump(StandardCharsets.US_ASCII);
380         Assertions.assertEquals("header\r\nstuff", s);
381     }
382 
383     @Test
384     public void testCodingFragmentBufferingTinyFragments() 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 IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 1);
390         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
391         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
392         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
393         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
394         Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
395 
396         Mockito.verify(channel, Mockito.times(5)).write(ArgumentMatchers.any());
397         Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
398         Mockito.verify(outbuf, Mockito.times(3)).flush(channel);
399 
400         Assertions.assertEquals(18, metrics.getBytesTransferred());
401 
402         outbuf.flush(channel);
403         final String s = channel.dump(StandardCharsets.US_ASCII);
404 
405         Assertions.assertEquals("stuff---more stuff", s);
406     }
407 
408     @Test
409     public void testCodingFragmentBufferingTinyFragments2() throws Exception {
410         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
411         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
412         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
413 
414         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 2);
415         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
416         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
417         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
418         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
419         Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
420 
421         Mockito.verify(channel, Mockito.times(4)).write(ArgumentMatchers.any());
422         Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
423         Mockito.verify(outbuf, Mockito.times(2)).flush(channel);
424 
425         Assertions.assertEquals(18, metrics.getBytesTransferred());
426 
427         outbuf.flush(channel);
428         final String s = channel.dump(StandardCharsets.US_ASCII);
429 
430         Assertions.assertEquals("stuff---more stuff", s);
431     }
432 
433     @Test
434     public void testCodingFragmentBufferingTinyFragments3() throws Exception {
435         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
436         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
437         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
438 
439         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 3);
440         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
441         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
442         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
443         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
444         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
445         Assertions.assertEquals(2, encoder.write(CodecTestUtils.wrap("--")));
446         Assertions.assertEquals(10, encoder.write(CodecTestUtils.wrap("more stuff")));
447 
448         Mockito.verify(channel, Mockito.times(4)).write(ArgumentMatchers.any());
449         Mockito.verify(outbuf, Mockito.times(5)).write(ArgumentMatchers.<ByteBuffer>any());
450         Mockito.verify(outbuf, Mockito.times(2)).flush(channel);
451 
452         Assertions.assertEquals(21, metrics.getBytesTransferred());
453 
454         outbuf.flush(channel);
455         final String s = channel.dump(StandardCharsets.US_ASCII);
456 
457         Assertions.assertEquals("stuff------more stuff", s);
458     }
459 
460     @Test
461     public void testCodingFragmentBufferingBufferFlush() throws Exception {
462         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
463         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
464         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
465 
466         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 8);
467         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
468         Assertions.assertEquals(6, encoder.write(CodecTestUtils.wrap("-stuff")));
469 
470         Mockito.verify(channel, Mockito.times(1)).write(ArgumentMatchers.any());
471         Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
472         Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
473 
474         Assertions.assertEquals(8, metrics.getBytesTransferred());
475         Assertions.assertEquals(3, outbuf.length());
476 
477         outbuf.flush(channel);
478         final String s = channel.dump(StandardCharsets.US_ASCII);
479 
480         Assertions.assertEquals("stuff-stuff", s);
481     }
482 
483     @Test
484     public void testCodingFragmentBufferingBufferFlush2() throws Exception {
485         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64));
486         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
487         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
488 
489         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 8);
490         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
491         Assertions.assertEquals(16, encoder.write(CodecTestUtils.wrap("-much more stuff")));
492 
493         Mockito.verify(channel, Mockito.times(2)).write(ArgumentMatchers.any());
494         Mockito.verify(outbuf, Mockito.times(1)).write(ArgumentMatchers.<ByteBuffer>any());
495         Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
496 
497         Assertions.assertEquals(21, metrics.getBytesTransferred());
498         Assertions.assertEquals(0, outbuf.length());
499 
500         outbuf.flush(channel);
501         final String s = channel.dump(StandardCharsets.US_ASCII);
502 
503         Assertions.assertEquals("stuff-much more stuff", s);
504     }
505 
506     @Test
507     public void testCodingFragmentBufferingChannelSaturated() throws Exception {
508         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64, 8));
509         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
510         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
511 
512         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 3);
513         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
514         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
515         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
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(0, encoder.write(CodecTestUtils.wrap("-")));
521         Assertions.assertEquals(0, encoder.write(CodecTestUtils.wrap("more stuff")));
522 
523         Mockito.verify(channel, Mockito.times(5)).write(ArgumentMatchers.any());
524         Mockito.verify(outbuf, Mockito.times(6)).write(ArgumentMatchers.<ByteBuffer>any());
525         Mockito.verify(outbuf, Mockito.times(4)).flush(channel);
526 
527         Assertions.assertEquals(8, metrics.getBytesTransferred());
528 
529         outbuf.flush(channel);
530         final String s = channel.dump(StandardCharsets.US_ASCII);
531 
532         Assertions.assertEquals("stuff---", s);
533         Assertions.assertEquals(3, outbuf.length());
534     }
535 
536     @Test
537     public void testCodingFragmentBufferingChannelSaturated2() throws Exception {
538         final WritableByteChannelMock channel = Mockito.spy(new WritableByteChannelMock(64, 8));
539         final SessionOutputBuffer outbuf = Mockito.spy(new SessionOutputBufferImpl(1024, 128));
540         final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics();
541 
542         final IdentityEncoder encoder = new IdentityEncoder(channel, outbuf, metrics, 8);
543         Assertions.assertEquals(5, encoder.write(CodecTestUtils.wrap("stuff")));
544         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
545         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("-")));
546         Assertions.assertEquals(1, encoder.write(CodecTestUtils.wrap("much more stuff")));
547 
548         Mockito.verify(channel, Mockito.times(3)).write(ArgumentMatchers.any());
549         Mockito.verify(outbuf, Mockito.times(3)).write(ArgumentMatchers.<ByteBuffer>any());
550         Mockito.verify(outbuf, Mockito.times(1)).flush(channel);
551 
552         Assertions.assertEquals(8, metrics.getBytesTransferred());
553 
554         outbuf.flush(channel);
555         final String s = channel.dump(StandardCharsets.US_ASCII);
556 
557         Assertions.assertEquals("stuff--m", s);
558         Assertions.assertEquals(0, outbuf.length());
559     }
560 
561 }