blob: 394fc560a7739f1863823119f7fd0b55435be0ca [file] [log] [blame]
package org.apache.commons.jcs3.auxiliary.disk.block;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import junit.framework.TestCase;
/**
* Test for the disk access layer of the Block Disk Cache.
* <p>
* @author Aaron Smuts
*/
public class BlockDiskUnitTest
extends TestCase
{
/** data file. */
private File rafDir;
private BlockDisk disk;
/**
* @see junit.framework.TestCase#setUp()
* Creates the base directory
*/
@Override
protected void setUp() throws Exception
{
super.setUp();
final String rootDirName = "target/test-sandbox/block";
this.rafDir = new File( rootDirName );
this.rafDir.mkdirs();
}
private void setUpBlockDisk(final String fileName) throws IOException
{
final File file = new File(rafDir, fileName + ".data");
file.delete();
this.disk = new BlockDisk(file, new StandardSerializer());
}
private void setUpBlockDisk(final String fileName, final int blockSize) throws IOException
{
final File file = new File(rafDir, fileName + ".data");
file.delete();
this.disk = new BlockDisk(file, blockSize, new StandardSerializer());
}
/**
* @see junit.framework.TestCase#tearDown()
*/
@Override
protected void tearDown() throws Exception
{
disk.close();
super.tearDown();
}
/**
* Test writing a null object within a single block size.
* <p>
* @throws Exception
*/
public void testWrite_NullBlockElement()
throws Exception
{
// SETUP
setUpBlockDisk("testWrite_NullBlockElement");
// DO WORK
final int[] blocks = disk.write( null );
// VERIFY
assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
assertEquals( "Wrong block returned.", 0, blocks[0] );
}
/**
* Test writing an element within a single block size.
* <p>
* @throws Exception
*/
public void testWrite_SingleBlockElement()
throws Exception
{
// SETUP
setUpBlockDisk("testWrite_SingleBlockElement");
// DO WORK
final int bytes = 1 * 1024;
final int[] blocks = disk.write( new byte[bytes] );
// VERIFY
assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
assertEquals( "Wrong block returned.", 0, blocks[0] );
}
/**
* Test writing and reading an element within a single block size.
* <p>
* @throws Exception
*/
public void testWriteAndRead_SingleBlockElement()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteAndRead_SingleBlockElement");
// DO WORK
final int bytes = 1 * 1024;
final int[] blocks = disk.write( new byte[bytes] );
final byte[] result = (byte[]) disk.read( blocks );
// VERIFY
assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
}
/**
* Test writing two elements that each fit within a single block size.
* <p>
* @throws Exception
*/
public void testWrite_TwoSingleBlockElements()
throws Exception
{
// SETUP
setUpBlockDisk("testWrite_TwoSingleBlockElements");
// DO WORK
final int bytes = 1 * 1024;
final int[] blocks1 = disk.write( new byte[bytes] );
final int[] blocks2 = disk.write( new byte[bytes] );
// VERIFY
assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
assertEquals( "Wrong number of blocks returned.", 1, blocks1.length );
assertEquals( "Wrong block returned.", 0, blocks1[0] );
assertEquals( "Wrong number of blocks returned.", 1, blocks2.length );
assertEquals( "Wrong block returned.", 1, blocks2[0] );
}
/**
* Verify that it says we need two blocks if the total size will fit.
* <p>
* @throws Exception
*/
public void testCalculateBlocksNeededDouble()
throws Exception
{
// SETUP
setUpBlockDisk("testCalculateBlocksNeededDouble");
// DO WORK
final int result = disk.calculateTheNumberOfBlocksNeeded( new byte[disk.getBlockSizeBytes() * 2
- ( 2 * BlockDisk.HEADER_SIZE_BYTES )] );
// Verify
assertEquals( "Wrong number of blocks", 2, result );
}
/**
* Test writing an element that takes two blocks.
* <p>
* @throws Exception
*/
public void testWrite_DoubleBlockElement()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteDoubleBlockElement");
// DO WORK
// byte arrays encur 27 bytes of serialization overhead.
final int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), 2 );
final int[] blocks = disk.write( new byte[bytes] );
// VERIFY
assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
assertEquals( "Wrong number of blocks returned.", 2, blocks.length );
assertEquals( "Wrong block returned.", 0, blocks[0] );
}
/**
* Test writing an element that takes 128 blocks. There was a byte in a for loop that limited the number to 127. I fixed this.
* <p>
* @throws Exception
*/
public void testWrite_128BlockElement()
throws Exception
{
// SETUP
final int numBlocks = 128;
setUpBlockDisk("testWrite_128BlockElement");
// DO WORK
// byte arrays encur 27 bytes of serialization overhead.
final int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocks );
final int[] blocks = disk.write( new byte[bytes] );
// VERIFY
assertEquals( "Wrong number of blocks recorded.", numBlocks, disk.getNumberOfBlocks() );
assertEquals( "Wrong number of blocks returned.", numBlocks, blocks.length );
assertEquals( "Wrong block returned.", 0, blocks[0] );
}
/**
* Test writing and reading elements that do not fit within a single block.
* <p>
* @throws Exception
*/
public void testWriteAndReadMultipleMultiBlockElement()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteAndReadSingleBlockElement");
// DO WORK
final int numBlocksPerElement = 4;
final int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
final int numElements = 100;
for ( int i = 0; i < numElements; i++ )
{
final int[] blocks = disk.write( new byte[bytes] );
final byte[] result = (byte[]) disk.read( blocks );
// VERIFY
assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
}
}
/**
* Test writing and reading elements that do not fit within a single block.
* <p>
* @throws Exception
*/
public void testWriteAndReadMultipleMultiBlockElement_setSize()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteAndReadSingleBlockElement", 1024);
// DO WORK
final int numBlocksPerElement = 4;
final int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
final int numElements = 100;
final Random r = new Random(System.currentTimeMillis());
final byte[] src = new byte[bytes];
for ( int i = 0; i < numElements; i++ )
{
r.nextBytes(src); // Ensure we don't just write zeros out
final int[] blocks = disk.write( src );
final byte[] result = (byte[]) disk.read( blocks );
// VERIFY
assertEquals( "Wrong item length retured.", src.length, result.length );
assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
// We check the array contents, too, to ensure we read back what we wrote out
for (int j = 0 ; j < src.length ; j++) {
assertEquals( "Mismatch at offset " + j + " in attempt # " + (i + 1), src[j], result[j] );
}
}
assertEquals( "Wrong number of elements. "+disk, numBlocksPerElement * numElements, disk.getNumberOfBlocks() );
}
/**
* Used to get the size for byte arrays that will take up the number of blocks specified.
* <p>
* @param blockSize
* @param numBlocks
* @return num bytes.
*/
private int getBytesForBlocksOfByteArrays( final int blockSize, final int numBlocks )
{
// byte arrays encur some bytes of serialization overhead.
return blockSize * numBlocks - ( numBlocks * BlockDisk.HEADER_SIZE_BYTES ) - ( numBlocks * 14 );
}
/**
* Verify that the block disk can handle a big string.
* <p>
* @throws Exception
*/
public void testWriteAndRead_BigString()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteAndRead_BigString", 4096); //1024
String string = "This is my big string ABCDEFGH";
final StringBuilder sb = new StringBuilder();
sb.append( string );
for ( int i = 0; i < 8; i++ )
{
sb.append( " " + i + sb.toString() ); // big string
}
string = sb.toString();
// DO WORK
final int[] blocks = disk.write( string );
final String result = (String) disk.read( blocks );
// VERIFY
// System.out.println( string );
// System.out.println( result );
// System.out.println( disk );
assertEquals( "Wrong item retured.", string, result );
}
/**
* Verify that the block disk can handle a big string.
* <p>
* @throws Exception
*/
public void testWriteAndRead_BigString2()
throws Exception
{
// SETUP
setUpBlockDisk("testWriteAndRead_BigString", 47); //4096;//1024
String string = "abcdefghijklmnopqrstuvwxyz1234567890";
string += string;
string += string;
// DO WORK
final int[] blocks = disk.write( string );
final String result = (String) disk.read( blocks );
// VERIFY
assertEquals( "Wrong item retured.", string, result );
}
public void testJCS156() throws Exception
{
// SETUP
setUpBlockDisk("testJCS156", 4096);
final long offset = disk.calculateByteOffsetForBlockAsLong(Integer.MAX_VALUE);
assertTrue("Must not wrap round", offset > 0);
assertEquals(Integer.MAX_VALUE*4096L,offset);
}
}