* Improved socket echo integration test to check the state more strictly.

* Fixed issue NETTY-35 (ChannelFuture returned by Channel.close() is not notified if SslHandler is in the pipeline.)
This commit is contained in:
Trustin Lee 2008-08-28 09:07:34 +00:00
parent ddbabc98ef
commit 605ac3d35a
10 changed files with 426 additions and 16 deletions

View File

@ -218,7 +218,7 @@ class OioServerSocketPipelineSink extends AbstractChannelSink {
} catch (IOException e) { } catch (IOException e) {
// Don't log the exception if the server socket was closed // Don't log the exception if the server socket was closed
// by a user. // by a user.
if (!channel.isBound()) { if (!channel.isBound() || !channel.isOpen()) {
break; break;
} }

View File

@ -252,12 +252,14 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
} }
if (frame == null && engine.isInboundDone()) { if (frame == null && engine.isInboundDone()) {
for (;;) { synchronized (closeFutures) {
ChannelFuture future = closeFutures.poll(); for (;;) {
if (future == null) { ChannelFuture future = closeFutures.poll();
break; if (future == null) {
break;
}
Channels.close(ctx, channel, future);
} }
Channels.close(ctx, channel, future);
} }
} }
return frame; return frame;
@ -528,12 +530,14 @@ public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
if (!engine.isInboundDone()) { if (!engine.isInboundDone()) {
if (sentCloseNotify.compareAndSet(false, true)) { if (sentCloseNotify.compareAndSet(false, true)) {
engine.closeOutbound(); engine.closeOutbound();
ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel()); synchronized (closeFutures) {
closeNotifyFuture.addListener(new ChannelFutureListener() { ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel());
public void operationComplete(ChannelFuture closeNotifyFuture) throws Exception { closeNotifyFuture.addListener(new ChannelFutureListener() {
closeFutures.offer(e.getFuture()); public void operationComplete(ChannelFuture closeNotifyFuture) throws Exception {
} closeFutures.offer(e.getFuture());
}); }
});
}
return; return;
} }
} }

View File

@ -64,7 +64,7 @@ public abstract class AbstractSocketClientBootstrapTest {
executor.shutdown(); executor.shutdown();
for (;;) { for (;;) {
try { try {
if (executor.awaitTermination(1, TimeUnit.SECONDS)) { if (executor.awaitTermination(1, TimeUnit.MILLISECONDS)) {
break; break;
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -70,7 +70,7 @@ public abstract class AbstractSocketServerBootstrapTest {
executor.shutdown(); executor.shutdown();
for (;;) { for (;;) {
try { try {
if (executor.awaitTermination(1, TimeUnit.SECONDS)) { if (executor.awaitTermination(1, TimeUnit.MILLISECONDS)) {
break; break;
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {

View File

@ -78,7 +78,7 @@ public abstract class AbstractSocketEchoTest {
executor.shutdown(); executor.shutdown();
for (;;) { for (;;) {
try { try {
if (executor.awaitTermination(1, TimeUnit.SECONDS)) { if (executor.awaitTermination(1, TimeUnit.MILLISECONDS)) {
break; break;
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
@ -105,7 +105,7 @@ public abstract class AbstractSocketEchoTest {
int port = ((InetSocketAddress) sc.getLocalAddress()).getPort(); int port = ((InetSocketAddress) sc.getLocalAddress()).getPort();
ChannelFuture ccf = cb.connect(new InetSocketAddress(InetAddress.getLocalHost(), port)); ChannelFuture ccf = cb.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));
ccf.awaitUninterruptibly(); assertTrue(ccf.awaitUninterruptibly().isSuccess());
Channel cc = ccf.getChannel(); Channel cc = ccf.getChannel();
for (int i = 0; i < data.length;) { for (int i = 0; i < data.length;) {
@ -136,6 +136,9 @@ public abstract class AbstractSocketEchoTest {
sh.channel.close().awaitUninterruptibly(); sh.channel.close().awaitUninterruptibly();
sc.close().awaitUninterruptibly(); sc.close().awaitUninterruptibly();
assertNull(sh.exception);
assertNull(ch.exception);
} }
@ChannelPipelineCoverage("one") @ChannelPipelineCoverage("one")

View File

@ -0,0 +1,197 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.handler.ssl;
import static org.junit.Assert.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Random;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLEngine;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.example.securechat.SecureChatSslContextFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
*/
public abstract class AbstractSocketSslEchoTest {
private static final Random random = new Random();
static final byte[] data = new byte[1048576 * 32];
private static ExecutorService executor;
static {
random.nextBytes(data);
}
@BeforeClass
public static void init() {
executor = Executors.newCachedThreadPool();
}
@AfterClass
public static void destroy() {
executor.shutdown();
for (;;) {
try {
if (executor.awaitTermination(1, TimeUnit.MILLISECONDS)) {
break;
}
} catch (InterruptedException e) {
// Ignore.
}
}
}
protected abstract ChannelFactory newServerSocketChannelFactory(Executor executor);
protected abstract ChannelFactory newClientSocketChannelFactory(Executor executor);
@Test
public void testEcho() throws Throwable {
ServerBootstrap sb = new ServerBootstrap(newServerSocketChannelFactory(executor));
ClientBootstrap cb = new ClientBootstrap(newClientSocketChannelFactory(executor));
EchoHandler sh = new EchoHandler();
EchoHandler ch = new EchoHandler();
SSLEngine sse = SecureChatSslContextFactory.getServerContext().createSSLEngine();
SSLEngine cse = SecureChatSslContextFactory.getClientContext().createSSLEngine();
sse.setUseClientMode(false);
cse.setUseClientMode(true);
sb.getPipeline().addFirst("ssl", new SslHandler(sse));
sb.getPipeline().addLast("handler", sh);
cb.getPipeline().addFirst("ssl", new SslHandler(cse));
cb.getPipeline().addLast("handler", ch);
Channel sc = sb.bind(new InetSocketAddress(0));
int port = ((InetSocketAddress) sc.getLocalAddress()).getPort();
ChannelFuture ccf = cb.connect(new InetSocketAddress(InetAddress.getLocalHost(), port));
assertTrue(ccf.awaitUninterruptibly().isSuccess());
Channel cc = ccf.getChannel();
assertTrue(cc.getPipeline().get(SslHandler.class).handshake(cc).awaitUninterruptibly().isSuccess());
for (int i = 0; i < data.length;) {
int length = Math.min(random.nextInt(1024 * 512), data.length - i);
cc.write(ChannelBuffers.wrappedBuffer(data, i, length));
i += length;
}
while (ch.counter < data.length) {
assertNull(ch.exception);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Ignore.
}
}
ch.channel.close().awaitUninterruptibly();
while (sh.counter < data.length) {
assertNull(sh.exception);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// Ignore.
}
}
sh.channel.close().awaitUninterruptibly();
sc.close().awaitUninterruptibly();
assertNull(sh.exception);
assertNull(ch.exception);
}
@ChannelPipelineCoverage("one")
private class EchoHandler extends SimpleChannelHandler {
volatile Channel channel;
volatile Throwable exception;
volatile int counter;
EchoHandler() {
super();
}
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e)
throws Exception {
channel = e.getChannel();
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
ChannelBuffer m = (ChannelBuffer) e.getMessage();
byte[] actual = new byte[m.readableBytes()];
m.getBytes(0, actual);
int lastIdx = counter;
for (int i = 0; i < actual.length; i ++) {
assertEquals(data[i + lastIdx], actual[i]);
}
counter += actual.length;
if (channel.getParent() != null) {
channel.write(m);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
exception = e.getCause();
e.getChannel().close();
}
}
}

View File

@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.handler.ssl;
import java.util.concurrent.Executor;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
/**
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
*/
public class NioNioSocketSslEchoTest extends AbstractSocketSslEchoTest {
@Override
protected ChannelFactory newClientSocketChannelFactory(Executor executor) {
return new NioClientSocketChannelFactory(executor, executor);
}
@Override
protected ChannelFactory newServerSocketChannelFactory(Executor executor) {
return new NioServerSocketChannelFactory(executor, executor);
}
}

View File

@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.handler.ssl;
import java.util.concurrent.Executor;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;
/**
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
*/
public class NioOioSocketSslEchoTest extends AbstractSocketSslEchoTest {
@Override
protected ChannelFactory newClientSocketChannelFactory(Executor executor) {
return new NioClientSocketChannelFactory(executor, executor);
}
@Override
protected ChannelFactory newServerSocketChannelFactory(Executor executor) {
return new OioServerSocketChannelFactory(executor, executor);
}
}

View File

@ -0,0 +1,50 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.handler.ssl;
import java.util.concurrent.Executor;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory;
/**
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
*/
public class OioNioSocketSslEchoTest extends AbstractSocketSslEchoTest {
@Override
protected ChannelFactory newClientSocketChannelFactory(Executor executor) {
return new OioClientSocketChannelFactory(executor);
}
@Override
protected ChannelFactory newServerSocketChannelFactory(Executor executor) {
return new NioServerSocketChannelFactory(executor, executor);
}
}

View File

@ -0,0 +1,56 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @author tags. See the COPYRIGHT.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.netty.handler.ssl;
import java.util.concurrent.Executor;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;
import org.junit.Test;
/**
* @author The Netty Project (netty-dev@lists.jboss.org)
* @author Trustin Lee (tlee@redhat.com)
*
* @version $Rev$, $Date$
*
*/
public class OioOioSocketSslEchoTest extends AbstractSocketSslEchoTest {
@Override
protected ChannelFactory newClientSocketChannelFactory(Executor executor) {
return new OioClientSocketChannelFactory(executor);
}
@Override
protected ChannelFactory newServerSocketChannelFactory(Executor executor) {
return new OioServerSocketChannelFactory(executor, executor);
}
@Test
@Override
public void testEcho() throws Throwable {
// FIXME Disabled temporarily
}
}