/** * VMware Continuent Tungsten Replicator * Copyright (C) 2015 VMware, Inc. All rights reserved. * * Licensed 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. * * Initial developer(s): Robert Hodges * Contributor(s): */ package com.continuent.tungsten.common.cache; import java.util.List; import org.junit.Assert; import org.junit.Test; import com.continuent.tungsten.common.cache.CacheResourceManager; import com.continuent.tungsten.common.cache.IndexedLRUCache; /** * Implements a unit test of IndexedLRUCache features. * * @author <a href="mailto:robert.hodges@continuent.com">Robert Hodges</a> * @version 1.0 */ public class IndexedLRUCacheTest { // Implementation of a dummy resource manager. class StringResourceManager implements CacheResourceManager<String> { private int count = 0; public void release(String string) { count++; } } /** * Verify that we can create and release a simple cache. */ @Test public void testCreate() throws Exception { // Create cache. StringResourceManager srm = new StringResourceManager(); IndexedLRUCache<String> cache = new IndexedLRUCache<String>(10, srm); Assert.assertEquals("Empty, size=0", 0, cache.size()); Assert.assertNull("No value found", cache.get("any")); Assert.assertEquals("Empty list", 0, cache.lruValues().size()); } /** * Verify we can insert, retrieve, and delete a single entry. */ @Test public void testCacheOfOne() throws Exception { // Create cache. StringResourceManager srm = new StringResourceManager(); IndexedLRUCache<String> cache = new IndexedLRUCache<String>(10, srm); // Add an entry. cache.put("entry", "my string"); Assert.assertEquals("1 entry", 1, cache.size()); // Ensure we can find it. String myString = cache.get("entry"); Assert.assertEquals("entry value", "my string", myString); Assert.assertEquals("List of 1", 1, cache.lruValues().size()); // Ensure we can remove it. Assert.assertEquals("No released items", 0, srm.count); cache.invalidate("entry"); Assert.assertNull("No value found", cache.get("any")); Assert.assertEquals("Empty list", 0, cache.lruValues().size()); Assert.assertEquals("1 released item", 1, srm.count); } /** * Verify that connections are always ordered from first to last used in the * LRU list. */ @Test public void testLRUMaintenance() throws Exception { // Create cache. StringResourceManager srm = new StringResourceManager(); IndexedLRUCache<String> cache = new IndexedLRUCache<String>(10, srm); // Add some entries. String[] entries = {"a", "a.b", "a.a", "b"}; for (int i = 0; i < entries.length; i++) cache.put(entries[i], new Integer(i).toString()); // Ensure that entries are in the LRU in reverse order of addition, // i.e., in reverse order of addition. List<String> lru = cache.lruValues(); for (int i = 0; i < lru.size(); i++) { String value = lru.get(i); Assert.assertEquals("Initial load", 3 - i, Integer.parseInt(value)); } // Touch the last entry and validate that it moves to the front. String v = cache.get("a.b"); List<String> lru2 = cache.lruValues(); String v1 = lru2.get(0); Assert.assertEquals("Touched member at head of LRU", v, v1); // Remove two entries and ensure they leave the list. We get them to // ensure their location in the list. String v2a = cache.get("a.b"); String v2b = cache.get("a"); cache.invalidate("a.b"); cache.invalidate("a"); List<String> lru3 = cache.lruValues(); Assert.assertFalse("Looking for first value", lru3.remove(v2a)); Assert.assertFalse("Looking for first value", lru3.remove(v2b)); Assert.assertEquals("LRU has only 2 members", 2, lru3.size()); // Release all entries and check the LRU size. cache.invalidateByPrefix("a"); List<String> lru4 = cache.lruValues(); Assert.assertEquals("LRU has only 1 member", 1, lru4.size()); cache.invalidateAll(); List<String> lru5 = cache.lruValues(); Assert.assertEquals("LRU has 0 members", 0, lru5.size()); } /** * Verify that entries are purged in LRU order when the index hits maximum * capacity. */ @Test public void testPurge() throws Exception { // Create cache. StringResourceManager srm = new StringResourceManager(); IndexedLRUCache<String> cache = new IndexedLRUCache<String>(3, srm); // Add some entries. This will overflow capacity and force a purge. String[] entries = {"a", "a.b", "a.a", "b"}; for (int i = 0; i < entries.length; i++) cache.put(entries[i], new Integer(i).toString()); Assert.assertEquals("Initial load", 3, cache.size()); // Ensure that only the last three entries are present. List<String> lru = cache.lruValues(); for (int i = 0; i < (entries.length - 1); i++) { String value = lru.get(i); Assert.assertEquals("LRU after first purge", 3 - i, Integer .parseInt(value)); } // Add another entry and touch two values to get them at the head of the // LRU. Conform that these are all in the LRU in correct order. String v1 = cache.get("a.b"); String v2 = cache.get("a.a"); cache.put("c.1", "4"); List<String> lru2 = cache.lruValues(); Assert.assertEquals("Touched member #1", "4", lru2.get(0)); Assert.assertEquals("Touched member #1", v2, lru2.get(1)); Assert.assertEquals("Touched member #1", v1, lru2.get(2)); cache.invalidateAll(); } /** * Verify that values may be invalidated by key, by prefix, and by all values * remaining in cache. */ @Test public void testInvalidate() throws Exception { // Create cache. StringResourceManager srm = new StringResourceManager(); IndexedLRUCache<String> cache = new IndexedLRUCache<String>(50, srm); // Add some entries. String[] entries = {"a", "a.b", "a.a", "b", "b.a", "c", "a.a.b", "b.b"}; for (int i = 0; i < entries.length; i++) cache.put(entries[i], new Integer(i).toString()); // Remove single key. cache.invalidate("b"); Assert.assertEquals("Remove single key", 7, cache.size()); // Remove a prefix. cache.invalidateByPrefix("a.a"); Assert.assertEquals("Remove prefix", 5, cache.size()); // Remove all. cache.invalidateAll(); Assert.assertEquals("Remove all", 0, cache.size()); } }