Http2ConnectionHandler extends ByteToMessageDecoder implements Http2LifecycleManager,
                                                                            ChannelOutboundHandler { @Override public ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode, final ChannelPromise promise) { final Http2Stream stream = connection().stream(streamId); if (stream == null || stream.isResetSent()) { return promise.setSuccess(); } final ChannelFuture future; if (stream.state() == IDLE || (connection().local().created(stream) && !stream.isHeaderSent())) { future = promise.setSuccess(); } else { future = frameWriter().writeRstStream(ctx, streamId, errorCode, promise); } stream.resetSent(); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (future.isSuccess()) { closeStream(stream, promise); } else { onConnectionError(ctx, future.cause(), null); } } }); return future; } protected  Http2ConnectionHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
                                     Http2Settings initialSettings); long gracefulShutdownTimeoutMillis(); void gracefulShutdownTimeoutMillis(long gracefulShutdownTimeoutMillis); Http2Connection connection(); Http2ConnectionDecoder decoder(); Http2ConnectionEncoder encoder(); void onHttpClientUpgrade(); void onHttpServerUpgrade(Http2Settings settings); @Override void flush(ChannelHandlerContext ctx); @Override void handlerAdded(ChannelHandlerContext ctx); @Override void channelActive(ChannelHandlerContext ctx); @Override void channelInactive(ChannelHandlerContext ctx); @Override void channelWritabilityChanged(ChannelHandlerContext ctx); @Override void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise); @Override void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
                        ChannelPromise promise); @Override void disconnect(ChannelHandlerContext ctx, ChannelPromise promise); @Override void close(ChannelHandlerContext ctx, ChannelPromise promise); @Override void deregister(ChannelHandlerContext ctx, ChannelPromise promise); @Override void read(ChannelHandlerContext ctx); @Override void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise); @Override void channelReadComplete(ChannelHandlerContext ctx); @Override void exceptionCaught(ChannelHandlerContext ctx, Throwable cause); @Override void closeStreamLocal(Http2Stream stream, ChannelFuture future); @Override void closeStreamRemote(Http2Stream stream, ChannelFuture future); @Override void closeStream(final Http2Stream stream, ChannelFuture future); @Override void onError(ChannelHandlerContext ctx, Throwable cause); @Override ChannelFuture resetStream(final ChannelHandlerContext ctx, int streamId, long errorCode,
            final ChannelPromise promise); @Override ChannelFuture goAway(final ChannelHandlerContext ctx, final int lastStreamId, final long errorCode,
                                final ByteBuf debugData, ChannelPromise promise);  }
@Test public void writeRstOnNonExistantStreamShouldSucceed() throws Exception { handler = newHandler(); handler.resetStream(ctx, NON_EXISTANT_STREAM_ID, STREAM_CLOSED.code(), promise); verify(frameWriter, never()) .writeRstStream(any(ChannelHandlerContext.class), anyInt(), anyLong(), any(ChannelPromise.class)); assertTrue(promise.isDone()); assertTrue(promise.isSuccess()); assertNull(promise.cause()); }
@Test public void writeRstOnClosedStreamShouldSucceed() throws Exception { handler = newHandler(); when(frameWriter.writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class))).thenReturn(future); when(stream.state()).thenReturn(CLOSED); when(stream.isHeaderSent()).thenReturn(true); handler.resetStream(ctx, STREAM_ID, STREAM_CLOSED.code(), promise); verify(frameWriter).writeRstStream(eq(ctx), eq(STREAM_ID), anyLong(), any(ChannelPromise.class)); }