ddf.catalog.cache.ResourceCacheSizeLimitTest.java Source code

Java tutorial

Introduction

Here is the source code for ddf.catalog.cache.ResourceCacheSizeLimitTest.java

Source

/**
 * 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 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.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.hazelcast.core.EntryEvent;
import com.hazelcast.core.EntryEventType;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.IMap;
import com.hazelcast.test.TestHazelcastInstanceFactory;

import ddf.catalog.cache.impl.ProductCacheDirListener;
import ddf.catalog.cache.impl.ResourceCache;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.resource.data.ReliableResource;

public class ResourceCacheSizeLimitTest {

    private static final String PRODUCT_CACHE_NAME = "Product_Cache";

    private static final transient Logger LOGGER = LoggerFactory.getLogger(ResourceCacheSizeLimitTest.class);

    private static TestHazelcastInstanceFactory hcInstanceFactory;

    private static String productCacheDir;

    private static ProductCacheDirListener<Object, Object> listener;

    @BeforeClass
    public static void oneTimeSetup() {
        String workingDir = System.getProperty("user.dir") + File.separator + "target";
        System.setProperty("karaf.home", workingDir);
        productCacheDir = workingDir + File.separator + ResourceCache.DEFAULT_PRODUCT_CACHE_DIRECTORY;
        hcInstanceFactory = new TestHazelcastInstanceFactory(10);
        listener = new ProductCacheDirListener<Object, Object>(15);
    }

    @AfterClass
    public static void oneTimeTeardown() {
        LOGGER.debug("instances still remaining" + Hazelcast.getAllHazelcastInstances().size());
    }

    @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 = this.getClass().getResource("/" + fileName).getFile();
        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));
    }
}