package org.apache.commons.jcs3.auxiliary.disk.block; /* * 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 java.io.File; import java.io.IOException; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.Map; import org.apache.commons.jcs3.auxiliary.disk.block.BlockDiskCacheAttributes; import org.apache.commons.jcs3.engine.CacheElement; import org.apache.commons.jcs3.engine.ElementAttributes; import org.apache.commons.jcs3.engine.behavior.ICacheElement; import org.apache.commons.jcs3.engine.behavior.IElementAttributes; import org.apache.commons.jcs3.engine.control.group.GroupAttrName; import org.apache.commons.jcs3.engine.control.group.GroupId; import org.apache.commons.jcs3.utils.serialization.StandardSerializer; import junit.framework.TestCase; /** Unit tests for the Block Disk Cache */ public abstract class BlockDiskCacheUnitTestAbstract extends TestCase { public abstract BlockDiskCacheAttributes getCacheAttributes(); public void testPutGetMatching_SmallWait() throws Exception { // SETUP int items = 200; String cacheName = "testPutGetMatching_SmallWait"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr); // DO WORK for (int i = 0; i <= items; i++) { diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i)); } Thread.sleep(500); Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+"); // VERIFY assertEquals("Wrong number returned", 10, matchingResults.size()); // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() ); // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() ); } /** * Test the basic get matching. With no wait this will all come from purgatory. * <p> * * @throws Exception */ public void testPutGetMatching_NoWait() throws Exception { // SETUP int items = 200; String cacheName = "testPutGetMatching_NoWait"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr); // DO WORK for (int i = 0; i <= items; i++) { diskCache.update(new CacheElement<>(cacheName, i + ":key", cacheName + " data " + i)); } Map<String, ICacheElement<String, String>> matchingResults = diskCache.getMatching("1.8.+"); // VERIFY assertEquals("Wrong number returned", 10, matchingResults.size()); // System.out.println( "matchingResults.keySet() " + matchingResults.keySet() ); // System.out.println( "\nAFTER TEST \n" + diskCache.getStats() ); } /** * Verify that the block disk cache can handle a big string. * <p> * * @throws Exception */ public void testChunk_BigString() throws Exception { String string = "This is my big string ABCDEFGH"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append("|" + i + ":" + sb.toString()); // big string } string = sb.toString(); StandardSerializer elementSerializer = new StandardSerializer(); byte[] data = elementSerializer.serialize(string); File file = new File("target/test-sandbox/BlockDiskCacheUnitTest/testChunk_BigString.data"); BlockDisk blockDisk = new BlockDisk(file, 200, elementSerializer); int numBlocksNeeded = blockDisk.calculateTheNumberOfBlocksNeeded(data); // System.out.println( numBlocksNeeded ); // get the individual sub arrays. byte[][] chunks = blockDisk.getBlockChunks(data, numBlocksNeeded); byte[] resultData = new byte[0]; for (short i = 0; i < chunks.length; i++) { byte[] chunk = chunks[i]; byte[] newTotal = new byte[data.length + chunk.length]; // copy data into the new array System.arraycopy(data, 0, newTotal, 0, data.length); // copy the chunk into the new array System.arraycopy(chunk, 0, newTotal, data.length, chunk.length); // swap the new and old. resultData = newTotal; } Serializable result = elementSerializer.deSerialize(resultData, null); // System.out.println( result ); assertEquals("wrong string after retrieval", string, result); blockDisk.close(); } /** * Verify that the block disk cache can handle a big string. * <p> * * @throws Exception */ public void testPutGet_BigString() throws Exception { String string = "This is my big string ABCDEFGH"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append(" " + i + sb.toString()); // big string } string = sb.toString(); String cacheName = "testPutGet_BigString"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(200); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr); // DO WORK diskCache.update(new CacheElement<>(cacheName, "x", string)); // VERIFY assertNotNull(diskCache.get("x")); Thread.sleep(1000); ICacheElement<String, String> afterElement = diskCache.get("x"); assertNotNull(afterElement); // System.out.println( "afterElement = " + afterElement ); String after = afterElement.getVal(); assertNotNull(after); assertEquals("wrong string after retrieval", string, after); } /** * Verify that the block disk cache can handle utf encoded strings. * <p> * * @throws Exception */ public void testUTF8String() throws Exception { String string = "IÒtÎrn‚tiÙn‡lizÊti¯n"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append(sb.toString()); // big string } string = sb.toString(); // System.out.println( "The string contains " + string.length() + " characters" ); String cacheName = "testUTF8String"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(200); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> diskCache = new BlockDiskCache<>(cattr); // DO WORK diskCache.update(new CacheElement<>(cacheName, "x", string)); // VERIFY assertNotNull(diskCache.get("x")); Thread.sleep(1000); ICacheElement<String, String> afterElement = diskCache.get("x"); assertNotNull(afterElement); // System.out.println( "afterElement = " + afterElement ); String after = afterElement.getVal(); assertNotNull(after); assertEquals("wrong string after retrieval", string, after); } /** * Verify that the block disk cache can handle utf encoded strings. * <p> * * @throws Exception */ public void testUTF8ByteArray() throws Exception { String string = "IÒtÎrn‚tiÙn‡lizÊti¯n"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append(sb.toString()); // big string } string = sb.toString(); // System.out.println( "The string contains " + string.length() + " characters" ); byte[] bytes = string.getBytes(StandardCharsets.UTF_8); String cacheName = "testUTF8ByteArray"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(200); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, byte[]> diskCache = new BlockDiskCache<>(cattr); // DO WORK diskCache.update(new CacheElement<>(cacheName, "x", bytes)); // VERIFY assertNotNull(diskCache.get("x")); Thread.sleep(1000); ICacheElement<String, byte[]> afterElement = diskCache.get("x"); assertNotNull(afterElement); // System.out.println( "afterElement = " + afterElement ); byte[] after = afterElement.getVal(); assertNotNull(after); assertEquals("wrong bytes after retrieval", bytes.length, after.length); // assertEquals( "wrong bytes after retrieval", bytes, after ); // assertEquals( "wrong bytes after retrieval", string, new String( after, StandardCharsets.UTF_8 ) ); } /** * Verify that the block disk cache can handle utf encoded strings. * <p> * * @throws Exception */ public void testUTF8StringAndBytes() throws Exception { X before = new X(); String string = "IÒtÎrn‚tiÙn‡lizÊti¯n"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append(sb.toString()); // big string } string = sb.toString(); // System.out.println( "The string contains " + string.length() + " characters" ); before.string = string; before.bytes = string.getBytes(StandardCharsets.UTF_8); String cacheName = "testUTF8StringAndBytes"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(500); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr); // DO WORK diskCache.update(new CacheElement<>(cacheName, "x", before)); // VERIFY assertNotNull(diskCache.get("x")); Thread.sleep(1000); ICacheElement<String, X> afterElement = diskCache.get("x"); // System.out.println( "afterElement = " + afterElement ); X after = (afterElement.getVal()); assertNotNull(after); assertEquals("wrong string after retrieval", string, after.string); assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8)); } public void testLoadFromDisk() throws Exception { for (int i = 0; i < 20; i++) { // usually after 2 time it fails oneLoadFromDisk(); } } public void testAppendToDisk() throws Exception { String cacheName = "testAppendToDisk"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(500); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr); diskCache.removeAll(); X value1 = new X(); value1.string = "1234567890"; X value2 = new X(); value2.string = "0987654321"; diskCache.update(new CacheElement<>(cacheName, "1", value1)); diskCache.dispose(); diskCache = new BlockDiskCache<>(cattr); diskCache.update(new CacheElement<>(cacheName, "2", value2)); diskCache.dispose(); diskCache = new BlockDiskCache<>(cattr); assertTrue(diskCache.verifyDisk()); assertEquals(2, diskCache.getKeySet().size()); assertEquals(value1.string, diskCache.get("1").getVal().string); assertEquals(value2.string, diskCache.get("2").getVal().string); } public void oneLoadFromDisk() throws Exception { // initialize object to be stored X before = new X(); String string = "IÒtÎrn‚tiÙn‡lizÊti¯n"; StringBuilder sb = new StringBuilder(); sb.append(string); for (int i = 0; i < 4; i++) { sb.append(sb.toString()); // big string } string = sb.toString(); before.string = string; before.bytes = string.getBytes(StandardCharsets.UTF_8); // initialize cache String cacheName = "testLoadFromDisk"; BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName(cacheName); cattr.setMaxKeySize(100); cattr.setBlockSizeBytes(500); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, X> diskCache = new BlockDiskCache<>(cattr); // DO WORK for (int i = 0; i < 50; i++) { diskCache.update(new CacheElement<>(cacheName, "x" + i, before)); } diskCache.dispose(); // VERIFY diskCache = new BlockDiskCache<>(cattr); for (int i = 0; i < 50; i++) { ICacheElement<String, X> afterElement = diskCache.get("x" + i); assertNotNull("Missing element from cache. Cache size: " + diskCache.getSize() + " element: x" + i, afterElement); X after = (afterElement.getVal()); assertNotNull(after); assertEquals("wrong string after retrieval", string, after.string); assertEquals("wrong bytes after retrieval", string, new String(after.bytes, StandardCharsets.UTF_8)); } diskCache.dispose(); } /** * Add some items to the disk cache and then remove them one by one. * * @throws IOException */ public void testRemoveItems() throws IOException { BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName("testRemoveItems"); cattr.setMaxKeySize(100); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr); disk.processRemoveAll(); int cnt = 25; for (int i = 0; i < cnt; i++) { IElementAttributes eAttr = new ElementAttributes(); eAttr.setIsSpool(true); ICacheElement<String, String> element = new CacheElement<>("testRemoveItems", "key:" + i, "data:" + i); element.setElementAttributes(eAttr); disk.processUpdate(element); } // remove each for (int i = 0; i < cnt; i++) { disk.remove("key:" + i); ICacheElement<String, String> element = disk.processGet("key:" + i); assertNull("Should not have received an element.", element); } } /** * Add some items to the disk cache and then remove them one by one. * <p> * * @throws IOException */ public void testRemove_PartialKey() throws IOException { BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName("testRemove_PartialKey"); cattr.setMaxKeySize(100); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<String, String> disk = new BlockDiskCache<>(cattr); disk.processRemoveAll(); int cnt = 25; for (int i = 0; i < cnt; i++) { IElementAttributes eAttr = new ElementAttributes(); eAttr.setIsSpool(true); ICacheElement<String, String> element = new CacheElement<>("testRemove_PartialKey", i + ":key", "data:" + i); element.setElementAttributes(eAttr); disk.processUpdate(element); } // verify each for (int i = 0; i < cnt; i++) { ICacheElement<String, String> element = disk.processGet(i + ":key"); assertNotNull("Shoulds have received an element.", element); } // remove each for (int i = 0; i < cnt; i++) { disk.remove(i + ":"); ICacheElement<String, String> element = disk.processGet(i + ":key"); assertNull("Should not have received an element.", element); } } /** * Verify that group members are removed if we call remove with a group. * * @throws IOException */ public void testRemove_Group() throws IOException { // SETUP BlockDiskCacheAttributes cattr = getCacheAttributes(); cattr.setCacheName("testRemove_Group"); cattr.setMaxKeySize(100); cattr.setDiskPath("target/test-sandbox/BlockDiskCacheUnitTest"); BlockDiskCache<GroupAttrName<String>, String> disk = new BlockDiskCache<>(cattr); disk.processRemoveAll(); String cacheName = "testRemove_Group_Region"; String groupName = "testRemove_Group"; int cnt = 25; for (int i = 0; i < cnt; i++) { GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key"); CacheElement<GroupAttrName<String>, String> element = new CacheElement<>(cacheName, groupAttrName, "data:" + i); IElementAttributes eAttr = new ElementAttributes(); eAttr.setIsSpool(true); element.setElementAttributes(eAttr); disk.processUpdate(element); } // verify each for (int i = 0; i < cnt; i++) { GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key"); ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName); assertNotNull("Should have received an element.", element); } // DO WORK // remove the group disk.remove(getGroupAttrName(cacheName, groupName, null)); for (int i = 0; i < cnt; i++) { GroupAttrName<String> groupAttrName = getGroupAttrName(cacheName, groupName, i + ":key"); ICacheElement<GroupAttrName<String>, String> element = disk.processGet(groupAttrName); // VERIFY assertNull("Should not have received an element.", element); } } /** * Internal method used for group functionality. * <p> * * @param cacheName * @param group * @param name * @return GroupAttrName */ private GroupAttrName<String> getGroupAttrName(String cacheName, String group, String name) { GroupId gid = new GroupId(cacheName, group); return new GroupAttrName<>(gid, name); } /** Holder for a string and byte array. */ static class X implements Serializable { /** ignore */ private static final long serialVersionUID = 1L; /** Test string */ String string; /*** test byte array. */ byte[] bytes; } }