/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.Channel; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.IoFuture; import org.xnio.LocalSocketAddress; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.MulticastMessageChannel; /** * Test for XnioWorker. * * @author <a href="mailto:frainone@redhat.com">Flavia Rainone</a> * */ @SuppressWarnings("deprecation") public class XnioWorkerTestCase { private static final int SERVER_PORT = 12345; private static SocketAddress bindAddress; private static XnioWorker worker; private static Xnio xnio; protected AcceptingChannel<? extends ConnectedStreamChannel> server; @BeforeClass public static void createWorker() throws IOException { xnio = Xnio.getInstance("nio", XnioWorkerTestCase.class.getClassLoader()); bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT); } @AfterClass public static void destroyWorker() throws InterruptedException { if (worker != null && !worker.isShutdown()) { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } } @Test public void illegalWorker() throws IOException { IllegalArgumentException expected = null; try { xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.createWorker(OptionMap.create(Options.STACK_SIZE, -10000l)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createTcpStreamServerAndConnect() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener<AcceptingChannel<StreamConnection>> acceptingChannelListener = new TestChannelListener<AcceptingChannel<StreamConnection>>();; final AcceptingChannel<? extends StreamConnection> streamServer = xnioWorker.createStreamConnectionServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { assertEquals(bindAddress, streamServer.getLocalAddress()); assertSame(xnioWorker, streamServer.getWorker()); final TestChannelListener<StreamConnection> connectionListener1 = new TestChannelListener<StreamConnection>(); final TestChannelListener<StreamConnection> connectionListener2 = new TestChannelListener<StreamConnection>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); final IoFuture<StreamConnection> connection1 = xnioWorker.openStreamConnection(bindAddress, connectionListener1, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)); final IoFuture<StreamConnection> connection2 = xnioWorker.openStreamConnection(bindAddress, connectionListener2, bindListener, OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000)); assertNotNull(connection1); assertNotNull(connection2); assertServerClientConnection(streamServer, bindListener, connection1.get(), connectionListener1, connection2.get(), connectionListener2); } finally { streamServer.close(); } } private void assertServerClientConnection(AcceptingChannel<? extends ConnectedChannel> server, TestChannelListener<BoundChannel> bindListener, ConnectedChannel clientChannel1, final TestChannelListener<? extends ConnectedChannel> clientListener1, ConnectedChannel clientChannel2, final TestChannelListener<? extends ConnectedChannel> clientListener2) throws IOException { assertNotNull(server); assertNotNull(clientChannel1); assertNotNull(clientChannel2); try { assertTrue(clientListener1.isInvoked()); assertSame(clientChannel1, clientListener1.getChannel()); assertEquals(bindAddress, clientChannel1.getPeerAddress()); assertTrue(clientListener2.isInvoked()); assertSame(clientChannel2, clientListener2.getChannel()); assertTrue(bindListener.isInvoked()); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertEquals(clientChannel2.getLocalAddress(), boundChannel.getLocalAddress()); assertEquals(clientChannel2.getLocalAddress(InetSocketAddress.class), boundChannel.getLocalAddress(InetSocketAddress.class)); assertEquals(clientChannel2.getLocalAddress(LocalSocketAddress.class), boundChannel.getLocalAddress(LocalSocketAddress.class)); assertSame(clientChannel2.getWorker(), boundChannel.getWorker()); assertEquals(clientChannel2.getOption(Options.SEND_BUFFER), boundChannel.getOption(Options.SEND_BUFFER)); clientChannel2.setOption(Options.SEND_BUFFER, 3000); assertEquals(3000, (int) boundChannel.getOption(Options.SEND_BUFFER)); assertEquals(bindAddress, clientChannel2.getPeerAddress()); assertTrue(boundChannel.supportsOption(Options.KEEP_ALIVE)); assertFalse(boundChannel.supportsOption(Options.CONNECTION_LOW_WATER)); assertNotNull(boundChannel.toString()); final TestChannelListener<BoundChannel> boundChannelCloseListener = new TestChannelListener<BoundChannel>(); boundChannel.getCloseSetter().set(boundChannelCloseListener); assertTrue(boundChannel.isOpen()); assertTrue(clientChannel2.isOpen()); assertFalse(boundChannelCloseListener.isInvokedYet()); boundChannel.close(); assertTrue(boundChannelCloseListener.isInvoked()); assertFalse(boundChannel.isOpen()); assertFalse(clientChannel2.isOpen()); } finally { clientChannel1.close(); clientChannel2.close(); } } @Test public void createTcpStreamChannelServerAndConnect() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener<AcceptingChannel<ConnectedStreamChannel>> acceptingChannelListener = new TestChannelListener<AcceptingChannel<ConnectedStreamChannel>>();; final AcceptingChannel<? extends ConnectedStreamChannel> streamServer = xnioWorker.createStreamServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { assertEquals(bindAddress, streamServer.getLocalAddress()); assertSame(xnioWorker, streamServer.getWorker()); final TestChannelListener<ConnectedStreamChannel> channelListener1 = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<ConnectedStreamChannel> channelListener2 = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); final IoFuture<ConnectedStreamChannel> connectedStreamChannel1 = xnioWorker.connectStream(bindAddress, channelListener1, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)); final IoFuture<ConnectedStreamChannel> connectedStreamChannel2 = xnioWorker.connectStream(bindAddress, channelListener2, bindListener, OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000)); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertServerClientConnection(streamServer, bindListener, connectedStreamChannel1.get(), channelListener1, connectedStreamChannel2.get(), channelListener2); } finally { streamServer.close(); } } @Test public void cancelOpenStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener<AcceptingChannel<StreamConnection>> acceptingChannelListener = new TestChannelListener<AcceptingChannel<StreamConnection>>();; final AcceptingChannel<? extends StreamConnection> streamServer = xnioWorker.createStreamConnectionServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { final TestChannelListener<StreamConnection> channelListener = new TestChannelListener<StreamConnection>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); IoFuture<StreamConnection> connectedStreamChannel = null; do { if (connectedStreamChannel != null) { connectedStreamChannel.await(); final IoFuture.Status status = connectedStreamChannel.getStatus(); if (status == IoFuture.Status.DONE) { connectedStreamChannel.get().close(); } channelListener.clear(); } connectedStreamChannel = xnioWorker.openStreamConnection(bindAddress, channelListener, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)).cancel(); connectedStreamChannel.cancel(); } while (connectedStreamChannel.getStatus() != IoFuture.Status.CANCELLED); CancellationException expected = null; try { connectedStreamChannel.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertSame(IoFuture.Status.CANCELLED, connectedStreamChannel.getStatus()); assertFalse(channelListener.isInvokedYet()); assertFalse(bindListener.isInvokedYet()); // make sure that the server is up and can accept more connections assertTrue(streamServer.isOpen()); final IoFuture<StreamConnection> anotherChannel = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); assertNotNull(anotherChannel.get()); anotherChannel.get().close(); } finally { streamServer.close(); } } @Test public void cancelConnectStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener<AcceptingChannel<ConnectedStreamChannel>> acceptingChannelListener = new TestChannelListener<AcceptingChannel<ConnectedStreamChannel>>();; final AcceptingChannel<? extends ConnectedStreamChannel> streamServer = xnioWorker.createStreamServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { final TestChannelListener<ConnectedStreamChannel> channelListener = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); IoFuture<ConnectedStreamChannel> connectedStreamChannel = null; do { if (connectedStreamChannel != null) { connectedStreamChannel.await(); final IoFuture.Status status = connectedStreamChannel.getStatus(); if (status == IoFuture.Status.DONE) { connectedStreamChannel.get().close(); } channelListener.clear(); } connectedStreamChannel = xnioWorker.connectStream(bindAddress, channelListener, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)).cancel(); connectedStreamChannel.cancel(); } while (connectedStreamChannel.getStatus() != IoFuture.Status.CANCELLED); CancellationException expected = null; try { connectedStreamChannel.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertSame(IoFuture.Status.CANCELLED, connectedStreamChannel.getStatus()); assertFalse(channelListener.isInvokedYet()); assertFalse(bindListener.isInvokedYet()); // make sure that the server is up and can accept more connections assertTrue(streamServer.isOpen()); final IoFuture<ConnectedStreamChannel> anotherChannel = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); assertNotNull(anotherChannel.get()); anotherChannel.get().close(); } finally { streamServer.close(); } } @Test public void createLocalStreamConnectionServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.createStreamConnectionServer(new LocalSocketAddress("server"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void createLocalStreamServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.createStreamServer(new LocalSocketAddress("server"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void openLocalStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.openStreamConnection(new LocalSocketAddress("server for test"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void connectLocalStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.connectStream(new LocalSocketAddress("server for test"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void acceptStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress bindAddress2 = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 23456); final TestChannelListener<StreamConnection> channelListener1 = new TestChannelListener<StreamConnection>(); final TestChannelListener<StreamConnection> channelListener2 = new TestChannelListener<StreamConnection>(); final TestChannelListener<BoundChannel> bindListener1 = new TestChannelListener<BoundChannel>(); final TestChannelListener<BoundChannel> bindListener2 = new TestChannelListener<BoundChannel>(); final OptionMap optionMap = OptionMap.create(Options.READ_TIMEOUT, 800000); final IoFuture<StreamConnection> channelFuture1 = xnioWorker.acceptStreamConnection(bindAddress, channelListener1, bindListener1, optionMap); final IoFuture<StreamConnection> channelFuture2 = xnioWorker.acceptStreamConnection(bindAddress2, channelListener2, bindListener2, optionMap); final IoFuture<StreamConnection> connectedStreamChannel1 = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); final IoFuture<StreamConnection> connectedStreamChannel2 = xnioWorker.openStreamConnection(bindAddress2, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertNotNull(channelFuture1); assertNotNull(channelFuture2); final StreamConnection channel1 = channelFuture1.get(); final StreamConnection channel2 = channelFuture2.get(); assertNotNull(channel1); assertNotNull(channel2); assertAcceptedChannels(xnioWorker, channel1, channelListener1, bindListener1, bindAddress, connectedStreamChannel1.get().getLocalAddress(), channel2, channelListener2, bindListener2, bindAddress2, connectedStreamChannel2.get().getLocalAddress()); } private void assertAcceptedChannels(XnioWorker worker, ConnectedChannel channel1, TestChannelListener<? extends ConnectedChannel> channelListener1, TestChannelListener<BoundChannel> bindListener1, SocketAddress bindAddress1, SocketAddress peerAddress1, ConnectedChannel channel2, TestChannelListener<? extends ConnectedChannel> channelListener2, TestChannelListener<BoundChannel> bindListener2, SocketAddress bindAddress2, SocketAddress peerAddress2) throws IOException { try { assertTrue(channelListener1.isInvoked()); assertSame(channel1, channelListener1.getChannel()); assertTrue(bindListener1.isInvoked()); assertEquals(peerAddress1, channel1.getPeerAddress()); final BoundChannel boundChannel1 = bindListener1.getChannel(); assertNotNull(boundChannel1); assertSame(worker, boundChannel1.getWorker()); assertEquals(bindAddress, boundChannel1.getLocalAddress()); assertNull(boundChannel1.getLocalAddress(LocalSocketAddress.class)); assertNotNull(boundChannel1.getCloseSetter()); assertFalse(boundChannel1.isOpen()); // expected assertFalse(boundChannel1.supportsOption(Options.KEEP_ALIVE)); assertNull(boundChannel1.getOption(Options.KEEP_ALIVE)); assertNull(boundChannel1.setOption(Options.KEEP_ALIVE, null)); assertNull(boundChannel1.getOption(Options.KEEP_ALIVE)); assertNotNull(boundChannel1.toString()); assertTrue(channelListener2.isInvoked()); assertSame(channel2, channelListener2.getChannel()); assertTrue(bindListener2.isInvoked()); assertEquals(peerAddress2, channel2.getPeerAddress()); final BoundChannel boundChannel2 = bindListener2.getChannel(); assertNotNull(boundChannel2); assertSame(worker, boundChannel2.getWorker()); assertEquals(bindAddress2, boundChannel2.getLocalAddress()); assertNull(boundChannel2.getLocalAddress(LocalSocketAddress.class)); assertNotNull(boundChannel2.getCloseSetter()); assertFalse(boundChannel2.isOpen()); // expected assertFalse(boundChannel2.supportsOption(Options.KEEP_ALIVE)); assertNull(boundChannel2.getOption(Options.KEEP_ALIVE)); assertNull(boundChannel2.setOption(Options.KEEP_ALIVE, null)); assertNull(boundChannel2.getOption(Options.KEEP_ALIVE)); assertNotNull(boundChannel2.toString()); } finally { channel1.close(); channel2.close(); } } @Test public void acceptTcpStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress bindAddress2 = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 23456); final TestChannelListener<ConnectedStreamChannel> channelListener1 = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<ConnectedStreamChannel> channelListener2 = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<BoundChannel> bindListener1 = new TestChannelListener<BoundChannel>(); final TestChannelListener<BoundChannel> bindListener2 = new TestChannelListener<BoundChannel>(); final OptionMap optionMap = OptionMap.create(Options.READ_TIMEOUT, 800000); final IoFuture<ConnectedStreamChannel> channelFuture1 = xnioWorker.acceptStream(bindAddress, channelListener1, bindListener1, optionMap); final IoFuture<ConnectedStreamChannel> channelFuture2 = xnioWorker.acceptStream(bindAddress2, channelListener2, bindListener2, optionMap); final IoFuture<ConnectedStreamChannel> connectedStreamChannel1 = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); final IoFuture<ConnectedStreamChannel> connectedStreamChannel2 = xnioWorker.connectStream(bindAddress2, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertNotNull(channelFuture1); assertNotNull(channelFuture2); final ConnectedStreamChannel channel1 = channelFuture1.get(); final ConnectedStreamChannel channel2 = channelFuture2.get(); assertNotNull(channel1); assertNotNull(channel2); assertAcceptedChannels(xnioWorker, channel1, channelListener1, bindListener1, bindAddress, connectedStreamChannel1.get().getLocalAddress(), channel2, channelListener2, bindListener2, bindAddress2, connectedStreamChannel2.get().getLocalAddress()); } @Test public void cancelAcceptStreamConnection() throws CancellationException, IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final TestChannelListener<StreamConnection> channelListener = new TestChannelListener<StreamConnection>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); final IoFuture<StreamConnection> connectionFuture1 = xnioWorker.acceptStreamConnection(bindAddress, channelListener, bindListener, OptionMap.EMPTY); final IoFuture<StreamConnection> connection2 = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); assertNotNull(connectionFuture1); assertNotNull(connection2); connectionFuture1.cancel(); CancellationException expected = null; try { connectionFuture1.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertFalse(channelListener.isInvokedYet()); assertFalse(channelListener.isInvokedYet()); if (bindListener.isInvokedYet()) { BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertFalse(boundChannel.isOpen()); } } @Test public void cancelAcceptTcpStream() throws CancellationException, IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final TestChannelListener<ConnectedStreamChannel> channelListener = new TestChannelListener<ConnectedStreamChannel>(); final TestChannelListener<BoundChannel> bindListener = new TestChannelListener<BoundChannel>(); final IoFuture<ConnectedStreamChannel> channelFuture = xnioWorker.acceptStream(bindAddress, channelListener, bindListener, OptionMap.EMPTY); final IoFuture<ConnectedStreamChannel> connectedStreamChannel = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel); assertNotNull(channelFuture); channelFuture.cancel(); CancellationException expected = null; try { channelFuture.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertFalse(channelListener.isInvokedYet()); if (bindListener.isInvokedYet()) { BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertFalse(boundChannel.isOpen()); } } @Test public void acceptLocalStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.acceptStream(new LocalSocketAddress("local address"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.acceptStreamConnection(new LocalSocketAddress("local address"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void connectTcpDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.connectDatagram(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void connectLocalDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.connectDatagram(new LocalSocketAddress("local"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void acceptDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.acceptDatagram(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void acceptMessageConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.acceptMessageConnection(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createUdpServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress address = new InetSocketAddress(0); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, false); final MulticastMessageChannel channel = xnioWorker.createUdpServer(address, optionMap); assertNotNull(channel); try { // check address assertNotNull(channel.getLocalAddress()); } finally { channel.close(); } } @Test public void createUdpServerWithListener() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress address = new InetSocketAddress(0); final TestChannelListener<MulticastMessageChannel> listener = new TestChannelListener<MulticastMessageChannel>(); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, true); final MulticastMessageChannel channel = xnioWorker.createUdpServer(address, listener, optionMap); assertNotNull(channel); try { // check address assertNotNull(channel.getLocalAddress()); // check listener assertTrue(listener.isInvoked()); assertSame(channel, listener.getChannel()); } finally { channel.close(); } } @Test public void createFullDuplexPipe() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); assertNotNull(xnioWorker.createFullDuplexPipe()); assertNotNull(xnioWorker.createHalfDuplexPipe()); } @Test public void shutdownNowWithTerminationTask() throws IOException, InterruptedException { final TerminationTask terminationTask = new TerminationTask(); final XnioWorker xnioWorker = xnio.createWorker(Thread.currentThread().getThreadGroup(), OptionMap.EMPTY, terminationTask); assertFalse(xnioWorker.isShutdown()); assertFalse(xnioWorker.isTerminated()); xnioWorker.shutdownNow(); assertTrue(xnioWorker.isShutdown()); if (!xnioWorker.isTerminated()) { xnioWorker.awaitTermination(); } assertTrue(terminationTask.isInvoked()); assertTrue(xnioWorker.isShutdown()); assertTrue(xnioWorker.isTerminated()); xnioWorker.awaitTermination(); // idempotent xnioWorker.shutdown(); xnioWorker.shutdownNow(); } @Test public void awaitTerminationWithMultipleAwaiters1() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker, 10, TimeUnit.MILLISECONDS); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); thread1.start(); thread2.start(); thread3.start(); thread1.join(20); thread2.join(20); thread3.join(); assertFalse(awaiter3.isInterrupted()); assertTrue(thread1.isAlive()); assertTrue(thread2.isAlive()); worker.shutdown(); thread1.join(); thread2.join(); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter2.isInterrupted()); } @Test public void awaitTerminationWithMultipleAwaiters2() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker, 300, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter4 = new TerminationAwaiter(worker, 10, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter5 = new TerminationAwaiter(worker, 100, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter6 = new TerminationAwaiter(worker, 10, TimeUnit.MINUTES); final TerminationAwaiter awaiter7 = new TerminationAwaiter(worker, 1, TimeUnit.MILLISECONDS); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); final Thread thread4 = new Thread(awaiter4); final Thread thread5 = new Thread(awaiter5); final Thread thread6 = new Thread(awaiter6); final Thread thread7 = new Thread(awaiter7); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread6.start(); thread7.start(); thread1.join(20); thread2.join(20); thread4.join(); thread5.join(); thread3.join(); thread6.join(20); thread7.join(); assertFalse(awaiter3.isInterrupted()); assertFalse(awaiter4.isInterrupted()); assertFalse(awaiter5.isInterrupted()); assertFalse(awaiter7.isInterrupted()); assertTrue(thread1.isAlive()); assertTrue(thread2.isAlive()); assertTrue(thread6.isAlive()); worker.shutdown(); thread1.join(); thread2.join(); thread6.join(); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter2.isInterrupted()); assertFalse(awaiter6.isInterrupted()); } @Test public void awaitTerminationWithMultipleAwaiters3() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker, 1, TimeUnit.NANOSECONDS); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter4 = new TerminationAwaiter(worker, 3, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter5 = new TerminationAwaiter(worker); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); final Thread thread4 = new Thread(awaiter4); final Thread thread5 = new Thread(awaiter5); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread1.join(); thread2.join(20); thread3.join(20); thread4.join(); thread5.join(20); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter4.isInterrupted()); assertTrue(thread2.isAlive()); assertTrue(thread3.isAlive()); assertTrue(thread5.isAlive()); worker.shutdown(); thread2.join(); thread3.join(); thread5.join(); assertFalse(awaiter2.isInterrupted()); assertFalse(awaiter3.isInterrupted()); assertFalse(awaiter5.isInterrupted()); } @Test public void interruptedAwaiters() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 3, TimeUnit.MINUTES); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); thread1.start(); thread2.start(); thread1.interrupt(); thread2.interrupt(); thread1.join(); thread2.join(); assertTrue(awaiter1.isInterrupted()); assertTrue(awaiter2.isInterrupted()); worker.shutdown(); } @Test public void invalidAcceptStream() throws IOException { final XnioWorker worker = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0, Options.WORKER_WRITE_THREADS, 0)); assertNotNull(worker); IllegalArgumentException expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private static class TestChannelListener<C extends Channel> implements ChannelListener<C> { private boolean invoked = false; private C channel = null; private CountDownLatch latch = new CountDownLatch(1); @Override public void handleEvent(C c) { invoked = true; channel = c; latch.countDown(); } public boolean isInvoked() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } return invoked; } public boolean isInvokedYet() { return invoked; } public C getChannel() { return channel; } public void clear() { invoked = false; } } private static class TerminationTask implements Runnable { private boolean invoked = false; private final CountDownLatch countDown = new CountDownLatch(1); @Override public void run() { invoked = true; countDown.countDown(); } public boolean isInvoked() { try { countDown.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } return invoked; } } private static class TerminationAwaiter implements Runnable { private final XnioWorker xnioWorker; private final long timeout; private final TimeUnit timeoutUnit; private boolean interrupted; public TerminationAwaiter (XnioWorker w, long t, TimeUnit tu) { xnioWorker = w;; timeout = t; timeoutUnit = tu; } public TerminationAwaiter(XnioWorker w) { this(w, -1, null); } public void run() { try { if (timeoutUnit == null) { xnioWorker.awaitTermination(); } else { xnioWorker.awaitTermination(timeout, timeoutUnit); } } catch (InterruptedException e) { interrupted = true; } } public boolean isInterrupted() { return interrupted; } } }