package org.infinispan.notifications.cachelistener;
import static org.testng.AssertJUnit.assertEquals;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.filter.CollectionKeyFilter;
import org.infinispan.metadata.Metadata;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryActivated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryInvalidated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryPassivated;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
import org.infinispan.notifications.cachelistener.annotation.TopologyChanged;
import org.infinispan.notifications.cachelistener.event.CacheEntryEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
import org.infinispan.notifications.cachelistener.event.Event;
import org.infinispan.notifications.cachelistener.event.TopologyChangedEvent;
import org.infinispan.notifications.cachelistener.filter.CacheEventFilter;
import org.infinispan.notifications.cachelistener.filter.EventType;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import org.testng.annotations.Test;
/**
* Simple test class that tests to make sure other events are properly handled for filters
*
* @author wburns
* @since 4.0
*/
@Test(groups = "functional", testName = "notifications.cachelistener.CacheNotifierFilterTest")
public class CacheNotifierFilterTest extends MultipleCacheManagersTest {
protected final String CACHE_NAME = getClass().getName();
protected ConfigurationBuilder builderUsed;
@Override
protected void createCacheManagers() throws Throwable {
builderUsed = new ConfigurationBuilder();
builderUsed.clustering().cacheMode(CacheMode.REPL_SYNC);
createClusteredCaches(3, CACHE_NAME, builderUsed);
}
private static class VisitedFilter implements CacheEventFilter<String, String> {
@Override
public boolean accept(String key, String oldValue, Metadata oldMetadata, String newValue, Metadata newMetadata, EventType eventType) {
return eventType.getType() != Event.Type.CACHE_ENTRY_VISITED;
}
}
@SuppressWarnings("unused")
@Listener
private static class TestListener {
private static final Log log = LogFactory.getLog(TestListener.class);
private final List<CacheEntryVisitedEvent> visitedEvents = Collections.synchronizedList(
new ArrayList<>());
private final List<TopologyChangedEvent> topologyEvents = Collections.synchronizedList(new ArrayList<>());
@CacheEntryVisited
public void entryVisited(CacheEntryVisitedEvent event) {
log.tracef("Visited %s", event.getKey());
visitedEvents.add(event);
}
@TopologyChanged
public void topologyChanged(TopologyChangedEvent event) {
topologyEvents.add(event);
}
}
@SuppressWarnings("unused")
@Listener
private static class AllCacheEntryListener {
private final List<CacheEntryEvent> events = Collections.synchronizedList(new ArrayList<>());
@CacheEntryVisited
@CacheEntryActivated
@CacheEntryModified
@CacheEntryRemoved
@CacheEntryCreated
@CacheEntryInvalidated
@CacheEntryPassivated
public void listenEvent(CacheEntryEvent event) {
events.add(event);
}
}
/**
* Basic test to ensure that non modification events are properly filtered
*/
@Test
public void testCacheEntryVisitedEventFiltered() {
String key = "key";
String value = "value";
Cache<String, String> cache0 = cache(0, CACHE_NAME);
cache0.put(key, value);
TestListener listener = new TestListener();
cache0.addListener(listener, new CollectionKeyFilter<>(Collections.singletonList(key)));
assertEquals(value, cache0.get(key));
assertEquals(0, listener.visitedEvents.size());
// Verify others work still as well
String notKey = "not" + key;
cache0.put(notKey, value);
cache0.get("not" + key);
cache0.getAdvancedCache().getAll(Collections.singleton("not" + key));
assertEquals(4, listener.visitedEvents.size());
}
@Test
public void testNonCacheEventsNotFiltered() {
Cache<String, String> cache0 = cache(0, CACHE_NAME);
TestListener listener = new TestListener();
// This would block all cache events
cache0.addListener(listener, new CollectionKeyFilter<>(Collections.emptyList(), true));
addClusterEnabledCacheManager(builderUsed);
waitForClusterToForm(CACHE_NAME);
// Adding a node requires 4 topologies x2 for pre/post = 8
assertEquals(8, listener.topologyEvents.size());
}
@Test
public void testVisitationsBlocked() {
String key = "key";
String value = "value";
Cache<String, String> cache0 = cache(0, CACHE_NAME);
cache0.put(key, value);
AllCacheEntryListener listener = new AllCacheEntryListener();
cache0.addListener(listener, new VisitedFilter(), null);
assertEquals(value, cache0.get(key));
assertEquals(0, listener.events.size());
// Verify others don't work as well
String notKey = "not" + key;
cache0.put(notKey, value);
cache0.get("not" + key);
// We should have 2 create events
assertEquals(2, listener.events.size());
assertEquals(Event.Type.CACHE_ENTRY_CREATED, listener.events.get(0).getType());
assertEquals(Event.Type.CACHE_ENTRY_CREATED, listener.events.get(1).getType());
}
}