ddf.catalog.cache.ResourceCacheImplSizeLimitTest.java Source code

Java tutorial

Introduction

Here is the source code for ddf.catalog.cache.ResourceCacheImplSizeLimitTest.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 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));
    }
}