/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library 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 2.1 of the License, or (at your option)
* any later version.
*
* This library 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.
*/
package com.liferay.portal.kernel.cache.index;
import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
import com.liferay.portal.kernel.cache.PortalCache;
import com.liferay.portal.kernel.cache.PortalCacheListener;
import com.liferay.portal.kernel.concurrent.test.MappedMethodCallableInvocationHandler;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.util.RandomTestUtil;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.tools.ToolDependencies;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
/**
* @author Preston Crary
*/
public class PortalCacheIndexerTest {
@ClassRule
public static final CodeCoverageAssertor codeCoverageAssertor =
CodeCoverageAssertor.INSTANCE;
@Before
public void setUp() throws Exception {
ToolDependencies.wireCaches();
_portalCache = MultiVMPoolUtil.getPortalCache(
RandomTestUtil.randomString());
_portalCacheIndexer = new PortalCacheIndexer<>(
_indexEncoder, _portalCache);
List<PortalCacheListener<?, ?>> portalCacheListeners =
ReflectionTestUtil.getFieldValue(
_portalCache, "_portalCacheListeners");
_cacheListener =
(PortalCacheListener<TestKey, String>)portalCacheListeners.get(0);
_mappedMethodCallableInvocationHandler =
new MappedMethodCallableInvocationHandler(
ReflectionTestUtil.getFieldValue(
_portalCacheIndexer, "_indexedCacheKeys"),
true);
ReflectionTestUtil.setFieldValue(
_portalCacheIndexer, "_indexedCacheKeys",
ProxyUtil.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class<?>[] {ConcurrentMap.class},
_mappedMethodCallableInvocationHandler));
}
@Test
public void testAddIndexedCacheKeyConcurrentPutDifferentKeys()
throws ReflectiveOperationException {
_mappedMethodCallableInvocationHandler.putBeforeCallable(
ConcurrentMap.class.getMethod(
"putIfAbsent", Object.class, Object.class),
new Callable<Void>() {
@Override
public Void call() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
return null;
}
});
_portalCache.put(_INDEX_1_KEY_2, _VALUE);
assertIndexCacheSynchronization();
}
@Test
public void testAddIndexedCacheKeyPutSameKey() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
assertIndexCacheSynchronization();
}
@Test
public void testAddIndexedCacheKeyWithDifferentIndex() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_2_KEY_3, _VALUE);
assertIndexCacheSynchronization();
}
@Test
public void testAddIndexedCacheKeyWithSameIndex() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_1_KEY_2, _VALUE);
assertIndexCacheSynchronization();
}
@Test
public void testConstructor() {
_portalCache = MultiVMPoolUtil.getPortalCache(
RandomTestUtil.randomString());
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCacheIndexer = new PortalCacheIndexer<>(
_indexEncoder, _portalCache);
assertIndexCacheSynchronization();
}
@Test
public void testDispose() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.unregisterPortalCacheListeners();
Set<TestKey> testKeys = _portalCacheIndexer.getKeys(
_indexEncoder.encode(_INDEX_1_KEY_1));
Assert.assertTrue(testKeys.isEmpty());
}
@Test
public void testGetIndexedCacheKeysWithIndexKey() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
Set<TestKey> testKeys = _portalCacheIndexer.getKeys(
_indexEncoder.encode(_INDEX_1_KEY_1));
testKeys.clear();
assertIndexCacheSynchronization();
}
@Test
public void testGetIndexedCacheKeysWithoutIndexKey() {
_portalCacheIndexer.getKeys(_indexEncoder.encode(_INDEX_1_KEY_1));
assertIndexCacheSynchronization();
}
@Test
public void testNotifyEntryEvicted() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.remove(_INDEX_1_KEY_1);
_cacheListener.notifyEntryEvicted(
_portalCache, _INDEX_1_KEY_1, _VALUE, 0);
assertIndexCacheSynchronization();
}
@Test
public void testNotifyEntryExpired() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.remove(_INDEX_1_KEY_1);
_cacheListener.notifyEntryExpired(
_portalCache, _INDEX_1_KEY_1, _VALUE, 0);
assertIndexCacheSynchronization();
}
@Test
public void testNotifyEntryRemoved() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.remove(_INDEX_1_KEY_1);
assertIndexCacheSynchronization();
}
@Test
public void testNotifyEntryUpdated() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
assertIndexCacheSynchronization();
}
@Test
public void testNotifyRemoveAll() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_1_KEY_2, _VALUE);
_portalCache.put(_INDEX_2_KEY_3, _VALUE);
_portalCache.removeAll();
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeyConcurrentPut()
throws ReflectiveOperationException {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_mappedMethodCallableInvocationHandler.putBeforeCallable(
ConcurrentMap.class.getMethod("remove", Object.class, Object.class),
new Callable<Void>() {
@Override
public Void call() throws Exception {
_portalCache.put(_INDEX_1_KEY_2, _VALUE);
return null;
}
});
_portalCache.remove(_INDEX_1_KEY_1);
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeyConcurrentRemove()
throws ReflectiveOperationException {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_mappedMethodCallableInvocationHandler.putBeforeCallable(
ConcurrentMap.class.getMethod("remove", Object.class, Object.class),
new Callable<Void>() {
@Override
public Void call() throws Exception {
_portalCacheIndexer.removeKeys(1L);
return null;
}
});
_portalCache.remove(_INDEX_1_KEY_1);
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeysWithIndex() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCacheIndexer.removeKeys(_indexEncoder.encode(_INDEX_1_KEY_1));
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeysWithoutIndex() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCacheIndexer.removeKeys(_indexEncoder.encode(_INDEX_2_KEY_3));
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeyWithKey() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.put(_INDEX_1_KEY_2, _VALUE);
_portalCache.remove(_INDEX_1_KEY_1);
assertIndexCacheSynchronization();
}
@Test
public void testRemoveIndexedCacheKeyWithoutKey() {
_portalCache.put(_INDEX_1_KEY_1, _VALUE);
_portalCache.remove(_INDEX_1_KEY_2);
assertIndexCacheSynchronization();
}
protected void assertIndexCacheSynchronization() {
Set<TestKey> expectedTestKeys = new HashSet<>(_portalCache.getKeys());
Set<Long> indexes = new HashSet<>();
for (TestKey testKey : expectedTestKeys) {
indexes.add(_indexEncoder.encode(testKey));
}
Set<TestKey> actualTestKeys = new HashSet<>();
for (Long index : indexes) {
actualTestKeys.addAll(_portalCacheIndexer.getKeys(index));
}
Assert.assertEquals(expectedTestKeys, actualTestKeys);
}
private static final TestKey _INDEX_1_KEY_1 = new TestKey(1L, 1L);
private static final TestKey _INDEX_1_KEY_2 = new TestKey(1L, 2L);
private static final TestKey _INDEX_2_KEY_3 = new TestKey(2L, 3L);
private static final String _VALUE = "VALUE";
private static final IndexEncoder<Long, TestKey> _indexEncoder =
new TestKeyIndexEncoder();
private PortalCacheListener<TestKey, String> _cacheListener;
private MappedMethodCallableInvocationHandler
_mappedMethodCallableInvocationHandler;
private PortalCache<TestKey, String> _portalCache;
private PortalCacheIndexer<Long, TestKey, String> _portalCacheIndexer;
}