/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2012 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.channels;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.xnio.AssertReadWrite.assertWrittenMessage;
import java.io.Flushable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.xnio.mock.ConnectedStreamChannelMock;
/**
* Abstract class that contains test cases applicable to any blocking {@code GatheringByteChannel}, {@code Flushable}.
*
* @author <a href="mailto:flavia.rainone@jboss.com">Flavia Rainone</a>
*/
public abstract class AbstractBlockingWritableByteChannelTest<T extends GatheringByteChannel & Flushable> {
private ConnectedStreamChannelMock channelMock;
@Before
public void initChannelMock() {
channelMock = new ConnectedStreamChannelMock();
channelMock.enableRead(true);
channelMock.enableWrite(false);
}
protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock);
protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit);
protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit);
protected abstract void setWriteTimeout(T channel, long writeTimeout, TimeUnit writeTimeoutUnit);
@Test
public void simpleWrite() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
channelMock.enableWrite(true);
final ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put("write".getBytes("UTF-8")).flip();
assertEquals(5, blockingChannel.write(buffer));
assertWrittenMessage(channelMock, "write");
}
@Test
public void simpleWriteWithTimeout() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 100, TimeUnit.MILLISECONDS);
channelMock.enableWrite(true);
final ByteBuffer buffer = ByteBuffer.allocate(20);
buffer.put("write with timeout".getBytes("UTF-8")).flip();
assertEquals(18, blockingChannel.write(buffer));
assertWrittenMessage(channelMock, "write with timeout");
}
@Test
public void simpleEmptyWriteWithTimeout() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 15, TimeUnit.MILLISECONDS);
channelMock.enableWrite(true);
final ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.flip();
assertEquals(0, blockingChannel.write(buffer));
assertWrittenMessage(channelMock);
}
@Test
public void writeBlocks() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
final Write writeRunnable = new Write(blockingChannel, "message");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(30);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(7, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "message");
}
@Test
public void writeBlocksWithTimeout1() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, Long.MAX_VALUE, TimeUnit.NANOSECONDS);
final Write writeRunnable = new Write(blockingChannel, "j");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(1, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "j");
}
@Test
public void writeBlocksUntilTimeout2() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS, 0, TimeUnit.MINUTES);
final Write writeRunnable = new Write(blockingChannel, "");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(0, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "");
}
@Test
public void writeBlocksUntilTimeout3() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.NANOSECONDS, 30000000, TimeUnit.NANOSECONDS);
final Write writeRunnable = new Write(blockingChannel, "write... this");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(20);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(13, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "write... this");
}
@Test
public void writeBlocksUntilTimeout4() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 0, TimeUnit.DAYS);
final Write writeRunnable = new Write(blockingChannel, "123456");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(6, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "123456");
}
@Test
public void writeBlocksUntilTimeout5() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 2, TimeUnit.MICROSECONDS);
final Write writeRunnable = new Write(blockingChannel, "try with 1 microsecond");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(22, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "try with 1 microsecond");
}
@Test
public void writeBlocksUntilTimeout6() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 10, TimeUnit.MILLISECONDS);
final Write writeRunnable = new Write(blockingChannel, "wait just 10 milliseconds");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(25, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "wait just 10 milliseconds");
}
@Test
public void writeBlocksUntilTimeout7() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS);
final Write writeRunnable = new Write(blockingChannel, "wait nothing");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(12, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "wait nothing");
}
@Test
public void simpleWriteWithBufferArray() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
channelMock.enableWrite(true);
final ByteBuffer[] buffer = new ByteBuffer[]{null, ByteBuffer.allocate(10), ByteBuffer.allocate(0)};
buffer[1].put("write".getBytes("UTF-8")).flip();
assertEquals(5, blockingChannel.write(buffer, 1, 2));
assertWrittenMessage(channelMock, "write");
}
@Test
public void simpleEmptyWriteWithBufferArray() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
channelMock.enableWrite(true);
final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(10), ByteBuffer.allocate(0)};
buffer[0].flip();
buffer[1].flip();
assertEquals(0, blockingChannel.write(buffer, 0, 1));
assertWrittenMessage(channelMock);
}
@Test
public void simpleWriteBufferArrayWithTimeou() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 100, TimeUnit.MILLISECONDS);
channelMock.enableWrite(true);
final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(10), ByteBuffer.allocate(10), ByteBuffer.allocate(10)};
buffer[0].put("write with".getBytes("UTF-8")).flip();
buffer[1].put(" timeout".getBytes("UTF-8")).flip();
buffer[2].flip();
assertEquals(18, blockingChannel.write(buffer));
assertWrittenMessage(channelMock, "write with timeout");
}
@Test
public void simpleEmptyWriteWithBufferArrayWithTimeout() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 5, TimeUnit.MILLISECONDS);
channelMock.enableWrite(true);
final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(10), ByteBuffer.allocate(0)};
buffer[0].flip();
buffer[1].flip();
assertEquals(0, blockingChannel.write(buffer, 0, 1));
assertWrittenMessage(channelMock);
}
@Test
public void writeBufferArrayBlocks() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "mess", "age");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(30);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(7, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "message");
}
@Test
public void writeBufferArrayBlocksWithTimeout1() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 50000, TimeUnit.SECONDS);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "a");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(10);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(1, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "a");
}
@Test
public void writeBufferArrayBlocksUntilTimeout2() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS, 0, TimeUnit.MINUTES);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel);
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(0, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "");
}
@Test
public void writeBufferArrayBlocksUntilTimeout3() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.NANOSECONDS, 30, TimeUnit.MINUTES);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "write", "anything", "...", "like", "this");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(5);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(24, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "write", "anything", "...", "like", "this");
}
@Test
public void writeBuffeArrayBlocksUntilTimeout4() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 0, TimeUnit.DAYS);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "78910");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableWrite(true);
writeThread.join();
assertEquals(5, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "78910");
}
@Test
public void writeBufferArrayBlocksUntilTimeout5() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 2, TimeUnit.MICROSECONDS);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "2", "microseconds");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(13, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "2", "microseconds");
}
@Test
public void writeBufferArrayBlocksUntilTimeout6() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 10, TimeUnit.MILLISECONDS);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "10", "milliseconds");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(14, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "10", "milliseconds");
}
@Test
public void writeBufferArrayBlocksUntilTimeout7() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock, 11000000, TimeUnit.NANOSECONDS);
final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "wait almost"," nothing");
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
channelMock.enableWrite(true);
writeThread.join();
assertEquals(19, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "wait almost", " nothing");
}
// TODO wait until questions are cleared before doing this one
public void writeTimeOut() {}
@Test
public void flush() throws IOException {
channelMock.enableWrite(true);
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
assertTrue(channelMock.isFlushed());
blockingChannel.flush();
assertTrue(channelMock.isFlushed());
final ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put("5".getBytes("UTF-8")).flip();
assertEquals(1, blockingChannel.write(buffer));
assertWrittenMessage(channelMock, "5");
assertFalse(channelMock.isFlushed());
blockingChannel.flush();
assertTrue(channelMock.isFlushed());
}
@Test
public void flushWithTimeout() throws IOException {
channelMock.enableWrite(true);
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 500, TimeUnit.HOURS);
assertTrue(channelMock.isFlushed());
blockingChannel.flush();
assertTrue(channelMock.isFlushed());
final ByteBuffer buffer = ByteBuffer.allocate(5);
buffer.put("500".getBytes("UTF-8")).flip();
assertEquals(3, blockingChannel.write(buffer));
assertWrittenMessage(channelMock, "500");
assertFalse(channelMock.isFlushed());
blockingChannel.flush();
assertTrue(channelMock.isFlushed());
}
@Test
public void flushBlocks() throws Exception {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
final Write writeRunnable = new Write(blockingChannel, "test", true);
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableFlush(false);
channelMock.enableWrite(true);
Thread.sleep(50);
channelMock.enableFlush(true);
writeThread.join();
assertEquals(4, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "test");
assertTrue(channelMock.isFlushed());
}
@Test
public void flushWithTimeoutBlocks() throws Exception {
channelMock.enableFlush(false);
channelMock.enableWrite(true);
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
setWriteTimeout(blockingChannel, 1, TimeUnit.HOURS);
final Write writeRunnable = new Write(blockingChannel, "test2", true);
final Thread writeThread = new Thread(writeRunnable);
writeThread.start();
Thread.sleep(50);
channelMock.enableFlush(true);
writeThread.join();
assertEquals(5, writeRunnable.getWriteResult());
assertWrittenMessage(channelMock, "test2");
assertTrue(channelMock.isFlushed());
}
@Test
public void illegalTimeout() throws Exception {
boolean illegal = false;
try {
createBlockingWritableByteChannel(channelMock, 10, TimeUnit.MICROSECONDS, -3, TimeUnit.DAYS);
} catch (IllegalArgumentException e) {
illegal = true;
}
assertTrue(illegal);
illegal = false;
try {
createBlockingWritableByteChannel(channelMock, -8, TimeUnit.SECONDS);
} catch (IllegalArgumentException e) {
illegal = true;
}
assertTrue(illegal);
illegal = false;
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
illegal = false;
try {
setWriteTimeout(blockingChannel, -20, TimeUnit.MINUTES);
} catch (IllegalArgumentException e) {
illegal = true;
}
assertTrue(illegal);
}
@Test
public void close() throws IOException {
final T blockingChannel = createBlockingWritableByteChannel(channelMock);
assertTrue(channelMock.isOpen());
assertTrue(blockingChannel.isOpen());
blockingChannel.close();
assertFalse(channelMock.isOpen());
assertFalse(blockingChannel.isOpen());
}
private class Write implements Runnable {
private final String message;
private final T channel;
private final boolean flush;
private int writeResult;
public Write(T c, String m) {
this(c, m, false);
}
public Write(T c, String m, boolean f) {
channel = c;
message = m;
flush = f;
}
@Override
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(30);
try {
buffer.put(message.getBytes("UTF-8")).flip();
writeResult = channel.write(buffer);
if (flush) {
channel.flush();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public int getWriteResult() {
return writeResult;
}
}
private class WriteBufferArray implements Runnable {
private final String[] message;
private final T channel;
private long writeResult;
public WriteBufferArray(T c, String... m) {
channel = c;
message = m;
}
@Override
public void run() {
final ByteBuffer[] buffer = new ByteBuffer[message.length];
try {
for (int i = 0; i < buffer.length; i++) {
buffer[i] = ByteBuffer.allocate(message[i].length());
buffer[i].put(message[i].getBytes("UTF-8")).flip();
}
writeResult = channel.write(buffer);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public long getWriteResult() {
return writeResult;
}
}
}