View Javadoc
1   package org.apache.commons.jcs3.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 java.io.File;
23  import java.io.IOException;
24  import java.io.Serializable;
25  import java.nio.charset.StandardCharsets;
26  import java.util.Map;
27  
28  import org.apache.commons.jcs3.engine.CacheElement;
29  import org.apache.commons.jcs3.engine.ElementAttributes;
30  import org.apache.commons.jcs3.engine.behavior.ICacheElement;
31  import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
32  import org.apache.commons.jcs3.engine.control.group.GroupAttrName;
33  import org.apache.commons.jcs3.engine.control.group.GroupId;
34  import org.apache.commons.jcs3.utils.serialization.StandardSerializer;
35  
36  import junit.framework.TestCase;
37  
38  /** Unit tests for the Block Disk Cache */
39  public abstract class BlockDiskCacheUnitTestAbstract extends TestCase
40  {
41      public abstract BlockDiskCacheAttributes getCacheAttributes();
42  
43      public void testPutGetMatching_SmallWait() throws Exception
44      {
45          // SETUP
46          final int items = 200;
47  
48          final String cacheName = "testPutGetMatching_SmallWait";
49          final BlockDiskCacheAttributes cattr = getCacheAttributes();
50          cattr.setCacheName(cacheName);
51          cattr.setMaxKeySize(100);
52          cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
53          final BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
54  
55          // DO WORK
56          for (int i = 0; i <= items; i++)
57          {
58              diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
59          }
60          Thread.sleep(500);
61  
62          final Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
63  
64          // VERIFY
65          assertEquals("Wrong number returned", 10, matchingResults.size());
66          // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
67          // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
68      }
69  
70      /**
71       * Test the basic get matching. With no wait this will all come from purgatory.
72       * <p>
73       *
74       * @throws Exception
75       */
76      public void testPutGetMatching_NoWait() throws Exception
77      {
78          // SETUP
79          final int items = 200;
80  
81          final String cacheName = "testPutGetMatching_NoWait";
82          final BlockDiskCacheAttributes cattr = getCacheAttributes();
83          cattr.setCacheName(cacheName);
84          cattr.setMaxKeySize(100);
85          cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
86          final BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
87  
88          // DO WORK
89          for (int i = 0; i <= items; i++)
90          {
91              diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i));
92          }
93  
94          final Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+");
95  
96          // VERIFY
97          assertEquals("Wrong number returned", 10, matchingResults.size());
98          // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() );
99          // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() );
100     }
101 
102     /**
103      * Verify that the block disk cache can handle a big string.
104      * <p>
105      *
106      * @throws Exception
107      */
108     public void testChunk_BigString() throws Exception
109     {
110         String string = "This is my big string ABCDEFGH";
111         final StringBuilder sb = new StringBuilder();
112         sb.append(string);
113         for (int i = 0; i < 4; i++)
114         {
115             sb.append("|" + i + ":" + sb.toString()); // big string
116         }
117         string = sb.toString();
118 
119         final StandardSerializer elementSerializer = new StandardSerializer();
120         final byte[] data = elementSerializer.serialize(string);
121 
122         final File file = new File("target/test-sandbox/BlockDiskCacheUnitTest/testChunk_BigString.data");
123 
124         final BlockDisk blockDisk = new BlockDisk(file, 200, elementSerializer);
125 
126         final int numBlocksNeeded = blockDisk.calculateTheNumberOfBlocksNeeded(data);
127         // System.out.println( numBlocksNeeded );
128 
129         // get the individual sub arrays.
130         final byte[][] chunks = blockDisk.getBlockChunks(data, numBlocksNeeded);
131 
132         byte[] resultData = new byte[0];
133 
134         for (short i = 0; i < chunks.length; i++)
135         {
136             final byte[] chunk = chunks[i];
137             final byte[] newTotal = new byte[data.length + chunk.length];
138             // copy data into the new array
139             System.arraycopy(data, 0, newTotal, 0, data.length);
140             // copy the chunk into the new array
141             System.arraycopy(chunk, 0, newTotal, data.length, chunk.length);
142             // swap the new and old.
143             resultData = newTotal;
144         }
145 
146         final Serializable result = elementSerializer.deSerialize(resultData, null);
147         // System.out.println( result );
148         assertEquals("wrong string after retrieval", string, result);
149         blockDisk.close();
150     }
151 
152     /**
153      * Verify that the block disk cache can handle a big string.
154      * <p>
155      *
156      * @throws Exception
157      */
158     public void testPutGet_BigString() throws Exception
159     {
160         String string = "This is my big string ABCDEFGH";
161         final StringBuilder sb = new StringBuilder();
162         sb.append(string);
163         for (int i = 0; i < 4; i++)
164         {
165             sb.append(" " + i + sb.toString()); // big string
166         }
167         string = sb.toString();
168 
169         final String cacheName = "testPutGet_BigString";
170 
171         final BlockDiskCacheAttributes cattr = getCacheAttributes();
172         cattr.setCacheName(cacheName);
173         cattr.setMaxKeySize(100);
174         cattr.setBlockSizeBytes(200);
175         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
176         final BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
177 
178         // DO WORK
179         diskCache.update(new CacheElement<>(cacheName, "x", string));
180 
181         // VERIFY
182         assertNotNull(diskCache.get("x"));
183         Thread.sleep(1000);
184         final ICacheElement<String, String> afterElement = diskCache.get("x");
185         assertNotNull(afterElement);
186         // System.out.println( "afterElement = " + afterElement );
187         final String after = afterElement.getVal();
188 
189         assertNotNull(after);
190         assertEquals("wrong string after retrieval", string, after);
191     }
192 
193     /**
194      * Verify that the block disk cache can handle utf encoded strings.
195      * <p>
196      *
197      * @throws Exception
198      */
199     public void testUTF8String() throws Exception
200     {
201         String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
202         final StringBuilder sb = new StringBuilder();
203         sb.append(string);
204         for (int i = 0; i < 4; i++)
205         {
206             sb.append(sb.toString()); // big string
207         }
208         string = sb.toString();
209 
210         // System.out.println( "The string contains " + string.length() + " characters" );
211 
212         final String cacheName = "testUTF8String";
213 
214         final BlockDiskCacheAttributes cattr = getCacheAttributes();
215         cattr.setCacheName(cacheName);
216         cattr.setMaxKeySize(100);
217         cattr.setBlockSizeBytes(200);
218         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
219         final BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr);
220 
221         // DO WORK
222         diskCache.update(new CacheElement<>(cacheName, "x", string));
223 
224         // VERIFY
225         assertNotNull(diskCache.get("x"));
226         Thread.sleep(1000);
227         final ICacheElement<String, String> afterElement = diskCache.get("x");
228         assertNotNull(afterElement);
229         // System.out.println( "afterElement = " + afterElement );
230         final String after = afterElement.getVal();
231 
232         assertNotNull(after);
233         assertEquals("wrong string after retrieval", string, after);
234     }
235 
236     /**
237      * Verify that the block disk cache can handle utf encoded strings.
238      * <p>
239      *
240      * @throws Exception
241      */
242     public void testUTF8ByteArray() throws Exception
243     {
244         String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
245         final StringBuilder sb = new StringBuilder();
246         sb.append(string);
247         for (int i = 0; i < 4; i++)
248         {
249             sb.append(sb.toString()); // big string
250         }
251         string = sb.toString();
252         // System.out.println( "The string contains " + string.length() + " characters" );
253         final byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
254 
255         final String cacheName = "testUTF8ByteArray";
256 
257         final BlockDiskCacheAttributes cattr = getCacheAttributes();
258         cattr.setCacheName(cacheName);
259         cattr.setMaxKeySize(100);
260         cattr.setBlockSizeBytes(200);
261         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
262         final BlockDiskCache<String, byte[]> diskCache = new BlockDiskCache<>(cattr);
263 
264         // DO WORK
265         diskCache.update(new CacheElement<>(cacheName, "x", bytes));
266 
267         // VERIFY
268         assertNotNull(diskCache.get("x"));
269         Thread.sleep(1000);
270         final ICacheElement<String, byte[]> afterElement = diskCache.get("x");
271         assertNotNull(afterElement);
272         // System.out.println( "afterElement = " + afterElement );
273         final byte[] after = afterElement.getVal();
274 
275         assertNotNull(after);
276         assertEquals("wrong bytes after retrieval", bytes.length, after.length);
277         // assertEquals( "wrong bytes after retrieval", bytes, after );
278         // assertEquals( "wrong bytes after retrieval", string, new String( after, StandardCharsets.UTF_8 ) );
279 
280     }
281 
282     /**
283      * Verify that the block disk cache can handle utf encoded strings.
284      * <p>
285      *
286      * @throws Exception
287      */
288     public void testUTF8StringAndBytes() throws Exception
289     {
290         final X before = new X();
291         String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
292         final StringBuilder sb = new StringBuilder();
293         sb.append(string);
294         for (int i = 0; i < 4; i++)
295         {
296             sb.append(sb.toString()); // big string
297         }
298         string = sb.toString();
299         // System.out.println( "The string contains " + string.length() + " characters" );
300         before.string = string;
301         before.bytes = string.getBytes(StandardCharsets.UTF_8);
302 
303         final String cacheName = "testUTF8StringAndBytes";
304 
305         final BlockDiskCacheAttributes cattr = getCacheAttributes();
306         cattr.setCacheName(cacheName);
307         cattr.setMaxKeySize(100);
308         cattr.setBlockSizeBytes(500);
309         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
310         final BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
311 
312         // DO WORK
313         diskCache.update(new CacheElement<>(cacheName, "x", before));
314 
315         // VERIFY
316         assertNotNull(diskCache.get("x"));
317         Thread.sleep(1000);
318         final ICacheElement<String, X> afterElement = diskCache.get("x");
319         // System.out.println( "afterElement = " + afterElement );
320         final X after = (afterElement.getVal());
321 
322         assertNotNull(after);
323         assertEquals("wrong string after retrieval", string, after.string);
324         assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
325 
326     }
327 
328     public void testLoadFromDisk() throws Exception
329     {
330         for (int i = 0; i < 20; i++)
331         { // usually after 2 time it fails
332             oneLoadFromDisk();
333         }
334     }
335 
336     public void testAppendToDisk() throws Exception
337     {
338         final String cacheName = "testAppendToDisk";
339         final BlockDiskCacheAttributes cattr = getCacheAttributes();
340         cattr.setCacheName(cacheName);
341         cattr.setMaxKeySize(100);
342         cattr.setBlockSizeBytes(500);
343         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
344         BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
345         diskCache.removeAll();
346         final X value1 = new X();
347         value1.string = "1234567890";
348         final X value2 = new X();
349         value2.string = "0987654321";
350         diskCache.update(new CacheElement<>(cacheName, "1", value1));
351         diskCache.dispose();
352         diskCache = new BlockDiskCache<>(cattr);
353         diskCache.update(new CacheElement<>(cacheName, "2", value2));
354         diskCache.dispose();
355         diskCache = new BlockDiskCache<>(cattr);
356         assertTrue(diskCache.verifyDisk());
357         assertEquals(2, diskCache.getKeySet().size());
358         assertEquals(value1.string, diskCache.get("1").getVal().string);
359         assertEquals(value2.string, diskCache.get("2").getVal().string);
360     }
361 
362     public void oneLoadFromDisk() throws Exception
363     {
364         // initialize object to be stored
365         final X before = new X();
366         String string = "IÒtÎrn‚tiÙn‡lizÊti¯n";
367         final StringBuilder sb = new StringBuilder();
368         sb.append(string);
369         for (int i = 0; i < 4; i++)
370         {
371             sb.append(sb.toString()); // big string
372         }
373         string = sb.toString();
374         before.string = string;
375         before.bytes = string.getBytes(StandardCharsets.UTF_8);
376 
377         // initialize cache
378         final String cacheName = "testLoadFromDisk";
379         final BlockDiskCacheAttributes cattr = getCacheAttributes();
380         cattr.setCacheName(cacheName);
381         cattr.setMaxKeySize(100);
382         cattr.setBlockSizeBytes(500);
383         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
384         BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr);
385 
386         // DO WORK
387         for (int i = 0; i < 50; i++)
388         {
389             diskCache.update(new CacheElement<>(cacheName, "x" + i, before));
390         }
391         diskCache.dispose();
392 
393         // VERIFY
394         diskCache = new BlockDiskCache<>(cattr);
395 
396         for (int i = 0; i < 50; i++)
397         {
398             final ICacheElement<String, X> afterElement = diskCache.get("x" + i);
399             assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement);
400             final X after = (afterElement.getVal());
401 
402             assertNotNull(after);
403             assertEquals("wrong string after retrieval", string, after.string);
404             assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8));
405         }
406 
407         diskCache.dispose();
408     }
409 
410     /**
411      * Add some items to the disk cache and then remove them one by one.
412      *
413      * @throws IOException
414      */
415     public void testRemoveItems() throws IOException
416     {
417         final BlockDiskCacheAttributes cattr = getCacheAttributes();
418         cattr.setCacheName("testRemoveItems");
419         cattr.setMaxKeySize(100);
420         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
421         final BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
422 
423         disk.processRemoveAll();
424 
425         final int cnt = 25;
426         for (int i = 0; i < cnt; i++)
427         {
428             final IElementAttributes eAttr = new ElementAttributes();
429             eAttr.setIsSpool(true);
430             final ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i);
431             element.setElementAttributes(eAttr);
432             disk.processUpdate(element);
433         }
434 
435         // remove each
436         for (int i = 0; i < cnt; i++)
437         {
438             disk.remove("key:" + i);
439             final ICacheElement<String, String> element = disk.processGet("key:" + i);
440             assertNull("Should not have received an element.", element);
441         }
442     }
443 
444     /**
445      * Add some items to the disk cache and then remove them one by one.
446      * <p>
447      *
448      * @throws IOException
449      */
450     public void testRemove_PartialKey() throws IOException
451     {
452         final BlockDiskCacheAttributes cattr = getCacheAttributes();
453         cattr.setCacheName("testRemove_PartialKey");
454         cattr.setMaxKeySize(100);
455         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
456         final BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr);
457 
458         disk.processRemoveAll();
459 
460         final int cnt = 25;
461         for (int i = 0; i < cnt; i++)
462         {
463             final IElementAttributes eAttr = new ElementAttributes();
464             eAttr.setIsSpool(true);
465             final ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:"
466                 + i);
467             element.setElementAttributes(eAttr);
468             disk.processUpdate(element);
469         }
470 
471         // verify each
472         for (int i = 0; i < cnt; i++)
473         {
474             final ICacheElement<String, String> element = disk.processGet(i + ":key");
475             assertNotNull("Shoulds have received an element.", element);
476         }
477 
478         // remove each
479         for (int i = 0; i < cnt; i++)
480         {
481             disk.remove(i + ":");
482             final ICacheElement<String, String> element = disk.processGet(i + ":key");
483             assertNull("Should not have received an element.", element);
484         }
485     }
486 
487 
488     /**
489      * Verify that group members are removed if we call remove with a group.
490      *
491      * @throws IOException
492      */
493     public void testRemove_Group() throws IOException
494     {
495         // SETUP
496         final BlockDiskCacheAttributes cattr = getCacheAttributes();
497         cattr.setCacheName("testRemove_Group");
498         cattr.setMaxKeySize(100);
499         cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest");
500         final BlockDiskCache<GroupAttrName<String>, String> disk = new BlockDiskCache<>(cattr);
501 
502         disk.processRemoveAll();
503 
504         final String cacheName = "testRemove_Group_Region";
505         final String groupName = "testRemove_Group";
506 
507         final int cnt = 25;
508         for (int i = 0; i < cnt; i++)
509         {
510             final GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
511             final CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName,
512                 groupAttrName, "data:" + i);
513 
514             final IElementAttributes eAttr = new ElementAttributes();
515             eAttr.setIsSpool(true);
516             element.setElementAttributes(eAttr);
517 
518             disk.processUpdate(element);
519         }
520 
521         // verify each
522         for (int i = 0; i < cnt; i++)
523         {
524             final GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
525             final ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
526             assertNotNull("Should have received an element.", element);
527         }
528 
529         // DO WORK
530         // remove the group
531         disk.remove(getGroupAttrName(cacheName, groupName, null));
532 
533         for (int i = 0; i < cnt; i++)
534         {
535             final GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key");
536             final ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName);
537 
538             // VERIFY
539             assertNull("Should not have received an element.", element);
540         }
541 
542     }
543 
544     /**
545      * Internal method used for group functionality.
546      * <p>
547      *
548      * @param cacheName
549      * @param group
550      * @param name
551      * @return GroupAttrName
552      */
553     private GroupAttrName<String> getGroupAttrName(final String cacheName, final String group, final String name)
554     {
555         final GroupId gid = new GroupId(cacheName, group);
556         return new GroupAttrName<>(gid, name);
557     }
558 
559     /** Holder for a string and byte array. */
560     static class X implements Serializable
561     {
562         /** ignore */
563         private static final long serialVersionUID = 1L;
564 
565         /** Test string */
566         String string;
567 
568         /*** test byte array. */
569         byte[] bytes;
570     }
571 }