/** * Test verifies the channel closure - while closing the channel * servercnxnfactory should remove all channel references to avoid * duplicate channel closure. Duplicate closure may result in * indefinite hanging due to netty open issue. * * @see <a href="https://issues.jboss.org/browse/NETTY-412">NETTY-412</a> */ @Test(timeout = 30000) public void testSendCloseSession() throws Exception { Assert.assertTrue( "Didn't instantiate ServerCnxnFactory with NettyServerCnxnFactory!", serverFactory instanceof NettyServerCnxnFactory); NettyServerCnxnFactory nettyServerFactory = (NettyServerCnxnFactory) serverFactory; final CountDownLatch channelLatch = new CountDownLatch(1); CnxnChannelHandler channelHandler = nettyServerFactory.new CnxnChannelHandler() { @Override public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { LOG.info("Recieves channel disconnected event"); channelLatch.countDown(); } }; LOG.info("Adding custom channel handler for simulation"); nettyServerFactory.bootstrap.getPipeline().remove("servercnxnfactory"); nettyServerFactory.bootstrap.getPipeline().addLast("servercnxnfactory", channelHandler); final ZooKeeper zk = createClient(); final String path = "/a"; try { // make sure zkclient works zk.create(path, "test".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); Assert.assertNotNull("Didn't create znode:" + path, zk.exists(path, false)); Iterable<ServerCnxn> connections = serverFactory.getConnections(); Assert.assertEquals("Mismatch in number of live connections!", 1, serverFactory.getNumAliveConnections()); for (ServerCnxn serverCnxn : connections) { serverCnxn.sendCloseSession(); } LOG.info("Waiting for the channel disconnected event"); channelLatch.await(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertEquals("Mismatch in number of live connections!", 0, serverFactory.getNumAliveConnections()); } finally { zk.close(); } }