@Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        cleanupSafely(ctx);
        super.channelInactive(ctx);
    }
@Test
    public void testCleanupThrows() {
        HttpContentEncoder encoder = new HttpContentEncoder() {
            @Override
            protected Result beginEncode(HttpResponse httpResponse, String acceptEncoding) throws Exception {
                return new Result("myencoding", new EmbeddedChannel(
                        new ChannelInboundHandlerAdapter() {
                    @Override
                    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                        ctx.fireExceptionCaught(new EncoderException());
                        ctx.fireChannelInactive();
                    }
                }));
            }
        };

        final AtomicBoolean channelInactiveCalled = new AtomicBoolean();
        final EmbeddedChannel channel = new EmbeddedChannel(encoder, new ChannelInboundHandlerAdapter() {
            @Override
            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                assertTrue(channelInactiveCalled.compareAndSet(false, true));
                super.channelInactive(ctx);
            }
        });
        assertTrue(channel.writeInbound(new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/")));
        assertTrue(channel.writeOutbound(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)));
        HttpContent content = new DefaultHttpContent(Unpooled.buffer().writeZero(10));
        assertTrue(channel.writeOutbound(content));
        assertEquals(1, content.refCnt());
        assertThrows(CodecException.class, new Executable() {
            @Override
            public void execute() {
                channel.finishAndReleaseAll();
            }
        });

        assertTrue(channelInactiveCalled.get());
        assertEquals(0, content.refCnt());
    }