001 package org.apache.jcs.auxiliary.disk.block;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.util.Random;
024
025 import junit.framework.TestCase;
026
027 import org.apache.jcs.utils.serialization.StandardSerializer;
028
029 /**
030 * Test for the disk access layer of the Block Disk Cache.
031 * <p>
032 * @author Aaron Smuts
033 */
034 public class BlockDiskUnitTest
035 extends TestCase
036 {
037 /** data file. */
038 private File rafDir;
039
040 /**
041 * Creates the base directory
042 */
043 public BlockDiskUnitTest()
044 {
045 String rootDirName = "target/test-sandbox/block";
046 this.rafDir = new File( rootDirName );
047 this.rafDir.mkdirs();
048 }
049
050 /**
051 * Test writing a null object within a single block size.
052 * <p>
053 * @throws Exception
054 */
055 public void testWrite_NullBlockElement()
056 throws Exception
057 {
058 // SETUP
059 String fileName = "testWrite_NullBlockElement";
060 File file = new File( rafDir, fileName + ".data" );
061 file.delete();
062 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
063
064 // DO WORK
065 int[] blocks = disk.write( null );
066
067 // VERIFY
068 System.out.println( "testWrite_NullBlockElement " + disk );
069 assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
070 assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
071 assertEquals( "Wrong block returned.", 0, blocks[0] );
072 }
073
074 /**
075 * Test writing an element within a single block size.
076 * <p>
077 * @throws Exception
078 */
079 public void testWrite_SingleBlockElement()
080 throws Exception
081 {
082 // SETUP
083 String fileName = "testWrite_SingleBlockElement";
084 File file = new File( rafDir, fileName + ".data" );
085 file.delete();
086 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
087
088 // DO WORK
089 int bytes = 1 * 1024;
090 int[] blocks = disk.write( new byte[bytes] );
091
092 // VERIFY
093 System.out.println( "testWriteSingleBlockElement " + disk );
094 assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
095 assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
096 assertEquals( "Wrong block returned.", 0, blocks[0] );
097 }
098
099 /**
100 * Test writing and reading an element within a single block size.
101 * <p>
102 * @throws Exception
103 */
104 public void testWriteAndRead_SingleBlockElement()
105 throws Exception
106 {
107 // SETUP
108 String fileName = "testWriteAndRead_SingleBlockElement";
109 File file = new File( rafDir, fileName + ".data" );
110 file.delete();
111 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
112
113 // DO WORK
114 int bytes = 1 * 1024;
115 int[] blocks = disk.write( new byte[bytes] );
116
117 byte[] result = (byte[]) disk.read( blocks );
118
119 // VERIFY
120 assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
121 }
122
123 /**
124 * Test writing two elements that each fit within a single block size.
125 * <p>
126 * @throws Exception
127 */
128 public void testWrite_TwoSingleBlockElements()
129 throws Exception
130 {
131 // SETUP
132 String fileName = "testWrite_TwoSingleBlockElements";
133 File file = new File( rafDir, fileName + ".data" );
134 file.delete();
135 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
136
137 // DO WORK
138 int bytes = 1 * 1024;
139 int[] blocks1 = disk.write( new byte[bytes] );
140 int[] blocks2 = disk.write( new byte[bytes] );
141
142 // VERIFY
143 assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
144 assertEquals( "Wrong number of blocks returned.", 1, blocks1.length );
145 assertEquals( "Wrong block returned.", 0, blocks1[0] );
146 assertEquals( "Wrong number of blocks returned.", 1, blocks2.length );
147 assertEquals( "Wrong block returned.", 1, blocks2[0] );
148 }
149
150 /**
151 * Verify that it says we need two blocks if the total size will fit.
152 * <p>
153 * @throws Exception
154 */
155 public void testCalculateBlocksNeededDouble()
156 throws Exception
157 {
158 // SETUP
159 String fileName = "testCalculateBlocksNeededDouble";
160 File file = new File( rafDir, fileName + ".data" );
161 file.delete();
162 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
163
164 // DO WORK
165 int result = disk.calculateTheNumberOfBlocksNeeded( new byte[disk.getBlockSizeBytes() * 2
166 - ( 2 * BlockDisk.HEADER_SIZE_BYTES )] );
167
168 // Verify
169 assertEquals( "Wrong number of blocks", 2, result );
170 }
171
172 /**
173 * Test writing an element that takes two blocks.
174 * <p>
175 * @throws Exception
176 */
177 public void testWrite_DoubleBlockElement()
178 throws Exception
179 {
180 // SETUP
181 String fileName = "testWriteDoubleBlockElement";
182 File file = new File( rafDir, fileName + ".data" );
183 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
184
185 // DO WORK
186 // byte arrays encur 27 bytes of serialization overhead.
187 int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), 2 );
188 int[] blocks = disk.write( new byte[bytes] );
189
190 // VERIFY
191 System.out.println( "testWriteDoubleBlockElement " + disk );
192 assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
193 assertEquals( "Wrong number of blocks returned.", 2, blocks.length );
194 assertEquals( "Wrong block returned.", 0, blocks[0] );
195 }
196
197 /**
198 * 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.
199 * <p>
200 * @throws Exception
201 */
202 public void testWrite_128BlockElement()
203 throws Exception
204 {
205 // SETUP
206 int numBlocks = 128;
207
208 String fileName = "testWrite_128BlockElement";
209 File file = new File( rafDir, fileName + ".data" );
210 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
211
212 // DO WORK
213 // byte arrays encur 27 bytes of serialization overhead.
214 int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocks );
215 int[] blocks = disk.write( new byte[bytes] );
216
217 // VERIFY
218 System.out.println( "testWriteDoubleBlockElement " + disk );
219 assertEquals( "Wrong number of blocks recorded.", numBlocks, disk.getNumberOfBlocks() );
220 assertEquals( "Wrong number of blocks returned.", numBlocks, blocks.length );
221 assertEquals( "Wrong block returned.", 0, blocks[0] );
222 }
223
224 /**
225 * Test writing and reading elements that do not fit within a single block.
226 * <p>
227 * @throws Exception
228 */
229 public void testWriteAndReadMultipleMultiBlockElement()
230 throws Exception
231 {
232 // SETUP
233 String fileName = "testWriteAndReadSingleBlockElement";
234 File file = new File( rafDir, fileName + ".data" );
235 file.delete();
236 BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
237
238 // DO WORK
239 int numBlocksPerElement = 4;
240 int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
241
242 int numElements = 100;
243 for ( int i = 0; i < numElements; i++ )
244 {
245 int[] blocks = disk.write( new byte[bytes] );
246 byte[] result = (byte[]) disk.read( blocks );
247
248 // VERIFY
249 assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
250 assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
251 }
252 System.out.println( "testWriteAndReadMultipleMultiBlockElement " + disk );
253 }
254
255 /**
256 * Test writing and reading elements that do not fit within a single block.
257 * <p>
258 * @throws Exception
259 */
260 public void testWriteAndReadMultipleMultiBlockElement_setSize()
261 throws Exception
262 {
263 // SETUP
264 String fileName = "testWriteAndReadSingleBlockElement";
265 File file = new File( rafDir, fileName + ".data" );
266 file.delete();
267 int blockSizeBytes = 1024;
268 BlockDisk disk = new BlockDisk( file, blockSizeBytes );
269
270 // DO WORK
271 int numBlocksPerElement = 4;
272 int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
273
274 int numElements = 100;
275 Random r = new Random(System.currentTimeMillis());
276 final byte[] src = new byte[bytes];
277 for ( int i = 0; i < numElements; i++ )
278 {
279 r.nextBytes(src); // Ensure we don't just write zeros out
280 int[] blocks = disk.write( src );
281 byte[] result = (byte[]) disk.read( blocks );
282
283 // VERIFY
284 assertEquals( "Wrong item length retured.", src.length, result.length );
285 assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
286
287 // We check the array contents, too, to ensure we read back what we wrote out
288 for (int j = 0 ; j < src.length ; j++) {
289 assertEquals( "Mismatch at offset " + j + " in attempt # " + (i + 1), src[j], result[j] );
290 }
291 }
292 System.out.println( "testWriteAndReadMultipleMultiBlockElement_setSize " + disk );
293 assertEquals( "Wrong number of elements.", numBlocksPerElement * numElements, disk.getNumberOfBlocks() );
294 }
295
296 /**
297 * Used to get the size for byte arrays that will take up the number of blocks specified.
298 * <p>
299 * @param blockSize
300 * @param numBlocks
301 * @return num bytes.
302 */
303 private int getBytesForBlocksOfByteArrays( int blockSize, int numBlocks )
304 {
305 // byte arrays encur some bytes of serialization overhead.
306 return blockSize * numBlocks - ( numBlocks * BlockDisk.HEADER_SIZE_BYTES ) - ( numBlocks * 14 );
307 }
308
309 /**
310 * Verify that the block disk can handle a big string.
311 * <p>
312 * @throws Exception
313 */
314 public void testWriteAndRead_BigString()
315 throws Exception
316 {
317 // SETUP
318 String fileName = "testWriteAndRead_BigString";
319 File file = new File( rafDir, fileName + ".data" );
320 file.delete();
321 int blockSizeBytes = 4096;//1024;
322 BlockDisk disk = new BlockDisk( file, blockSizeBytes, new StandardSerializer() );
323
324 String string = "This is my big string ABCDEFGH";
325 StringBuffer sb = new StringBuffer();
326 sb.append( string );
327 for ( int i = 0; i < 8; i++ )
328 {
329 sb.append( " " + i + sb.toString() ); // big string
330 }
331 string = sb.toString();
332
333 // DO WORK
334 int[] blocks = disk.write( string );
335 String result = (String) disk.read( blocks );
336
337 // VERIFY
338 System.out.println( string );
339 System.out.println( result );
340 System.out.println( disk );
341 assertEquals( "Wrong item retured.", string, result );
342 }
343
344 /**
345 * Verify that the block disk can handle a big string.
346 * <p>
347 * @throws Exception
348 */
349 public void testWriteAndRead_BigString2()
350 throws Exception
351 {
352 // SETUP
353 String fileName = "testWriteAndRead_BigString";
354 File file = new File( rafDir, fileName + ".data" );
355 file.delete();
356 int blockSizeBytes = 47;//4096;//1024;
357 BlockDisk disk = new BlockDisk( file, blockSizeBytes, new StandardSerializer() );
358
359 String string = "abcdefghijklmnopqrstuvwxyz1234567890";
360 string += string;
361 string += string;
362
363 // DO WORK
364 int[] blocks = disk.write( string );
365 String result = (String) disk.read( blocks );
366
367 // VERIFY
368 assertEquals( "Wrong item retured.", string, result );
369 }
370 }