@Override
    protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Object> out) throws Exception {
        if (serverConfig.handleCloseFrames() && frame instanceof CloseWebSocketFrame) {
            WebSocketServerHandshaker handshaker = getHandshaker(ctx.channel());
            if (handshaker != null) {
                frame.retain();
                ChannelPromise promise = ctx.newPromise();
                closeSent(promise);
                handshaker.close(ctx, (CloseWebSocketFrame) frame, promise);
            } else {
                ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
            }
            return;
        }
        super.decode(ctx, frame, out);
    }
@Test
    public void testExplicitCloseFrameSentWhenClientChannelClosed() throws Exception {
        WebSocketCloseStatus closeStatus = WebSocketCloseStatus.INVALID_PAYLOAD_DATA;
        EmbeddedChannel client = createClient();
        EmbeddedChannel server = createServer();

        assertFalse(server.writeInbound(client.<ByteBuf>readOutbound()));
        assertFalse(client.writeInbound(server.<ByteBuf>readOutbound()));

        // When client channel closed with explicit close-frame
        assertTrue(client.writeOutbound(new CloseWebSocketFrame(closeStatus)));
        client.close();

        // Then client receives provided close-frame
        assertFalse(server.writeInbound(client.<ByteBuf>readOutbound()));
        assertFalse(client.isOpen());
        assertFalse(server.isOpen());

        CloseWebSocketFrame closeMessage = decode(server.<ByteBuf>readOutbound(), CloseWebSocketFrame.class);
        assertEquals(closeMessage.statusCode(), closeStatus.code());
        closeMessage.release();

        assertFalse(client.finishAndReleaseAll());
        assertFalse(server.finishAndReleaseAll());
    }