/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.util.io;
import org.junit.Assert;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* Tests the {@link BufferUtils} class.
*/
public class BufferUtilsTest {
/**
* Tests the {@link BufferUtils#cloneByteBuffer(ByteBuffer)} method.
*/
@Test
public void cloneByteBuffer() {
final int bufferSize = 10;
ByteBuffer buf = ByteBuffer.allocate(bufferSize);
for (byte i = 0; i < bufferSize; i++) {
buf.put(i);
}
ByteBuffer bufClone = BufferUtils.cloneByteBuffer(buf);
Assert.assertEquals(buf, bufClone);
}
/**
* Tests the {@link BufferUtils#cloneByteBufferList(List)} method.
*/
@Test
public void cloneByteBufferList() {
final int bufferSize = 10;
final int listLength = 10;
ArrayList<ByteBuffer> bufList = new ArrayList<>(listLength);
for (int k = 0; k < listLength; k++) {
ByteBuffer buf = ByteBuffer.allocate(bufferSize);
for (byte i = 0; i < bufferSize; i++) {
buf.put((byte) (i + k));
}
bufList.add(buf);
}
List<ByteBuffer> bufListClone = BufferUtils.cloneByteBufferList(bufList);
Assert.assertEquals(listLength, bufListClone.size());
for (int k = 0; k < listLength; k++) {
Assert.assertEquals(bufList.get(k), bufListClone.get(k));
}
}
/**
* Tests the {@link BufferUtils#cloneByteBuffer(ByteBuffer)} method after allocating a buffer via
* {@link ByteBuffer#allocateDirect(int)} method.
*/
@Test
public void cloneDirectByteBuffer() {
final int bufferSize = 10;
ByteBuffer bufDirect = ByteBuffer.allocateDirect(bufferSize);
for (byte i = 0; i < bufferSize; i++) {
bufDirect.put(i);
}
ByteBuffer bufClone = BufferUtils.cloneByteBuffer(bufDirect);
Assert.assertEquals(bufDirect, bufClone);
}
/**
* Tests the {@link BufferUtils#cloneByteBufferList(List)} method after allocating a buffer via
* {@link ByteBuffer#allocateDirect(int)} method.
*/
@Test
public void cloneDirectByteBufferList() {
final int bufferSize = 10;
final int listLength = 10;
ArrayList<ByteBuffer> bufDirectList = new ArrayList<>(listLength);
for (int k = 0; k < listLength; k++) {
ByteBuffer bufDirect = ByteBuffer.allocateDirect(bufferSize);
for (byte i = 0; i < bufferSize; i++) {
bufDirect.put((byte) (i + k));
}
bufDirectList.add(bufDirect);
}
List<ByteBuffer> bufListClone = BufferUtils.cloneByteBufferList(bufDirectList);
Assert.assertEquals(listLength, bufListClone.size());
for (int k = 0; k < listLength; k++) {
Assert.assertEquals(bufDirectList.get(k), bufListClone.get(k));
}
}
/**
* Tests the {@link BufferUtils#generateNewByteBufferFromThriftRPCResults(ByteBuffer)} method.
*/
@Test
public void generateNewByteBufferFromThriftRPCResults() {
final int bufferSize = 10;
ByteBuffer mockRPCbuf = ByteBuffer.allocate(bufferSize);
for (byte i = 0; i < bufferSize; i++) {
mockRPCbuf.put(i);
}
mockRPCbuf.position(bufferSize / 2);
ByteBuffer buf = BufferUtils.generateNewByteBufferFromThriftRPCResults(mockRPCbuf);
Assert.assertEquals(0, buf.position());
Assert.assertEquals(bufferSize / 2, buf.capacity());
for (int i = 0; i < bufferSize / 2; i++) {
Assert.assertEquals(mockRPCbuf.get(i + bufferSize / 2), buf.get(i));
}
}
/**
* Tests the {@link BufferUtils#putIntByteBuffer(ByteBuffer, int)} method.
*/
@Test
public void putIntByteBuffer() {
class TestCase {
byte mExpected;
int mInput;
public TestCase(byte expected, int input) {
mExpected = expected;
mInput = input;
}
}
LinkedList<TestCase> testCases = new LinkedList<>();
testCases.add(new TestCase((byte) 0x00, 0x00));
testCases.add(new TestCase((byte) 0x12, 0x12));
testCases.add(new TestCase((byte) 0x34, 0x1234));
testCases.add(new TestCase((byte) 0x56, 0x123456));
testCases.add(new TestCase((byte) 0x78, 0x12345678));
for (TestCase testCase : testCases) {
ByteBuffer buf = ByteBuffer.allocate(1);
BufferUtils.putIntByteBuffer(buf, testCase.mInput);
Assert.assertEquals(testCase.mExpected, buf.get(0));
}
}
/**
* Tests the {@link BufferUtils#getIncreasingByteArray(int, int)} method.
*/
@Test
public void getIncreasingByteArray() {
class TestCase {
byte[] mExpected;
int mLength;
int mStart;
public TestCase(byte[] expected, int length, int start) {
mExpected = expected;
mLength = length;
mStart = start;
}
}
LinkedList<TestCase> testCases = new LinkedList<>();
testCases.add(new TestCase(new byte[] {}, 0, 0));
testCases.add(new TestCase(new byte[] {}, 0, 3));
testCases.add(new TestCase(new byte[] {0}, 1, 0));
testCases.add(new TestCase(new byte[] {0, 1, 2}, 3, 0));
testCases.add(new TestCase(new byte[] {3}, 1, 3));
testCases.add(new TestCase(new byte[] {3, 4, 5}, 3, 3));
for (TestCase testCase : testCases) {
byte[] result = BufferUtils.getIncreasingByteArray(testCase.mStart, testCase.mLength);
Assert.assertEquals(testCase.mExpected.length, result.length);
for (int k = 0; k < result.length; k++) {
Assert.assertEquals(testCase.mExpected[k], result[k]);
}
}
}
/**
* Tests the {@link BufferUtils#equalIncreasingByteArray(int, int, byte[])} method.
*/
@Test
public void equalIncreasingByteArray() {
class TestCase {
boolean mExpected;
byte[] mArray;
int mLength;
int mStart;
public TestCase(boolean expected, byte[] array, int length, int start) {
mExpected = expected;
mArray = array;
mLength = length;
mStart = start;
}
}
LinkedList<TestCase> testCases = new LinkedList<>();
testCases.add(new TestCase(false, null, 0, 0));
testCases.add(new TestCase(true, new byte[] {}, 0, 0));
testCases.add(new TestCase(false, new byte[] {1}, 0, 0));
testCases.add(new TestCase(true, new byte[] {}, 0, 3));
testCases.add(new TestCase(false, new byte[] {1}, 0, 3));
testCases.add(new TestCase(true, new byte[] {0}, 1, 0));
testCases.add(new TestCase(false, new byte[] {1}, 1, 0));
testCases.add(new TestCase(true, new byte[] {0, 1, 2}, 3, 0));
testCases.add(new TestCase(false, new byte[] {0, 1, 2, (byte) 0xFF}, 3, 0));
testCases.add(new TestCase(false, new byte[] {1, 2, 3}, 3, 0));
testCases.add(new TestCase(true, new byte[] {3}, 1, 3));
testCases.add(new TestCase(false, new byte[] {2}, 1, 3));
testCases.add(new TestCase(true, new byte[] {3, 4, 5}, 3, 3));
testCases.add(new TestCase(false, new byte[] {3, 4, 5, (byte) 0xFF}, 3, 3));
testCases.add(new TestCase(false, new byte[] {2, 3, 4}, 3, 3));
for (TestCase testCase : testCases) {
boolean result = BufferUtils.equalIncreasingByteArray(testCase.mStart, testCase.mLength,
testCase.mArray);
Assert.assertEquals(testCase.mExpected, result);
}
}
/**
* Tests the {@link BufferUtils#getIncreasingByteBuffer(int, int)} method.
*/
@Test
public void getIncreasingByteBuffer() {
class TestCase {
ByteBuffer mExpected;
int mLength;
int mStart;
public TestCase(ByteBuffer expected, int length, int start) {
mExpected = expected;
mLength = length;
mStart = start;
}
}
LinkedList<TestCase> testCases = new LinkedList<>();
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {}), 0, 0));
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {}), 0, 3));
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {0}), 1, 0));
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {0, 1, 2}), 3, 0));
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {3}), 1, 3));
testCases.add(new TestCase(ByteBuffer.wrap(new byte[] {3, 4, 5}), 3, 3));
for (TestCase testCase : testCases) {
ByteBuffer result = BufferUtils.getIncreasingByteBuffer(testCase.mStart, testCase.mLength);
Assert.assertEquals(testCase.mExpected.capacity(), result.capacity());
for (int k = 0; k < result.capacity(); k++) {
Assert.assertEquals(testCase.mExpected.get(k), result.get(k));
}
}
}
/**
* Tests the {@link BufferUtils#equalIncreasingByteBuffer(int, int, ByteBuffer)} method.
*/
@Test
public void equalIncreasingByteBuffer() {
class TestCase {
boolean mExpected;
ByteBuffer mBuffer;
int mLength;
int mStart;
public TestCase(boolean expected, ByteBuffer buffer, int length, int start) {
mExpected = expected;
mBuffer = buffer;
mLength = length;
mStart = start;
}
}
LinkedList<TestCase> testCases = new LinkedList<>();
testCases.add(new TestCase(false, null, 0, 0));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {}), 0, 0));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {1}), 0, 0));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {}), 0, 3));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {1}), 0, 3));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {0}), 1, 0));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {1}), 1, 0));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {0, 1, 2}), 3, 0));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {0, 1, 2, (byte) 0xFF}), 3, 0));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {1, 2, 3}), 3, 0));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {3}), 1, 3));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {2}), 1, 3));
testCases.add(new TestCase(true, ByteBuffer.wrap(new byte[] {3, 4, 5}), 3, 3));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {3, 4, 5, (byte) 0xFF}), 3, 3));
testCases.add(new TestCase(false, ByteBuffer.wrap(new byte[] {2, 3, 4}), 3, 3));
for (TestCase testCase : testCases) {
boolean result = BufferUtils.equalIncreasingByteBuffer(testCase.mStart, testCase.mLength,
testCase.mBuffer);
Assert.assertEquals(testCase.mExpected, result);
}
}
/**
* {@link BufferUtils#cleanDirectBuffer(ByteBuffer)} forces to unmap an unused direct buffer.
* This test repeated allocates and de-allocates a direct buffer of size 16MB to make sure
* cleanDirectBuffer is doing its job. The bufferArray is used to store references to the direct
* buffers so that they won't get garbage collected automatically. It has been tested that if the
* call to cleanDirectBuffer is removed, this test will fail.
*/
@Test
public void cleanDirectBuffer() {
final int MAX_ITERATIONS = 1024;
final int BUFFER_SIZE = 16 * 1024 * 1024;
// bufferArray keeps reference to each buffer to avoid auto GC
ByteBuffer[] bufferArray = new ByteBuffer[MAX_ITERATIONS];
try {
for (int i = 0; i < MAX_ITERATIONS; i++) {
ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);
bufferArray[i] = buf;
BufferUtils.cleanDirectBuffer(buf);
}
} catch (OutOfMemoryError ooe) {
Assert.fail("cleanDirectBuffer is causing memory leak." + ooe.getMessage());
}
}
/**
* Tests the {@link BufferUtils#sliceByteBuffer(ByteBuffer, int, int)} and the
* {@link BufferUtils#sliceByteBuffer(ByteBuffer, int)} methods.
*/
@Test
public void sliceByteBuffer() {
final int size = 100;
final ByteBuffer buf = BufferUtils.getIncreasingByteBuffer(size);
for (int slicePosition : new int[] {0, 1, size / 2, size - 1}) {
// Slice a ByteBuffer of length 1
ByteBuffer slicedBuffer = BufferUtils.sliceByteBuffer(buf, slicePosition, 1);
Assert.assertEquals(0, slicedBuffer.position());
Assert.assertEquals(1, slicedBuffer.limit());
Assert.assertTrue(BufferUtils.equalIncreasingByteBuffer(slicePosition, 1, slicedBuffer));
// Slice a ByteBuffer from the target position to the end
int slicedBufferLength = size - slicePosition;
ByteBuffer slicedBuffer1 = BufferUtils.sliceByteBuffer(buf, slicePosition,
slicedBufferLength);
ByteBuffer slicedBuffer2 = BufferUtils.sliceByteBuffer(buf, slicePosition);
Assert.assertEquals(0, slicedBuffer1.position());
Assert.assertEquals(0, slicedBuffer2.position());
Assert.assertEquals(slicedBufferLength, slicedBuffer1.limit());
Assert.assertEquals(slicedBufferLength, slicedBuffer2.limit());
Assert.assertTrue(BufferUtils.equalIncreasingByteBuffer(slicePosition, slicedBufferLength,
slicedBuffer1));
Assert.assertTrue(BufferUtils.equalIncreasingByteBuffer(slicePosition, slicedBufferLength,
slicedBuffer2));
}
}
}