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.
This commit is contained in:
Scott Mitchell 2018-01-26 17:33:51 -08:00 committed by Norman Maurer
parent b423a35783
commit 614b9e0f25

View File

@ -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<String> key = AttributeKey.newInstance("foo");