/**
* Copyright (C) 2009-2013 Barchart, Inc. <http://www.barchart.com/>
*
* All rights reserved. Licensed under the OSI BSD License.
*
* http://www.opensource.org/licenses/bsd-license.php
*/
package com.barchart.udt.nio;
import static java.nio.channels.SelectionKey.*;
import static org.junit.Assert.*;
import static util.UnitHelp.*;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import util.TestAny;
import util.UnitHelp;
import com.barchart.udt.StatusUDT;
public class TestSelect extends TestAny {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
static final int SIZE = 20 * 1024;
@Test
public void testSelectInfinite() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final AtomicBoolean isSelected = new AtomicBoolean(false);
final Thread thread = new Thread() {
@Override
public void run() {
try {
selector.select(0);
isSelected.set(true);
} catch (final IOException e) {
fail("");
}
}
};
final long timeStart = System.currentTimeMillis();
thread.start();
final long timeDelay = 100;
thread.join(timeDelay);
final long timeFinish = System.currentTimeMillis();
final long timeDiff = timeFinish - timeStart;
assertTrue(timeDiff >= timeDelay);
assertFalse(isSelected.get());
}
@Test
public void testSelectImmediate() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final long timeStart = System.currentTimeMillis();
final int readyCount = selector.selectNow();
final long timeFinish = System.currentTimeMillis();
final long timeDiff = timeFinish - timeStart;
assertTrue(timeDiff < 3);
assertEquals(0, readyCount);
}
@Test
public void testSelectDelayed() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final long timeDelay = 100;
final long timeStart = System.currentTimeMillis();
final int readyCount = selector.select(timeDelay);
final long timeFinish = System.currentTimeMillis();
final long timeDiff = timeFinish - timeStart;
assertTrue(timeDiff >= timeDelay);
assertEquals(0, readyCount);
}
@Test(timeout = 5 * 1000)
public void testAcceptNone() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final ServerSocketChannel acceptChannel = provider
.openServerSocketChannel();
acceptChannel.configureBlocking(false);
acceptChannel.socket().bind(localSocketAddress());
final SelectionKeyUDT acceptKey = (SelectionKeyUDT) acceptChannel
.register(selector, OP_ACCEPT);
assertNotNull(acceptKey);
final int readyCount = selector.select(1000);
assertEquals(0, readyCount);
final Set<SelectionKey> readySet = selector.selectedKeys();
assertTrue(readySet.isEmpty());
logSet(readySet);
selector.close();
}
@Test(timeout = 3 * 1000)
public void testAcceptOne() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final ServerSocketChannel acceptChannel = provider
.openServerSocketChannel();
acceptChannel.configureBlocking(false);
acceptChannel.socket().bind(localSocketAddress());
final SelectionKeyUDT acceptKey = (SelectionKeyUDT) acceptChannel
.register(selector, OP_ACCEPT);
socketAwait(acceptKey.socketUDT(), StatusUDT.LISTENING);
final SocketChannel clientChannel = provider.openSocketChannel();
clientChannel.configureBlocking(false);
clientChannel.socket().bind(localSocketAddress());
final SelectionKeyUDT clientKey = (SelectionKeyUDT) clientChannel
.register(selector, OP_CONNECT);
socketAwait(clientKey.socketUDT(), StatusUDT.OPENED);
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
{
log.info("state 0 - nothing to accept");
final int readyCount = selector.select(500);
final Set<SelectionKey> readySet = selector.selectedKeys();
UnitHelp.logSet(readySet);
assertEquals(0, readySet.size());
assertEquals(0, readyCount);
readySet.clear();
}
clientChannel.connect(acceptChannel.socket().getLocalSocketAddress());
socketAwait(clientKey.socketUDT(), StatusUDT.CONNECTED);
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
{
log.info("state 1 - both accept and client have interest");
final int readyCount = selector.select();
final Set<SelectionKey> readySet = selector.selectedKeys();
logSet(readySet);
assertEquals(2, readyCount);
assertEquals(2, readySet.size());
assertTrue(readySet.contains(acceptKey));
assertTrue(readySet.contains(clientKey));
assertTrue(acceptKey.isAcceptable());
assertTrue(clientKey.isConnectable());
readySet.clear();
}
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
{
log.info("state 2 - verify same interest reported");
final int readyCount = selector.select();
final Set<SelectionKey> readySet = selector.selectedKeys();
logSet(readySet);
assertEquals(2, readySet.size());
assertEquals(2, readyCount);
assertTrue(readySet.contains(acceptKey));
assertTrue(readySet.contains(clientKey));
assertTrue(acceptKey.isAcceptable());
assertTrue(clientKey.isConnectable());
readySet.clear();
}
final SocketChannel serverChannel = acceptChannel.accept();
assertNotNull("first accept valid", serverChannel);
assertNull("second accept invalid", acceptChannel.accept());
serverChannel.configureBlocking(false);
final SelectionKeyUDT serverKey = (SelectionKeyUDT) serverChannel
.register(selector, 0);
socketAwait(serverKey.socketUDT(), StatusUDT.CONNECTED);
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
{
log.info("state 3 - post accept interest");
final int readyCount = selector.select();
final Set<SelectionKey> readySet = selector.selectedKeys();
UnitHelp.logSet(readySet);
assertEquals(1, readyCount);
assertEquals(1, readySet.size());
assertTrue(readySet.contains(clientKey));
assertTrue(acceptKey.isAcceptable()); // XXX
assertTrue(clientKey.isConnectable()); // XXX
assertFalse(clientKey.isReadable());
assertFalse(clientKey.isWritable());
readySet.clear();
}
assertFalse(serverChannel.isConnectionPending());
assertTrue(clientChannel.isConnectionPending());
assertTrue(clientChannel.finishConnect());
assertFalse(clientChannel.isConnectionPending());
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
clientKey.interestOps(OP_READ | OP_WRITE);
{
log.info("state 4 - client is connected");
final int readyCount = selector.select();
final Set<SelectionKey> readySet = selector.selectedKeys();
UnitHelp.logSet(readySet);
assertEquals(1, readyCount);
assertEquals(1, readySet.size());
assertFalse(clientKey.isReadable());
assertTrue(clientKey.isWritable());
readySet.clear();
}
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
clientKey.interestOps(0);
{
log.info("state 5 - client is connected");
final int readyCount = selector.select(500);
final Set<SelectionKey> readySet = selector.selectedKeys();
UnitHelp.logSet(readySet);
assertEquals(0, readyCount);
assertEquals(0, readySet.size());
readySet.clear();
}
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
clientKey.interestOps(OP_WRITE);
{
log.info("state 6 - client is connected");
final int readyCount = selector.select(500);
final Set<SelectionKey> readySet = selector.selectedKeys();
UnitHelp.logSet(readySet);
assertEquals(1, readyCount);
assertEquals(1, readySet.size());
assertFalse(clientKey.isReadable());
assertTrue(clientKey.isWritable());
readySet.clear();
}
log.info("acceptKey={}", acceptKey);
log.info("clientKey={}", clientKey);
serverChannel.close();
clientChannel.close();
acceptChannel.close();
selector.close();
}
@Test(timeout = 5 * 1000)
public void testSelectCycle() throws Exception {
final SelectorProviderUDT provider = SelectorProviderUDT.DATAGRAM;
final Selector selector = provider.openSelector();
final ServerSocketChannel acceptChannel = provider
.openServerSocketChannel();
acceptChannel.configureBlocking(false);
final SocketChannel clientChannel = provider.openSocketChannel();
clientChannel.configureBlocking(false);
final ServerSocket acceptSocket = acceptChannel.socket();
acceptSocket.bind(localSocketAddress());
final Socket clientSocket = clientChannel.socket();
clientSocket.bind(localSocketAddress());
final SelectionKeyUDT acceptKey = (SelectionKeyUDT) acceptChannel
.register(selector, OP_ACCEPT);
socketAwait(acceptKey.socketUDT(), StatusUDT.LISTENING);
final SelectionKeyUDT clientKey = (SelectionKeyUDT) clientChannel
.register(selector, OP_CONNECT);
clientSocket.connect(acceptSocket.getLocalSocketAddress());
socketAwait(clientKey.socketUDT(), StatusUDT.CONNECTED);
log.info("accept : {}", acceptKey);
log.info("client : {}", clientKey);
{
log.info("state 0 - accept / client setup");
final int readyCount = selector.select();
log.info("readyCount={}", readyCount);
assertEquals(2, readyCount);
final Set<SelectionKey> keySet = selector.selectedKeys();
UnitHelp.logSet(keySet);
assertEquals(2, keySet.size());
assertTrue(keySet.contains(acceptKey));
assertTrue(keySet.contains(clientKey));
assertTrue(acceptKey.isValid());
assertTrue(clientKey.isValid());
assertTrue("accept has accept", acceptKey.isAcceptable());
assertFalse("accept w/o conn", acceptKey.isConnectable());
assertFalse("accept w/o read", acceptKey.isReadable());
assertFalse("accept w/o write", acceptKey.isWritable());
assertFalse("client w/o accept", clientKey.isAcceptable());
assertTrue("client has connect", clientKey.isConnectable());
assertFalse("client w/o read", clientKey.isReadable());
assertFalse("client w/o write", clientKey.isWritable());
assertTrue(clientChannel.isConnected());
keySet.clear();
}
final SocketChannel serverChannel = acceptChannel.accept();
serverChannel.configureBlocking(false);
final SelectionKey serverKey = serverChannel.register( //
selector, OP_READ | OP_WRITE);
assertTrue("server connect", serverChannel.isConnected());
assertTrue("client connect", clientChannel.finishConnect());
clientKey.interestOps(OP_READ | OP_WRITE);
log.info("server : {}", serverKey);
log.info("client : {}", clientKey);
{
log.info("state 1 - process accept");
final int readyCount = selector.select();
log.info("readyCount={}", readyCount);
final Set<SelectionKey> keySet = selector.selectedKeys();
UnitHelp.logSet(keySet);
assertEquals(2, readyCount);
assertEquals(2, keySet.size());
assertTrue(keySet.contains(serverKey));
assertTrue(keySet.contains(clientKey));
assertTrue("server has write", serverKey.isWritable());
assertTrue("client has write", clientKey.isWritable());
keySet.clear();
}
//
final Random random = new Random(0);
final byte[] writeArray = new byte[SIZE];
random.nextBytes(writeArray);
log.info("server : {}", serverKey);
log.info("client : {}", clientKey);
{
log.info("state 2 - client write to server");
final ByteBuffer buffer = ByteBuffer.allocate(SIZE);
buffer.put(writeArray);
buffer.flip();
final int writeCount = clientChannel.write(buffer);
assertEquals(SIZE, writeCount);
Thread.sleep(1000); // let it send
final int readyCount = selector.select();
log.info("readyCount={}", readyCount);
final Set<SelectionKey> keySet = selector.selectedKeys();
UnitHelp.logSet(keySet);
assertEquals(2, readyCount);
assertEquals(2, keySet.size());
assertTrue(keySet.contains(serverKey));
assertTrue(keySet.contains(clientKey));
assertFalse("client w/o accept", clientKey.isAcceptable());
assertFalse("client w/o conn", clientKey.isConnectable());
assertFalse("client w/o read", clientKey.isReadable());
assertTrue("client has write", clientKey.isWritable());
assertFalse("server w/o accept", serverKey.isAcceptable());
assertFalse("server w/o conn", serverKey.isConnectable());
assertTrue("server has read", serverKey.isReadable());
assertTrue("server has write", serverKey.isWritable());
keySet.clear();
}
log.info("server : {}", serverKey);
log.info("client : {}", clientKey);
{
log.info("state 3 - server read from client");
final ByteBuffer buffer = ByteBuffer.allocate(SIZE);
final int readSize = serverChannel.read(buffer);
assertEquals(SIZE, readSize);
final int readyCount = selector.select();
log.info("readyCount={}", readyCount);
final Set<SelectionKey> keySet = selector.selectedKeys();
UnitHelp.logSet(keySet);
assertFalse("server w/o accept", serverKey.isAcceptable());
assertFalse("server w/o conn", serverKey.isConnectable());
assertTrue("server w/o read", serverKey.isReadable());
assertTrue("server has write", serverKey.isWritable());
keySet.clear();
}
log.info("server : {}", serverKey);
log.info("client : {}", clientKey);
serverChannel.close();
clientChannel.close();
acceptChannel.close();
assertFalse(serverChannel.isOpen());
assertFalse(clientChannel.isOpen());
assertFalse(acceptChannel.isOpen());
}
}