View Javadoc
1   package org.apache.commons.jcs.auxiliary.disk.block;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import junit.framework.TestCase;
23  import org.apache.commons.jcs.utils.serialization.StandardSerializer;
24  
25  import java.io.File;
26  import java.util.Random;
27  
28  /**
29   * Test for the disk access layer of the Block Disk Cache.
30   * <p>
31   * @author Aaron Smuts
32   */
33  public class BlockDiskUnitTest
34      extends TestCase
35  {
36      /** data file. */
37      private File rafDir;
38  
39      /**
40       * Creates the base directory
41       */
42      public BlockDiskUnitTest()
43      {
44          String rootDirName = "target/test-sandbox/block";
45          this.rafDir = new File( rootDirName );
46          this.rafDir.mkdirs();
47      }
48  
49      /**
50       * Test writing a null object within a single block size.
51       * <p>
52       * @throws Exception
53       */
54      public void testWrite_NullBlockElement()
55          throws Exception
56      {
57          // SETUP
58          String fileName = "testWrite_NullBlockElement";
59          File file = new File( rafDir, fileName + ".data" );
60          file.delete();
61          BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
62  
63          // DO WORK
64          int[] blocks = disk.write( null );
65  
66          // VERIFY
67          assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
68          assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
69          assertEquals( "Wrong block returned.", 0, blocks[0] );
70      }
71  
72      /**
73       * Test writing an element within a single block size.
74       * <p>
75       * @throws Exception
76       */
77      public void testWrite_SingleBlockElement()
78          throws Exception
79      {
80          // SETUP
81          String fileName = "testWrite_SingleBlockElement";
82          File file = new File( rafDir, fileName + ".data" );
83          file.delete();
84          BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
85  
86          // DO WORK
87          int bytes = 1 * 1024;
88          int[] blocks = disk.write( new byte[bytes] );
89  
90          // VERIFY
91          assertEquals( "Wrong number of blocks recorded.", 1, disk.getNumberOfBlocks() );
92          assertEquals( "Wrong number of blocks returned.", 1, blocks.length );
93          assertEquals( "Wrong block returned.", 0, blocks[0] );
94      }
95  
96      /**
97       * Test writing and reading an element within a single block size.
98       * <p>
99       * @throws Exception
100      */
101     public void testWriteAndRead_SingleBlockElement()
102         throws Exception
103     {
104         // SETUP
105         String fileName = "testWriteAndRead_SingleBlockElement";
106         File file = new File( rafDir, fileName + ".data" );
107         file.delete();
108         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
109 
110         // DO WORK
111         int bytes = 1 * 1024;
112         int[] blocks = disk.write( new byte[bytes] );
113 
114         byte[] result = (byte[]) disk.read( blocks );
115 
116         // VERIFY
117         assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
118     }
119 
120     /**
121      * Test writing two elements that each fit within a single block size.
122      * <p>
123      * @throws Exception
124      */
125     public void testWrite_TwoSingleBlockElements()
126         throws Exception
127     {
128         // SETUP
129         String fileName = "testWrite_TwoSingleBlockElements";
130         File file = new File( rafDir, fileName + ".data" );
131         file.delete();
132         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
133 
134         // DO WORK
135         int bytes = 1 * 1024;
136         int[] blocks1 = disk.write( new byte[bytes] );
137         int[] blocks2 = disk.write( new byte[bytes] );
138 
139         // VERIFY
140         assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
141         assertEquals( "Wrong number of blocks returned.", 1, blocks1.length );
142         assertEquals( "Wrong block returned.", 0, blocks1[0] );
143         assertEquals( "Wrong number of blocks returned.", 1, blocks2.length );
144         assertEquals( "Wrong block returned.", 1, blocks2[0] );
145     }
146 
147     /**
148      * Verify that it says we need two blocks if the total size will fit.
149      * <p>
150      * @throws Exception
151      */
152     public void testCalculateBlocksNeededDouble()
153         throws Exception
154     {
155         // SETUP
156         String fileName = "testCalculateBlocksNeededDouble";
157         File file = new File( rafDir, fileName + ".data" );
158         file.delete();
159         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
160 
161         // DO WORK
162         int result = disk.calculateTheNumberOfBlocksNeeded( new byte[disk.getBlockSizeBytes() * 2
163             - ( 2 * BlockDisk.HEADER_SIZE_BYTES )] );
164 
165         // Verify
166         assertEquals( "Wrong number of blocks", 2, result );
167     }
168 
169     /**
170      * Test writing an element that takes two blocks.
171      * <p>
172      * @throws Exception
173      */
174     public void testWrite_DoubleBlockElement()
175         throws Exception
176     {
177         // SETUP
178         String fileName = "testWriteDoubleBlockElement";
179         File file = new File( rafDir, fileName + ".data" );
180         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
181 
182         // DO WORK
183         // byte arrays encur 27 bytes of serialization overhead.
184         int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), 2 );
185         int[] blocks = disk.write( new byte[bytes] );
186 
187         // VERIFY
188         assertEquals( "Wrong number of blocks recorded.", 2, disk.getNumberOfBlocks() );
189         assertEquals( "Wrong number of blocks returned.", 2, blocks.length );
190         assertEquals( "Wrong block returned.", 0, blocks[0] );
191     }
192 
193     /**
194      * 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.
195      * <p>
196      * @throws Exception
197      */
198     public void testWrite_128BlockElement()
199         throws Exception
200     {
201         // SETUP
202         int numBlocks = 128;
203 
204         String fileName = "testWrite_128BlockElement";
205         File file = new File( rafDir, fileName + ".data" );
206         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
207 
208         // DO WORK
209         // byte arrays encur 27 bytes of serialization overhead.
210         int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocks );
211         int[] blocks = disk.write( new byte[bytes] );
212 
213         // VERIFY
214         assertEquals( "Wrong number of blocks recorded.", numBlocks, disk.getNumberOfBlocks() );
215         assertEquals( "Wrong number of blocks returned.", numBlocks, blocks.length );
216         assertEquals( "Wrong block returned.", 0, blocks[0] );
217     }
218 
219     /**
220      * Test writing and reading elements that do not fit within a single block.
221      * <p>
222      * @throws Exception
223      */
224     public void testWriteAndReadMultipleMultiBlockElement()
225         throws Exception
226     {
227         // SETUP
228         String fileName = "testWriteAndReadSingleBlockElement";
229         File file = new File( rafDir, fileName + ".data" );
230         file.delete();
231         BlockDisk disk = new BlockDisk( file, new StandardSerializer() );
232 
233         // DO WORK
234         int numBlocksPerElement = 4;
235         int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
236 
237         int numElements = 100;
238         for ( int i = 0; i < numElements; i++ )
239         {
240             int[] blocks = disk.write( new byte[bytes] );
241             byte[] result = (byte[]) disk.read( blocks );
242 
243             // VERIFY
244             assertEquals( "Wrong item retured.", new byte[bytes].length, result.length );
245             assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
246         }
247     }
248 
249     /**
250      * Test writing and reading elements that do not fit within a single block.
251      * <p>
252      * @throws Exception
253      */
254     public void testWriteAndReadMultipleMultiBlockElement_setSize()
255         throws Exception
256     {
257         // SETUP
258         String fileName = "testWriteAndReadSingleBlockElement";
259         File file = new File( rafDir, fileName + ".data" );
260         file.delete();
261         int blockSizeBytes = 1024;
262         BlockDisk disk = new BlockDisk( file, blockSizeBytes );
263 
264         // DO WORK
265         int numBlocksPerElement = 4;
266         int bytes = getBytesForBlocksOfByteArrays( disk.getBlockSizeBytes(), numBlocksPerElement );
267 
268         int numElements = 100;
269         Random r = new Random(System.currentTimeMillis());
270         final byte[] src = new byte[bytes];
271         for ( int i = 0; i < numElements; i++ )
272         {
273             r.nextBytes(src);  // Ensure we don't just write zeros out
274             int[] blocks = disk.write( src );
275             byte[] result = (byte[]) disk.read( blocks );
276 
277             // VERIFY
278             assertEquals( "Wrong item length retured.", src.length, result.length );
279             assertEquals( "Wrong number of blocks returned.", numBlocksPerElement, blocks.length );
280 
281             // We check the array contents, too, to ensure we read back what we wrote out
282             for (int j = 0 ; j < src.length ; j++) {
283                 assertEquals( "Mismatch at offset " + j + " in attempt # " + (i + 1), src[j], result[j] );
284             }
285         }
286         assertEquals( "Wrong number of elements. "+disk, numBlocksPerElement * numElements, disk.getNumberOfBlocks() );
287     }
288 
289     /**
290      * Used to get the size for byte arrays that will take up the number of blocks specified.
291      * <p>
292      * @param blockSize
293      * @param numBlocks
294      * @return num bytes.
295      */
296     private int getBytesForBlocksOfByteArrays( int blockSize, int numBlocks )
297     {
298         // byte arrays encur some bytes of serialization overhead.
299         return blockSize * numBlocks - ( numBlocks * BlockDisk.HEADER_SIZE_BYTES ) - ( numBlocks * 14 );
300     }
301 
302     /**
303      * Verify that the block disk can handle a big string.
304      * <p>
305      * @throws Exception
306      */
307     public void testWriteAndRead_BigString()
308         throws Exception
309     {
310         // SETUP
311         String fileName = "testWriteAndRead_BigString";
312         File file = new File( rafDir, fileName + ".data" );
313         file.delete();
314         int blockSizeBytes = 4096;//1024;
315         BlockDisk disk = new BlockDisk( file, blockSizeBytes, new StandardSerializer() );
316 
317         String string = "This is my big string ABCDEFGH";
318         StringBuilder sb = new StringBuilder();
319         sb.append( string );
320         for ( int i = 0; i < 8; i++ )
321         {
322             sb.append( " " + i + sb.toString() ); // big string
323         }
324         string = sb.toString();
325 
326         // DO WORK
327         int[] blocks = disk.write( string );
328         String result = (String) disk.read( blocks );
329 
330         // VERIFY
331 //        System.out.println( string );
332 //        System.out.println( result );
333 //        System.out.println( disk );
334         assertEquals( "Wrong item retured.", string, result );
335     }
336 
337     /**
338      * Verify that the block disk can handle a big string.
339      * <p>
340      * @throws Exception
341      */
342     public void testWriteAndRead_BigString2()
343         throws Exception
344     {
345         // SETUP
346         String fileName = "testWriteAndRead_BigString";
347         File file = new File( rafDir, fileName + ".data" );
348         file.delete();
349         int blockSizeBytes = 47;//4096;//1024;
350         BlockDisk disk = new BlockDisk( file, blockSizeBytes, new StandardSerializer() );
351 
352         String string = "abcdefghijklmnopqrstuvwxyz1234567890";
353         string += string;
354         string += string;
355 
356         // DO WORK
357         int[] blocks = disk.write( string );
358         String result = (String) disk.read( blocks );
359 
360         // VERIFY
361         assertEquals( "Wrong item retured.", string, result );
362     }
363 
364     public void testJCS156() throws Exception {
365         // SETUP
366         String fileName = "testJCS156";
367         File file = new File( rafDir, fileName + ".data" );
368         file.delete();
369         int blockSizeBytes = 4096;
370         BlockDisk disk = new BlockDisk( file, blockSizeBytes, new StandardSerializer() );
371         long offset = disk.calculateByteOffsetForBlockAsLong(Integer.MAX_VALUE);
372         assertTrue("Must not wrap round", offset > 0);
373         assertEquals(Integer.MAX_VALUE*4096L,offset);
374         file.delete();
375     }
376 }