Java tutorial
/** * Copyright (c) Codice Foundation * * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU * Lesser General Public License as published by the Free Software Foundation, either version 3 of * the License, or any later version. * * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public * License is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package ddf.catalog.cache; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import com.hazelcast.core.EntryEvent; import com.hazelcast.core.EntryEventType; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IMap; import com.hazelcast.test.TestHazelcastInstanceFactory; import ddf.catalog.cache.impl.ProductCacheDirListener; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.resource.data.ReliableResource; import java.io.File; import java.io.IOException; import java.util.Collection; import javax.activation.MimeType; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ResourceCacheImplSizeLimitTest { private static final String PRODUCT_CACHE_NAME = "Product_Cache"; private static final transient Logger LOGGER = LoggerFactory.getLogger(ResourceCacheImplSizeLimitTest.class); private TestHazelcastInstanceFactory hcInstanceFactory; private String productCacheDir; private ProductCacheDirListener<Object, Object> listener; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setup() throws IOException { temporaryFolder.create(); productCacheDir = temporaryFolder.newFolder("cache").toString(); hcInstanceFactory = new TestHazelcastInstanceFactory(10); listener = new ProductCacheDirListener<Object, Object>(15); } @After public void teardownTest() throws IOException { Collection<HazelcastInstance> instances = hcInstanceFactory.getAllHazelcastInstances(); HazelcastInstance instance = instances.iterator().next(); instance.shutdown(); cleanProductCacheDirectory(); } @Test // @Ignore public void testExceedCacheDirMaxSize() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setMaxDirSizeBytes(15); listener.setHazelcastInstance(instance); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache String rr1Key = "rr1"; String rr1FileName = "10bytes.txt"; simulateAddFileToProductCache(rr1Key, rr1FileName, rr1FileName, cacheMap); // this may take longer to execute than just the next line. // ensure that the entry has not been removed from the cache since it doesn't exceed the max // size verifyCached(cacheMap, rr1Key, rr1FileName); // simulate adding additional product to cache String rr2Key = "rr2"; String rr2FileName = "15bytes.txt"; simulateAddFileToProductCache(rr2Key, rr2FileName, rr2FileName, cacheMap); verifyRemovedFromCache(cacheMap, rr1Key, rr1FileName); verifyCached(cacheMap, rr2Key, rr2FileName); } @Test public void testExceedCacheDirMaxSizeMultipleEvictions() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setMaxDirSizeBytes(28); listener.setHazelcastInstance(instance); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache String rr1Key = "rr1"; String rr1FileName = "10bytes.txt"; simulateAddFileToProductCache(rr1Key, rr1FileName, rr1FileName, cacheMap); // ensure that the entry has not been removed from the cache since it doesn't exceed the max // size ReliableResource rrFromCache = (ReliableResource) cacheMap.get(rr1Key); assertNotNull(rrFromCache); // simulate adding additional product to cache String rr2Key = "rr2"; String rr2FileName = "15bytes.txt"; simulateAddFileToProductCache(rr2Key, rr2FileName, rr2FileName, cacheMap); // simulate adding additional product to cache String rr3Key = "rr3"; String rr3FileName = "15bytes_B.txt"; simulateAddFileToProductCache(rr3Key, rr3FileName, rr3FileName, cacheMap); verifyRemovedFromCache(cacheMap, rr1Key, rr1FileName); verifyRemovedFromCache(cacheMap, rr2Key, rr2FileName); verifyCached(cacheMap, rr3Key, rr3FileName); } @Test // @Ignore public void testNotExceedCacheDirMaxSize() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setMaxDirSizeBytes(50); listener.setHazelcastInstance(instance); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache String rr1Key = "rr1"; String rr1FileName = "10bytes.txt"; simulateAddFileToProductCache(rr1Key, rr1FileName, rr1FileName, cacheMap); // simulate adding additional product to cache String rr2Key = "rr2"; String rr2FileName = "15bytes.txt"; simulateAddFileToProductCache(rr2Key, rr2FileName, rr2FileName, cacheMap); // simulate adding additional product to cache String rr3Key = "rr3"; String rr3FileName = "15bytes_B.txt"; simulateAddFileToProductCache(rr3Key, rr3FileName, rr3FileName, cacheMap); verifyCached(cacheMap, rr1Key, rr1FileName); verifyCached(cacheMap, rr2Key, rr2FileName); verifyCached(cacheMap, rr3Key, rr3FileName); } @Test public void testSingleFileExceedCacheDirMaxSize() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); listener.setMaxDirSizeBytes(5); listener.setHazelcastInstance(instance); // Simulate adding product to product cache String rr1Key = "rr1"; String rr1FileName = "10bytes.txt"; simulateAddFileToProductCache(rr1Key, rr1FileName, rr1FileName, cacheMap); verifyRemovedFromCache(cacheMap, rr1Key, rr1FileName); } @Test public void testCacheDirMaxSizeManyEntries() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setHazelcastInstance(instance); listener.setMaxDirSizeBytes(10); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache String rrKeyPrefix = "rr"; String rr1FileNameBase = "10bytes.txt"; int indexOfRemainingEntry = 11; for (int i = 0; i < 11; i++) { simulateAddFileToProductCache(rrKeyPrefix + i, rr1FileNameBase, i + rr1FileNameBase, cacheMap); } // not in loop in order to slightly delay this file being added to the cache so it is sorted // correctly and not accidentally removed simulateAddFileToProductCache(rrKeyPrefix + 11, rr1FileNameBase, 11 + rr1FileNameBase, cacheMap); // entries from 0-10 should be removed from cache for (int i = 0; i < 11; i++) { verifyRemovedFromCache(cacheMap, rrKeyPrefix + 1, i + rr1FileNameBase); } verifyCached(cacheMap, rrKeyPrefix + indexOfRemainingEntry, indexOfRemainingEntry + rr1FileNameBase); } @Test public void testCacheDirMaxSizePaging() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setHazelcastInstance(instance); listener.setMaxDirSizeBytes(132); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache // push 12 files into cache to total a size of 120 bytes String rrKeyPrefix = "rr"; String rr1FileNameBase = "10bytes.txt"; for (int i = 0; i < 12; i++) { simulateAddFileToProductCache(rrKeyPrefix + i, rr1FileNameBase, i + rr1FileNameBase, cacheMap); } // ensure all 12 10-byte files are cached for (int i = 0; i < 12; i++) { verifyCached(cacheMap, rrKeyPrefix + i, i + rr1FileNameBase); } // push 1 large file into cache to total 245 bytes. This file will be on the second "page" when // querying the cache. String oneTwentyFiveBytesFileName = "125bytes.txt"; int indexOf125Bytes = 12; simulateAddFileToProductCache(rrKeyPrefix + indexOf125Bytes, oneTwentyFiveBytesFileName, oneTwentyFiveBytesFileName, cacheMap); // ensure 125-byte file is cached verifyCached(cacheMap, rrKeyPrefix + indexOf125Bytes, oneTwentyFiveBytesFileName); // entries from 0-9 should be removed from cache for (int i = 0; i < 12; i++) { verifyRemovedFromCache(cacheMap, rrKeyPrefix + i, i + rr1FileNameBase); } verifyCached(cacheMap, rrKeyPrefix + indexOf125Bytes, oneTwentyFiveBytesFileName); } @Test public void testCacheDirMaxSize0() throws IOException, InterruptedException { HazelcastInstance instance = initializeTestHazelcastInstance(); listener.setMaxDirSizeBytes(0); listener.setHazelcastInstance(instance); IMap<String, ReliableResource> cacheMap = instance.getMap(PRODUCT_CACHE_NAME); // Simulate adding product to product cache String rr1Key = "rr1"; String rr1FileName = "10bytes.txt"; simulateAddFileToProductCache(rr1Key, rr1FileName, rr1FileName, cacheMap); // ensure that the entry has not been removed from the cache since it doesn't exceed the max // size verifyCached(cacheMap, rr1Key, rr1FileName); // simulate adding additional product to cache String rr2Key = "rr2"; String rr2FileName = "15bytes.txt"; simulateAddFileToProductCache(rr2Key, rr2FileName, rr2FileName, cacheMap); verifyCached(cacheMap, rr2Key, rr2FileName); } private HazelcastInstance initializeTestHazelcastInstance() { HazelcastInstance instance = hcInstanceFactory.newHazelcastInstance(); IMap<Object, Object> cacheMap1 = instance.getMap(PRODUCT_CACHE_NAME); // ProductCacheDirListener<Object, Object> listener = new ProductCacheDirListener<Object, // Object>(maxDirSizeBytes); // listener.setHazelcastInstance(instance); // cacheMap1.addEntryListener(listener, true); return instance; } private ReliableResource simulateAddFileToProductCache(String key, String fileName, String destFileName, IMap<String, ReliableResource> cacheMap) throws IOException { String productOriginalLocation = new File(this.getClass().getClassLoader().getResource(fileName).getPath()) .getAbsolutePath(); File rrCachedFile = new File(productCacheDir + "/" + destFileName); FileUtils.copyFile(new File(productOriginalLocation), rrCachedFile); ReliableResource rr = new ReliableResource(key, rrCachedFile.getAbsolutePath(), new MimeType(), fileName, new MetacardImpl()); rr.setSize(rrCachedFile.length()); LOGGER.debug("adding entry to cache: {}", key); cacheMap.put(key, rr); listener.entryAdded( new EntryEvent<Object, Object>(destFileName, null, EntryEventType.ADDED.getType(), key, rr)); return rr; } private void verifyCached(IMap<String, ReliableResource> cacheMap, String rrKey, String rrFileName) { ReliableResource rrFromCache = (ReliableResource) cacheMap.get(rrKey); assertNotNull(rrFromCache); File rrCachedFile = new File(productCacheDir + File.separator + rrFileName); assertTrue(new File(rrCachedFile.getAbsolutePath()).exists()); } private void verifyRemovedFromCache(IMap<String, ReliableResource> cacheMap, String rrKey, String rrFileName) { ReliableResource rrFromCache = (ReliableResource) cacheMap.get(rrKey); assertNull(rrFromCache); File rrCachedFile = new File(productCacheDir + File.separator + rrFileName); assertFalse(new File(rrCachedFile.getAbsolutePath()).exists()); } private void cleanProductCacheDirectory() throws IOException { FileUtils.cleanDirectory(new File(productCacheDir)); } }