PageRenderTime 31ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/codec/src/test/java/io/netty/handler/codec/ReplayingDecoderTest.java

https://bitbucket.org/htdzzc/netty
Java | 316 lines | 238 code | 56 blank | 22 comment | 12 complexity | 48d40fe7cecff52c07c2b71cf2d4f6ac MD5 | raw file
  1. /*
  2. * Copyright 2012 The Netty Project
  3. *
  4. * The Netty Project licenses this file to you under the Apache License,
  5. * version 2.0 (the "License"); you may not use this file except in compliance
  6. * with the License. You may obtain a copy of the License at:
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations
  14. * under the License.
  15. */
  16. package io.netty.handler.codec;
  17. import io.netty.buffer.ByteBuf;
  18. import io.netty.buffer.Unpooled;
  19. import io.netty.channel.ChannelHandlerContext;
  20. import io.netty.channel.ChannelInboundHandlerAdapter;
  21. import io.netty.channel.embedded.EmbeddedChannel;
  22. import io.netty.channel.socket.ChannelInputShutdownEvent;
  23. import io.netty.util.internal.PlatformDependent;
  24. import org.junit.Test;
  25. import java.util.List;
  26. import java.util.concurrent.BlockingQueue;
  27. import java.util.concurrent.LinkedBlockingDeque;
  28. import java.util.concurrent.atomic.AtomicReference;
  29. import static org.junit.Assert.*;
  30. public class ReplayingDecoderTest {
  31. @Test
  32. public void testLineProtocol() {
  33. EmbeddedChannel ch = new EmbeddedChannel(new LineDecoder());
  34. // Ordinary input
  35. ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'A' }));
  36. assertNull(ch.readInbound());
  37. ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'B' }));
  38. assertNull(ch.readInbound());
  39. ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'C' }));
  40. assertNull(ch.readInbound());
  41. ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { '\n' }));
  42. ByteBuf buf = Unpooled.wrappedBuffer(new byte[] { 'A', 'B', 'C' });
  43. ByteBuf buf2 = ch.readInbound();
  44. assertEquals(buf, buf2);
  45. buf.release();
  46. buf2.release();
  47. // Truncated input
  48. ch.writeInbound(Unpooled.wrappedBuffer(new byte[] { 'A' }));
  49. assertNull(ch.readInbound());
  50. ch.finish();
  51. assertNull(ch.readInbound());
  52. }
  53. private static final class LineDecoder extends ReplayingDecoder<Void> {
  54. LineDecoder() {
  55. }
  56. @Override
  57. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
  58. ByteBuf msg = in.readBytes(in.bytesBefore((byte) '\n'));
  59. out.add(msg);
  60. in.skipBytes(1);
  61. }
  62. }
  63. @Test
  64. public void testReplacement() throws Exception {
  65. EmbeddedChannel ch = new EmbeddedChannel(new BloatedLineDecoder());
  66. // "AB" should be forwarded to LineDecoder by BloatedLineDecoder.
  67. ch.writeInbound(Unpooled.wrappedBuffer(new byte[]{'A', 'B'}));
  68. assertNull(ch.readInbound());
  69. // "C\n" should be appended to "AB" so that LineDecoder decodes it correctly.
  70. ch.writeInbound(Unpooled.wrappedBuffer(new byte[]{'C', '\n'}));
  71. ByteBuf buf = Unpooled.wrappedBuffer(new byte[] { 'A', 'B', 'C' });
  72. ByteBuf buf2 = ch.readInbound();
  73. assertEquals(buf, buf2);
  74. buf.release();
  75. buf2.release();
  76. ch.finish();
  77. assertNull(ch.readInbound());
  78. }
  79. private static final class BloatedLineDecoder extends ChannelInboundHandlerAdapter {
  80. @Override
  81. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  82. ctx.pipeline().replace(this, "less-bloated", new LineDecoder());
  83. ctx.pipeline().fireChannelRead(msg);
  84. }
  85. }
  86. @Test
  87. public void testSingleDecode() throws Exception {
  88. LineDecoder decoder = new LineDecoder();
  89. decoder.setSingleDecode(true);
  90. EmbeddedChannel ch = new EmbeddedChannel(decoder);
  91. // "C\n" should be appended to "AB" so that LineDecoder decodes it correctly.
  92. ch.writeInbound(Unpooled.wrappedBuffer(new byte[]{'C', '\n' , 'B', '\n'}));
  93. ByteBuf buf = Unpooled.wrappedBuffer(new byte[] {'C'});
  94. ByteBuf buf2 = ch.readInbound();
  95. assertEquals(buf, buf2);
  96. buf.release();
  97. buf2.release();
  98. assertNull("Must be null as it must only decode one frame", ch.readInbound());
  99. ch.read();
  100. ch.finish();
  101. buf = Unpooled.wrappedBuffer(new byte[] {'B'});
  102. buf2 = ch.readInbound();
  103. assertEquals(buf, buf2);
  104. buf.release();
  105. buf2.release();
  106. assertNull(ch.readInbound());
  107. }
  108. @Test
  109. public void testRemoveItself() {
  110. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder() {
  111. private boolean removed;
  112. @Override
  113. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  114. assertFalse(removed);
  115. in.readByte();
  116. ctx.pipeline().remove(this);
  117. removed = true;
  118. }
  119. });
  120. ByteBuf buf = Unpooled.wrappedBuffer(new byte[] {'a', 'b', 'c'});
  121. channel.writeInbound(buf.copy());
  122. ByteBuf b = channel.readInbound();
  123. assertEquals(b, buf.skipBytes(1));
  124. b.release();
  125. buf.release();
  126. }
  127. @Test
  128. public void testRemoveItselfWithReplayError() {
  129. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder() {
  130. private boolean removed;
  131. @Override
  132. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  133. assertFalse(removed);
  134. ctx.pipeline().remove(this);
  135. in.readBytes(1000);
  136. removed = true;
  137. }
  138. });
  139. ByteBuf buf = Unpooled.wrappedBuffer(new byte[] {'a', 'b', 'c'});
  140. channel.writeInbound(buf.copy());
  141. ByteBuf b = channel.readInbound();
  142. assertEquals("Expect to have still all bytes in the buffer", b, buf);
  143. b.release();
  144. buf.release();
  145. }
  146. @Test
  147. public void testRemoveItselfWriteBuffer() {
  148. final ByteBuf buf = Unpooled.buffer().writeBytes(new byte[] {'a', 'b', 'c'});
  149. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder() {
  150. private boolean removed;
  151. @Override
  152. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  153. assertFalse(removed);
  154. in.readByte();
  155. ctx.pipeline().remove(this);
  156. // This should not let it keep call decode
  157. buf.writeByte('d');
  158. removed = true;
  159. }
  160. });
  161. channel.writeInbound(buf.copy());
  162. ByteBuf b = channel.readInbound();
  163. assertEquals(b, Unpooled.wrappedBuffer(new byte[] { 'b', 'c'}));
  164. b.release();
  165. buf.release();
  166. }
  167. @Test
  168. public void testFireChannelReadCompleteOnInactive() throws InterruptedException {
  169. final BlockingQueue<Integer> queue = new LinkedBlockingDeque<Integer>();
  170. final ByteBuf buf = Unpooled.buffer().writeBytes(new byte[]{'a', 'b'});
  171. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() {
  172. @Override
  173. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  174. int readable = in.readableBytes();
  175. assertTrue(readable > 0);
  176. in.skipBytes(readable);
  177. out.add("data");
  178. }
  179. @Override
  180. protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  181. assertFalse(in.isReadable());
  182. out.add("data");
  183. }
  184. }, new ChannelInboundHandlerAdapter() {
  185. @Override
  186. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  187. queue.add(3);
  188. }
  189. @Override
  190. public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
  191. queue.add(1);
  192. }
  193. @Override
  194. public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  195. if (!ctx.channel().isActive()) {
  196. queue.add(2);
  197. }
  198. }
  199. });
  200. assertFalse(channel.writeInbound(buf));
  201. channel.finish();
  202. assertEquals(1, (int) queue.take());
  203. assertEquals(1, (int) queue.take());
  204. assertEquals(2, (int) queue.take());
  205. assertEquals(3, (int) queue.take());
  206. assertTrue(queue.isEmpty());
  207. }
  208. @Test
  209. public void testChannelInputShutdownEvent() {
  210. final AtomicReference<Error> error = new AtomicReference<Error>();
  211. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>(0) {
  212. private boolean decoded;
  213. @Override
  214. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  215. if (!(in instanceof ReplayingDecoderByteBuf)) {
  216. error.set(new AssertionError("in must be of type " + ReplayingDecoderByteBuf.class
  217. + " but was " + in.getClass()));
  218. return;
  219. }
  220. if (!decoded) {
  221. decoded = true;
  222. in.readByte();
  223. state(1);
  224. } else {
  225. // This will throw an ReplayingError
  226. in.skipBytes(Integer.MAX_VALUE);
  227. }
  228. }
  229. });
  230. assertFalse(channel.writeInbound(Unpooled.wrappedBuffer(new byte[] {0, 1})));
  231. channel.pipeline().fireUserEventTriggered(ChannelInputShutdownEvent.INSTANCE);
  232. assertFalse(channel.finishAndReleaseAll());
  233. Error err = error.get();
  234. if (err != null) {
  235. throw err;
  236. }
  237. }
  238. @Test
  239. public void handlerRemovedWillNotReleaseBufferIfDecodeInProgress() {
  240. EmbeddedChannel channel = new EmbeddedChannel(new ReplayingDecoder<Integer>() {
  241. @Override
  242. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
  243. ctx.pipeline().remove(this);
  244. assertTrue(in.refCnt() != 0);
  245. }
  246. @Override
  247. protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
  248. assertCumulationReleased(internalBuffer());
  249. }
  250. });
  251. byte[] bytes = new byte[1024];
  252. PlatformDependent.threadLocalRandom().nextBytes(bytes);
  253. assertTrue(channel.writeInbound(Unpooled.wrappedBuffer(bytes)));
  254. assertTrue(channel.finishAndReleaseAll());
  255. }
  256. private static void assertCumulationReleased(ByteBuf byteBuf) {
  257. assertTrue("unexpected value: " + byteBuf,
  258. byteBuf == null || byteBuf == Unpooled.EMPTY_BUFFER || byteBuf.refCnt() == 0);
  259. }
  260. }