From 614b9e0f25e81052ccd1357c7999d0e74a121663 Mon Sep 17 00:00:00 2001 From: Scott Mitchell Date: Fri, 26 Jan 2018 17:33:51 -0800 Subject: [PATCH] Add tests for Http2MultiplexChannel close promise completion consistency with AbstractChannel Motivation: The completion order of promises in Http2MultiplexChannel#close should be consistent with that of AbstractChannel. Otherwise this may result in Future listeners seeing incorrect channel state. Modifications: Add tests cases. Result: Ensure consistent behavior between Http2MultiplexChannel and AbstractChannel. --- .../codec/http2/Http2MultiplexCodecTest.java | 73 ++++++++++++++++++- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java index cd4e103bbc..111f080bf7 100644 --- a/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java +++ b/codec-http2/src/test/java/io/netty/handler/codec/http2/Http2MultiplexCodecTest.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -29,15 +30,14 @@ import io.netty.handler.codec.http.HttpScheme; import io.netty.handler.codec.http2.Http2Exception.StreamException; import io.netty.util.AsciiString; import io.netty.util.AttributeKey; - -import java.net.InetSocketAddress; -import java.util.concurrent.atomic.AtomicBoolean; - import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import java.net.InetSocketAddress; +import java.util.concurrent.atomic.AtomicBoolean; + import static io.netty.util.ReferenceCountUtil.release; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -367,6 +367,71 @@ public class Http2MultiplexCodecTest { future.syncUninterruptibly(); } + @Test + public void channelClosedWhenCloseListenerCompletes() { + LastInboundHandler inboundHandler = streamActiveAndWriteHeaders(inboundStream); + Http2StreamChannel childChannel = (Http2StreamChannel) inboundHandler.channel(); + + assertTrue(childChannel.isOpen()); + assertTrue(childChannel.isActive()); + + final AtomicBoolean channelOpen = new AtomicBoolean(true); + final AtomicBoolean channelActive = new AtomicBoolean(true); + + // Create a promise before actually doing the close, because otherwise we would be adding a listener to a future + // that is already completed because we are using EmbeddedChannel which executes code in the JUnit thread. + ChannelPromise p = childChannel.newPromise(); + p.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) { + channelOpen.set(future.channel().isOpen()); + channelActive.set(future.channel().isActive()); + } + }); + childChannel.close(p).syncUninterruptibly(); + + assertFalse(channelOpen.get()); + assertFalse(childChannel.isActive()); + } + + @Test + public void channelClosedWhenChannelClosePromiseCompletes() { + LastInboundHandler inboundHandler = streamActiveAndWriteHeaders(inboundStream); + Http2StreamChannel childChannel = (Http2StreamChannel) inboundHandler.channel(); + + assertTrue(childChannel.isOpen()); + assertTrue(childChannel.isActive()); + + final AtomicBoolean channelOpen = new AtomicBoolean(true); + final AtomicBoolean channelActive = new AtomicBoolean(true); + + childChannel.closeFuture().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) { + channelOpen.set(future.channel().isOpen()); + channelActive.set(future.channel().isActive()); + } + }); + childChannel.close().syncUninterruptibly(); + + assertFalse(channelOpen.get()); + assertFalse(childChannel.isActive()); + } + + @Test + public void channelClosedTwiceMarksPromiseAsSuccessful() { + LastInboundHandler inboundHandler = streamActiveAndWriteHeaders(inboundStream); + Http2StreamChannel childChannel = (Http2StreamChannel) inboundHandler.channel(); + + assertTrue(childChannel.isOpen()); + assertTrue(childChannel.isActive()); + childChannel.close().syncUninterruptibly(); + childChannel.close().syncUninterruptibly(); + + assertFalse(childChannel.isOpen()); + assertFalse(childChannel.isActive()); + } + @Test public void settingChannelOptsAndAttrs() { AttributeKey key = AttributeKey.newInstance("foo");