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