HTTP/2 Unit Test LocalChannel Leaks

Motivation:
Some unit HTTP/2 unit tests use LocalChannel. LocalChannel's doClose method will ensure any pending items in the queue will be released, but it may execute a Runnable on the peer's EventLoop to ensure the peer's queue is also cleaned up. The HTTP/2 unit tests close the event loop groups with no wait time so that unit tests will execute quickly, but if the doClose Runnable is in the EventLoop's queue it will not run and thus the items in the queue will not be released.

Modifications:
- Ensure all HTTP/2 unit tests which use LocalChannel wait for both client and server channels to be closed before closing the EventLoop.

Result:
Related to https://github.com/netty/netty/issues/5850.
This commit is contained in:
Scott Mitchell 2017-02-20 11:16:56 -08:00
parent 2dffc2f9fb
commit 08e0c612cf
5 changed files with 23 additions and 6 deletions

View File

@ -81,6 +81,7 @@ public class DataCompressionHttp2Test {
private Bootstrap cb; private Bootstrap cb;
private Channel serverChannel; private Channel serverChannel;
private Channel clientChannel; private Channel clientChannel;
private volatile Channel serverConnectedChannel;
private CountDownLatch serverLatch; private CountDownLatch serverLatch;
private Http2Connection serverConnection; private Http2Connection serverConnection;
private Http2Connection clientConnection; private Http2Connection clientConnection;
@ -127,6 +128,11 @@ public class DataCompressionHttp2Test {
serverChannel.close().sync(); serverChannel.close().sync();
serverChannel = null; serverChannel = null;
} }
final Channel serverConnectedChannel = this.serverConnectedChannel;
if (serverConnectedChannel != null) {
serverConnectedChannel.close().sync();
this.serverConnectedChannel = null;
}
Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS);
Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS);
Future<?> clientGroup = cb.config().group().shutdownGracefully(0, 0, MILLISECONDS); Future<?> clientGroup = cb.config().group().shutdownGracefully(0, 0, MILLISECONDS);
@ -297,6 +303,7 @@ public class DataCompressionHttp2Test {
sb.childHandler(new ChannelInitializer<Channel>() { sb.childHandler(new ChannelInitializer<Channel>() {
@Override @Override
protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) throws Exception {
serverConnectedChannel = ch;
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter(); Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter();
serverConnection.remote().flowController( serverConnection.remote().flowController(

View File

@ -93,11 +93,18 @@ public class Http2CodecTest {
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
clientChannel.close().sync(); if (clientChannel != null) {
serverChannel.close().sync(); clientChannel.close().sync();
clientChannel = null;
}
if (serverChannel != null) {
serverChannel.close().sync();
serverChannel = null;
}
final Channel serverConnectedChannel = this.serverConnectedChannel;
if (serverConnectedChannel != null) { if (serverConnectedChannel != null) {
serverConnectedChannel.close().sync(); serverConnectedChannel.close().sync();
serverConnectedChannel = null; this.serverConnectedChannel = null;
} }
} }

View File

@ -118,9 +118,10 @@ public class Http2ConnectionRoundtripTest {
serverChannel.close().sync(); serverChannel.close().sync();
serverChannel = null; serverChannel = null;
} }
final Channel serverConnectedChannel = this.serverConnectedChannel;
if (serverConnectedChannel != null) { if (serverConnectedChannel != null) {
serverConnectedChannel.close().sync(); serverConnectedChannel.close().sync();
serverConnectedChannel = null; this.serverConnectedChannel = null;
} }
Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS);
Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS);

View File

@ -113,9 +113,10 @@ public class HttpToHttp2ConnectionHandlerTest {
serverChannel.close().sync(); serverChannel.close().sync();
serverChannel = null; serverChannel = null;
} }
final Channel serverConnectedChannel = this.serverConnectedChannel;
if (serverConnectedChannel != null) { if (serverConnectedChannel != null) {
serverConnectedChannel.close().sync(); serverConnectedChannel.close().sync();
serverConnectedChannel = null; this.serverConnectedChannel = null;
} }
Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS);
Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS);

View File

@ -119,9 +119,10 @@ public class InboundHttp2ToHttpAdapterTest {
serverChannel.close().sync(); serverChannel.close().sync();
serverChannel = null; serverChannel = null;
} }
final Channel serverConnectedChannel = this.serverConnectedChannel;
if (serverConnectedChannel != null) { if (serverConnectedChannel != null) {
serverConnectedChannel.close().sync(); serverConnectedChannel.close().sync();
serverConnectedChannel = null; this.serverConnectedChannel = null;
} }
Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverGroup = sb.config().group().shutdownGracefully(0, 0, MILLISECONDS);
Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS); Future<?> serverChildGroup = sb.config().childGroup().shutdownGracefully(0, 0, MILLISECONDS);