/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Ignore; import org.junit.Test; import org.xnio.Buffers; import org.xnio.OptionMap; import org.xnio.XnioWorker; import org.xnio.channels.StreamChannel; /** * Tests a pair of connected stream channels. * * @author <a href="mailto:frainone@redhat.com">Flavia Rainone</a> */ public abstract class AbstractNioStreamChannelTest extends AbstractStreamSinkSourceChannelTest <StreamChannel, StreamChannel> { private StreamChannel channel1 = null; private StreamChannel channel2 = null; @Override protected void initChannels(XnioWorker worker, OptionMap optionMap) throws IOException { super.initChannels(worker, optionMap); // for a matter of code readability, it is better to name those channels sink/source in the super class // and create new fields in this subclass so we can use a more appropriate name here channel1 = super.sinkChannel; channel2 = super.sourceChannel; } @Test public void readWrite() throws IOException{ initChannels(); final ByteBuffer writeBuffer = ByteBuffer.allocate(15); final ByteBuffer readBuffer = ByteBuffer.allocate(15); writeBuffer.put("read and write".getBytes()).flip(); assertEquals(0, channel1.read(readBuffer)); assertEquals(14, channel1.write(writeBuffer)); assertEquals(14, channel2.read(readBuffer)); assertEquals(0, channel2.write(writeBuffer)); assertEquals(0, channel2.read(readBuffer)); readBuffer.flip(); assertEquals("read and write", Buffers.getModifiedUtf8(readBuffer)); channel1.close(); assertEquals(-1, channel1.read(readBuffer)); writeBuffer.flip(); ClosedChannelException expected = null; try { channel1.write(writeBuffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void readWriteMultipleBuffers() throws IOException{ initChannels(); final ByteBuffer[] writeBuffers = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(9), ByteBuffer.allocate(13), Buffers.EMPTY_BYTE_BUFFER}; final ByteBuffer[] readBuffers = new ByteBuffer[] {ByteBuffer.allocate(1), ByteBuffer.allocate(5), ByteBuffer.allocate(10), ByteBuffer.allocate(15), ByteBuffer.allocate(20)}; writeBuffers[0].put("> 1".getBytes()).flip(); writeBuffers[1].put("multiple".getBytes()).flip(); writeBuffers[2].put("more than one".getBytes()).flip(); assertEquals(0, channel1.read(readBuffers)); assertEquals(0, channel1.write(writeBuffers, 3, 1)); assertEquals(13, channel1.write(writeBuffers, 2, 2)); assertEquals(0, channel1.write(writeBuffers, 2, 2)); assertEquals(1, channel2.read(readBuffers, 0, 1)); assertEquals('m', readBuffers[0].get(0)); assertEquals(12, channel2.read(readBuffers)); assertEquals(0, channel2.read(readBuffers, 1, 2)); assertEquals(11, channel2.write(writeBuffers)); assertEquals(11, channel1.read(readBuffers, 3, 2)); readBuffers[1].flip(); readBuffers[2].flip(); readBuffers[3].flip(); readBuffers[4].flip(); assertEquals("ore t", Buffers.getModifiedUtf8(readBuffers[1])); assertEquals("han one", Buffers.getModifiedUtf8(readBuffers[2])); assertEquals("> 1multiple", Buffers.getModifiedUtf8(readBuffers[3])); assertEquals(0, readBuffers[4].remaining()); channel1.close(); assertEquals(-1, channel1.read(readBuffers)); writeBuffers[0].flip(); ClosedChannelException expected = null; try { channel1.write(writeBuffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test @Ignore("Does not follow thread model") public void suspendResumeReadsAndWrites() throws IOException, InterruptedException { initChannels(); assertFalse(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); final TestChannelListener<StreamChannel> readListener = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> writeListener = new TestChannelListener<StreamChannel>(); channel1.getReadSetter().set(readListener); assertFalse(readListener.isInvokedYet()); channel1.getWriteSetter().set(writeListener); assertFalse(writeListener.isInvokedYet()); channel1.awaitWritable(); channel1.resumeReads(); int count = 0; while(!channel1.isReadResumed()) { Thread.sleep(50); if (++ count == 10) { fail("Read is not resumed"); } } assertTrue(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); channel1.resumeWrites(); count = 0; assertTrue(writeListener.isInvoked()); assertTrue(channel1.isWriteResumed()); writeListener.clear(); assertTrue(channel1.isReadResumed()); channel1.suspendReads(); assertFalse(channel1.isReadResumed()); assertTrue(channel1.isWriteResumed()); channel1.suspendWrites(); assertFalse(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); channel1.wakeupWrites(); assertTrue(writeListener.isInvoked()); assertFalse(readListener.isInvokedYet()); assertSame(channel1, writeListener.getChannel()); channel1.wakeupReads(); assertTrue(readListener.isInvoked()); assertSame(channel1, readListener.getChannel()); channel1.shutdownReads(); channel1.shutdownWrites(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } assertFalse(channel1.isOpen()); // idempotent operations channel1.shutdownReads(); channel1.shutdownWrites(); assertFalse(channel1.isOpen()); } @SuppressWarnings("deprecation") @Test public void awaitReadableAndWritable() throws IOException, InterruptedException { initChannels(); final TestChannelListener<StreamChannel> readListener1 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> writeListener1 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> readListener2 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> writeListener2 = new TestChannelListener<StreamChannel>(); channel1.getReadSetter().set(readListener1); channel1.getWriteSetter().set(writeListener1); channel2.getReadSetter().set(readListener2); channel2.getWriteSetter().set(writeListener2); channel1.awaitWritable(); channel1.awaitWritable(1, TimeUnit.HOURS); channel2.awaitWritable(); channel2.awaitWritable(1, TimeUnit.HOURS); final ReadableAwaiter<StreamChannel> readableAwaiter1 = new ReadableAwaiter<StreamChannel>(channel1); final ReadableAwaiter<StreamChannel> readableAwaiter2 = new ReadableAwaiter<StreamChannel>(channel1, 10, TimeUnit.MICROSECONDS); final ReadableAwaiter<StreamChannel> readableAwaiter3 = new ReadableAwaiter<StreamChannel>(channel1, 10, TimeUnit.MINUTES); final WritableAwaiter<StreamChannel> writableAwaiter1 = new WritableAwaiter<StreamChannel>(channel1); final WritableAwaiter<StreamChannel> writableAwaiter2 = new WritableAwaiter<StreamChannel>(channel1, 5, TimeUnit.NANOSECONDS); final WritableAwaiter<StreamChannel> writableAwaiter3 = new WritableAwaiter<StreamChannel>(channel1, 2222222, TimeUnit.SECONDS); final Thread readableAwaiterThread1 = new Thread(readableAwaiter1); final Thread readableAwaiterThread2 = new Thread(readableAwaiter2); final Thread readableAwaiterThread3 = new Thread(readableAwaiter3); final Thread writableAwaiterThread1 = new Thread(writableAwaiter1); final Thread writableAwaiterThread2 = new Thread(writableAwaiter2); final Thread writableAwaiterThread3 = new Thread(writableAwaiter3); readableAwaiterThread1.start(); readableAwaiterThread2.start(); readableAwaiterThread3.start(); readableAwaiterThread1.join(50); readableAwaiterThread2.join(); readableAwaiterThread3.join(50); assertTrue(readableAwaiterThread1.isAlive()); assertTrue(readableAwaiterThread3.isAlive()); channel1.shutdownWrites(); writableAwaiterThread1.start(); writableAwaiterThread2.start(); writableAwaiterThread3.start(); writableAwaiterThread1.join(); writableAwaiterThread2.join(); writableAwaiterThread3.join(); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes()).flip(); assertEquals(5, channel2.write(buffer)); readableAwaiterThread1.join(); readableAwaiterThread3.join(); channel1.resumeWrites(); writableAwaiterThread1.join(); writableAwaiterThread3.join(); assertNotNull(channel1.getWriteThread()); assertNotNull(channel1.getIoThread()); assertNotNull(channel2.getWriteThread()); assertNotNull(channel2.getIoThread()); } @Test public void awaitWritable() throws IOException, InterruptedException { initChannels(); final TestChannelListener<StreamChannel> readListener1 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> writeListener1 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> readListener2 = new TestChannelListener<StreamChannel>(); final TestChannelListener<StreamChannel> writeListener2 = new TestChannelListener<StreamChannel>(); channel1.getReadSetter().set(readListener1); channel1.getWriteSetter().set(writeListener1); channel2.getReadSetter().set(readListener2); channel2.getWriteSetter().set(writeListener2); channel1.shutdownWrites(); do { channel1.awaitWritable(); } while (! channel1.flush()); } }