/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* This file contains original code and/or modifications of original code.
* Any modifications made by VoltDB L.L.C. are licensed under the following
* terms and conditions:
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Copyright (C) 2008
* Evan Jones
* Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.network;
import java.nio.channels.ReadableByteChannel;
import java.nio.ByteBuffer;
import org.voltdb.network.NIOReadStream;
import junit.framework.TestCase;
import java.io.IOException;
import org.voltdb.utils.DBBPool;
public class NIOReadStreamTest extends TestCase {
MockReadableByteChannel channel;
NIOReadStream stream;
DBBPool pool;
private static class MockReadableByteChannel implements ReadableByteChannel {
public int read(ByteBuffer buffer) {
if (nextRead == null) {
if (end) return -1;
return 0;
}
byte[] target = nextRead;
nextRead = null;
int length = target.length;
// If we have too much data, split the nextRead array
if (length > buffer.remaining()) {
length = buffer.remaining();
nextRead = new byte[target.length-length];
for (int i = 0; i < nextRead.length; ++i) {
nextRead[i] = target[i + length];
}
}
buffer.put(target, 0, length);
return length;
}
public boolean isOpen() { return !closed; }
public void close() {
assert !closed;
closed = true;
end = true;
}
public byte[] nextRead;
public boolean end = false;
private boolean closed = false;
}
@Override
public void setUp() {
channel = new MockReadableByteChannel();
stream = new NIOReadStream();
pool = new DBBPool();
}
@Override
public void tearDown() {
stream.shutdown();
pool.clear();
}
public void testZeroLength() {
assertEquals(0, stream.dataAvailable());
byte[] empty = new byte[0];
stream.getBytes(empty);
}
public void testEmpty() {
byte[] foo = new byte[1];
try {
stream.getBytes(foo);
fail("expected IllegalStateException");
} catch (IllegalStateException e) {}
}
public void testMultipleOneRead() throws IOException {
channel.nextRead = new byte[]{0, 1, 2, 3,};
assertEquals(4, stream.read(channel, 1, pool));
assertEquals(4, stream.dataAvailable());
byte[] single = new byte[1];
for (int i = 0; i < 4; ++i) {
stream.getBytes(single);
assertEquals(i, single[0]);
}
}
public void testSpanRead() throws IOException {
// Write a block that spans multiple buffers
final int SIZE = 4096*5;
channel.nextRead = new byte[SIZE];
channel.nextRead[0] = 42;
channel.nextRead[SIZE-1] = 79;
// Read a byte off the beginning
assertTrue(stream.read(channel, 1, pool) >= 1);
assertTrue(1 <= stream.dataAvailable() && stream.dataAvailable() < SIZE);
byte[] single = new byte[1];
stream.getBytes(single);
assertEquals(42, single[0]);
// Read most of the block
byte[] most = new byte[SIZE-2];
final int remainingToRead = (SIZE - 1) - stream.dataAvailable();
assertEquals(remainingToRead, stream.read(channel, most.length, pool));
assertEquals(SIZE-1, stream.dataAvailable());
stream.getBytes(most);
// Read the byte off the end
stream.getBytes(single);
assertEquals(79, single[0]);
assertStreamIsEmpty();
}
public void testMultipleReadsOneValue() throws IOException {
final int HUGE_SIZE = 4096*16;
byte[] huge = new byte[HUGE_SIZE];
channel.nextRead = huge;
assertEquals(HUGE_SIZE, stream.read(channel, HUGE_SIZE, pool));
assertEquals(HUGE_SIZE, stream.dataAvailable());
stream.getBytes(huge);
assertStreamIsEmpty();
}
public void testIncompleteReads() throws IOException {
channel.nextRead = new byte[17408];
assertEquals(NIOReadStream.BUFFER_SIZE, stream.read(channel, 1500, pool));
assertEquals(NIOReadStream.BUFFER_SIZE, stream.dataAvailable());
channel.nextRead = new byte[500];
assertEquals(500, stream.read(channel, 1500, pool));
assertEquals(8692, stream.dataAvailable());
}
public void testReadInt() throws IOException {
channel.nextRead = new byte[]{1, 2, 3, 4};
assertEquals(4, stream.read( channel, 4, pool));
int value = stream.getInt();
assertEquals(0x01020304, value);
channel.nextRead = new byte[]{-1, -1, -1, -4};
assertEquals(4, stream.read( channel, 4, pool));
assertEquals(-4, stream.getInt());
channel.nextRead = new byte[]{0, 0, 0, -4};
assertEquals(4, stream.read( channel, 4, pool));
assertEquals(252, stream.getInt());
}
public void testEndReadComplete() throws IOException {
channel.nextRead = new byte[]{1, 2, 3,4 };
channel.end = true;
assertEquals(4, stream.read(channel, 1, pool));
assertEquals(-1, stream.read(channel, 42, pool));
}
/* public void testEndReadIncomplete() throws IOException {
channel.nextRead = new byte[]{1, 2, 3,4 };
channel.end = true;
assertEquals(-1, stream.fillFrom(channel, 42));
}*/
private void assertStreamIsEmpty() throws IOException {
assertEquals(0, stream.read(channel, Integer.MAX_VALUE, pool));
assertEquals(0, stream.dataAvailable());
}
}