package org.infinispan.notifications.cachelistener.cluster;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNull;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.distribution.MagicKey;
import org.infinispan.filter.CollectionKeyFilter;
import org.infinispan.notifications.cachelistener.event.CacheEntryEvent;
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
import org.infinispan.notifications.cachelistener.event.Event;
import org.infinispan.notifications.cachelistener.filter.CacheEventConverter;
import org.infinispan.notifications.cachelistener.filter.CacheEventFilter;
import org.infinispan.notifications.cachelistener.filter.KeyFilterAsCacheEventFilter;
import org.infinispan.notifications.cachelistener.filter.KeyValueFilterAsCacheEventFilter;
import org.infinispan.test.TestingUtil;
import org.testng.annotations.Test;
/**
* Base class to be used for cluster listener tests for both tx and nontx caches
*
* @author wburns
* @since 7.0
*/
@Test(groups = "functional")
public abstract class AbstractClusterListenerTest extends AbstractClusterListenerUtilTest {
protected AbstractClusterListenerTest(boolean tx, CacheMode cacheMode) {
super(tx, cacheMode);
}
protected ClusterListener listener() {
return new ClusterListener();
}
@Test
public void testCreateFromNonOwnerWithListenerNotOwner() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
MagicKey key = new MagicKey(cache1, cache2);
verifySimpleInsertion(cache2, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE);
}
@Test
public void testCreateFromNonOwnerWithListenerAsBackupOwner() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
MagicKey key = new MagicKey(cache1, cache0);
verifySimpleInsertion(cache2, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE);
}
@Test
public void testLocalNodeOwnerAndClusterListener() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
MagicKey key = new MagicKey(cache0);
verifySimpleInsertion(cache0, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE);
}
@Test
public void testLocalNodeNonOwnerAndClusterListener() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
MagicKey key = new MagicKey(cache1, cache2);
verifySimpleInsertion(cache0, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE);
}
@Test
public void testSimpleFilterNotOwner() {
testSimpleFilter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)));
}
@Test
public void testSimpleFilterLocalOnly() {
testSimpleFilter(new MagicKey(cache(0, CACHE_NAME)));
}
@Test
public void testMetadataFilterNotOwner() {
final String keyToFilterOut = "filter-me";
testFilter(keyToFilterOut, new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), 1000l,
new KeyValueFilterAsCacheEventFilter(new LifespanFilter<Object, String>(100)));
}
@Test
public void testMetadataFilterLocalOnly() {
final String keyToFilterOut = "filter-me";
testFilter(keyToFilterOut, new MagicKey(cache(0, CACHE_NAME)), 1000l,
new KeyValueFilterAsCacheEventFilter(new LifespanFilter<Object, String>(100)));
}
protected void testSimpleFilter(Object key) {
final String keyToFilterOut = "filter-me";
testFilter(keyToFilterOut, key, null, new KeyFilterAsCacheEventFilter<Object>(
new CollectionKeyFilter(Collections.singleton(key), true)));
}
protected void testFilter(Object keyToFilterOut, Object keyToUse, Long lifespan, CacheEventFilter<? super Object, ? super String> filter) {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, filter, null);
cache0.put(keyToFilterOut, FIRST_VALUE);
// We should not have gotten the message since it was filtered
assertEquals(clusterListener.events.size(), 0);
verifySimpleInsertion(cache0, keyToUse, FIRST_VALUE, lifespan, clusterListener, FIRST_VALUE);
}
@Test
public void testSimpleConverterNotOwner() {
testSimpleConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)));
}
@Test
public void testSimpleConverterLocalOnly() {
testSimpleConverter(new MagicKey(cache(0, CACHE_NAME)));
}
@Test
public void testMetadataConverterSuccessNotOwner() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(true, 500);
testConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), FIRST_VALUE, lifespan, lifespan, converter);
}
@Test
public void testMetadataConverterSuccessLocalOnly() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(true, 500);
testConverter(new MagicKey(cache(0, CACHE_NAME)), FIRST_VALUE, lifespan, lifespan, converter);
}
@Test
public void testMetadataConverterNoPassReturnOriginalNotOwner() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(true, Long.MAX_VALUE);
testConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), FIRST_VALUE, FIRST_VALUE, lifespan, converter);
}
@Test
public void testMetadataConverterNoPassReturnOriginalLocalOnly() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(true, Long.MAX_VALUE);
testConverter(new MagicKey(cache(0, CACHE_NAME)), FIRST_VALUE, FIRST_VALUE, lifespan, converter);
}
@Test
public void testMetadataConverterNoPassReturnNullNotOwner() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(false, Long.MAX_VALUE);
testConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), FIRST_VALUE, null, lifespan, converter);
}
@Test
public void testMetadataConverterNoPassReturnNullLocalOnly() {
long lifespan = 25000;
LifespanConverter converter = new LifespanConverter(false, Long.MAX_VALUE);
testConverter(new MagicKey(cache(0, CACHE_NAME)), FIRST_VALUE, null, lifespan, converter);
}
protected void testSimpleConverter(Object key) {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, null, new StringTruncator(0, 2));
verifySimpleInsertion(cache0, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE.substring(0, 2));
}
protected <C> void testConverter(Object key, String value, Object resultingValue, Long lifespan,
CacheEventConverter<Object, ? super String, C> converter) {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, null, converter);
verifySimpleInsertion(cache0, key, value, lifespan, clusterListener, resultingValue);
}
@Test
public void testClusterListenerNodeGoesDown() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
int cache1ListenerSize = cache1.getAdvancedCache().getListeners().size();
int cache2ListenerSize = cache2.getAdvancedCache().getListeners().size();
log.info("Killing node 0 ..");
TestingUtil.killCacheManagers(manager(0));
cacheManagers.remove(0);
log.info("Node 0 killed");
TestingUtil.blockUntilViewsReceived(60000, false, cache1, cache2);
TestingUtil.waitForNoRebalance(cache1, cache2);
assertEquals(cache1.getAdvancedCache().getListeners().size(), cache1ListenerSize -
(cacheMode.isDistributed() ? 1 : 0));
assertEquals(cache2.getAdvancedCache().getListeners().size(), cache2ListenerSize -
(cacheMode.isDistributed() ? 1 : 0));
}
@Test
public void testNodeComesUpWithClusterListenerAlreadyInstalled() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
log.info("Adding a new node ..");
addClusterEnabledCacheManager(builderUsed);
log.info("Added a new node");
Cache<Object, String> cache3 = cache(3, CACHE_NAME);
MagicKey key = new MagicKey(cache3);
verifySimpleInsertion(cache3, key, FIRST_VALUE, null, clusterListener, FIRST_VALUE);
}
@Test
public void testNodeComesUpWithClusterListenerAlreadyInstalledFilterAndConverter() {
final String keyToFilter = "filter-me";
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, new KeyFilterAsCacheEventFilter<Object>(
new CollectionKeyFilter<Object>(Collections.singleton(keyToFilter), true)), new StringTruncator(0, 3));
log.info("Adding a new node ..");
addClusterEnabledCacheManager(builderUsed);
log.info("Added a new node");
Cache<Object, String> cache3 = cache(3, CACHE_NAME);
MagicKey key = new MagicKey(cache3);
cache3.put(key, FIRST_VALUE);
// Should be filtered
assertEquals(clusterListener.events.size(), 0);
verifySimpleInsertion(cache3, keyToFilter, FIRST_VALUE, null, clusterListener, FIRST_VALUE.substring(0, 3));
}
@Test
public void testSimpleClusterListenerRemoved() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
int initialCache0ListenerSize = cache0.getAdvancedCache().getListeners().size();
int initialCache1ListenerSize = cache1.getAdvancedCache().getListeners().size();
int initialCache2ListenerSize = cache2.getAdvancedCache().getListeners().size();
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
// Adding a cluster listener should add to each node in cluster
assertEquals(cache0.getAdvancedCache().getListeners().size(), initialCache0ListenerSize + 1);
assertEquals(cache1.getAdvancedCache().getListeners().size(), initialCache1ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
assertEquals(cache2.getAdvancedCache().getListeners().size(), initialCache2ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
cache0.removeListener(clusterListener);
assertEquals(cache0.getAdvancedCache().getListeners().size(), initialCache0ListenerSize);
assertEquals(cache1.getAdvancedCache().getListeners().size(), initialCache1ListenerSize);
assertEquals(cache2.getAdvancedCache().getListeners().size(), initialCache2ListenerSize);
}
@Test
public void testClusterListenerRemovedWithMultipleInstalledOnSameNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
int initialCache0ListenerSize = cache0.getAdvancedCache().getListeners().size();
int initialCache1ListenerSize = cache1.getAdvancedCache().getListeners().size();
int initialCache2ListenerSize = cache2.getAdvancedCache().getListeners().size();
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
// Adding a cluster listener should add to each node in cluster
assertEquals(cache0.getAdvancedCache().getListeners().size(), initialCache0ListenerSize + 1);
assertEquals(cache1.getAdvancedCache().getListeners().size(), initialCache1ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
assertEquals(cache2.getAdvancedCache().getListeners().size(), initialCache2ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
ClusterListener clusterListener2 = listener();
cache0.addListener(clusterListener2);
// Adding a second cluster listener should add to each node in cluster as well
assertEquals(cache0.getAdvancedCache().getListeners().size(), initialCache0ListenerSize + 2);
assertEquals(cache1.getAdvancedCache().getListeners().size(), initialCache1ListenerSize +
(cacheMode.isDistributed() ? 2 : 0));
assertEquals(cache2.getAdvancedCache().getListeners().size(), initialCache2ListenerSize +
(cacheMode.isDistributed() ? 2 : 0));
MagicKey key = new MagicKey(cache2, cache1);
cache1.put(key, FIRST_VALUE);
// Both listeners should have been notified
assertEquals(clusterListener.events.size(), 1);
assertEquals(clusterListener2.events.size(), 1);
verifySimpleInsertionEvents(clusterListener, key, FIRST_VALUE);
verifySimpleInsertionEvents(clusterListener2, key, FIRST_VALUE);
cache0.removeListener(clusterListener);
assertEquals(cache0.getAdvancedCache().getListeners().size(), initialCache0ListenerSize + 1);
assertEquals(cache1.getAdvancedCache().getListeners().size(), initialCache1ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
assertEquals(cache2.getAdvancedCache().getListeners().size(), initialCache2ListenerSize +
(cacheMode.isDistributed() ? 1 : 0));
// Change the value again to make sure other listener is still working properly
cache2.put(key, SECOND_VALUE);
assertEquals(clusterListener2.events.size(), 2);
CacheEntryEvent event = clusterListener2.events.get(1);
assertEquals(Event.Type.CACHE_ENTRY_MODIFIED, event.getType());
assertEquals(key, event.getKey());
assertEquals(SECOND_VALUE, ((CacheEntryModifiedEvent)event).getValue());
}
@Test
public void testMemberLeavesThatClusterListenerNotNotified() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
Object key = new MagicKey(cache1, cache2);
cache1.put(key, "some-key");
final ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
log.info("Killing node 1 ..");
TestingUtil.killCacheManagers(manager(1));
cacheManagers.remove(1);
log.info("Node 1 killed");
TestingUtil.blockUntilViewsReceived(10000, false, cacheManagers);
TestingUtil.waitForNoRebalance(caches(CACHE_NAME));
assertEquals(clusterListener.hasIncludeState() ? 1 : 0, clusterListener.events.size());
}
@Test
public void testPreviousValueConverterEventRaisedLocalNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0);
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, null, new StringAppender());
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener,
previousValue + previousExpiration + newValue + newExpiration);
}
@Test
public void testPreviousValueConverterEventRaisedNonOwnerNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0, cache1);
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache2.addListener(clusterListener, null, new StringAppender());
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener,
previousValue + previousExpiration + newValue + newExpiration);
}
@Test
public void testPreviousValueConverterEventRaisedBackupOwnerNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0, cache1);
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache1.addListener(clusterListener, null, new StringAppender());
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159265;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener,
previousValue + previousExpiration + newValue + newExpiration);
}
@Test
public void testPreviousValueFilterEventRaisedLocalNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0, cache1);
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache1.addListener(clusterListener, new NewLifespanLargerFilter<Object, String>(), null);
// This event is ignored because lifespan is shorter
cache0.put(key, previousValue, previousExpiration - 100, TimeUnit.MILLISECONDS);
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159265;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener, newValue);
}
@Test
public void testPreviousValueFilterEventRaisedNonOwnerNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0, cache1);
// This event is ignored because no previous lifespan
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache2.addListener(clusterListener, new NewLifespanLargerFilter<Object, String>(), null);
// This event is ignored because lifespan is shorter
cache0.put(key, previousValue, previousExpiration - 100, TimeUnit.MILLISECONDS);
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159265;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener, newValue);
}
@Test
public void testPreviousValueFilterEventRaisedBackupOwnerNode() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
String previousValue = "myOldValue";
long previousExpiration = 10000000;
MagicKey key = new MagicKey(cache0, cache1);
// This event is ignored because no previous lifespan
cache0.put(key, previousValue, previousExpiration, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache1.addListener(clusterListener, new NewLifespanLargerFilter<Object, String>(), null);
// This event is ignored because lifespan is shorter
cache0.put(key, previousValue, previousExpiration - 100, TimeUnit.MILLISECONDS);
String newValue = "myBrandSpankingNewValue";
long newExpiration = 314159265;
verifySimpleModification(cache0, key, newValue, newExpiration, clusterListener, newValue);
}
@Test
public void testCacheEventFilterConverter() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(0, CACHE_NAME);
Cache<Object, String> cache2 = cache(0, CACHE_NAME);
String convertedValue = "my-value";
FilterConverter filterConverter = new FilterConverter(true, convertedValue);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, filterConverter, filterConverter);
MagicKey key = new MagicKey(cache1, cache2);
verifySimpleInsertion(cache0, key, "doesn't-matter", null, clusterListener, convertedValue);
}
@Test
public void testListenerOnPrimaryNodeReadPrimary() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
MagicKey key = new MagicKey(cache0);
String expectedValue = key + "-expiring";
cache0.put(key, key + "-expiring", 1000, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
ts0.advance(1001);
assertNull(cache0.get(key));
int expectCount = clusterListener.hasIncludeState() ? 2 : 1;
eventually(() -> clusterListener.events.size() >= expectCount, 200000);
assertEquals(expectCount, clusterListener.events.size());
CacheEntryEvent event = clusterListener.events.get(clusterListener.hasIncludeState() ? 1 : 0);
assertEquals(Event.Type.CACHE_ENTRY_EXPIRED, event.getType());
assertEquals(key, event.getKey());
assertEquals(expectedValue, event.getValue());
}
@Test
public void testListenerOnPrimaryNodeReadBackup() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
MagicKey key = new MagicKey(cache0, cache1);
String expectedValue = key + "-expiring";
cache0.put(key, key + "-expiring", 1000, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
ts1.advance(1001);
assertNull(cache1.get(key));
int expectCount = clusterListener.hasIncludeState() ? 2 : 1;
eventually(() -> clusterListener.events.size() >= expectCount);
assertEquals(expectCount, clusterListener.events.size());
CacheEntryEvent event = clusterListener.events.get(clusterListener.hasIncludeState() ? 1 : 0);
assertEquals(Event.Type.CACHE_ENTRY_EXPIRED, event.getType());
assertEquals(key, event.getKey());
assertEquals(expectedValue, event.getValue());
}
public void testListenerOnBackupOwnerNodePrimaryRead() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
MagicKey key = new MagicKey(cache0, cache1);
String expectedValue = key + "-expiring";
cache0.put(key, key + "-expiring", 1000, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache1.addListener(clusterListener);
ts0.advance(1001);
assertNull(cache0.get(key));
int expectCount = clusterListener.hasIncludeState() ? 2 : 1;
eventually(() -> clusterListener.events.size() >= expectCount);
assertEquals(expectCount, clusterListener.events.size());
CacheEntryEvent event = clusterListener.events.get(clusterListener.hasIncludeState() ? 1 : 0);
assertEquals(Event.Type.CACHE_ENTRY_EXPIRED, event.getType());
assertEquals(key, event.getKey());
assertEquals(expectedValue, event.getValue());
}
public void testListenerOnBackupOwnerNodeBackupRead() {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
MagicKey key = new MagicKey(cache0, cache1);
String expectedValue = key + "-expiring";
cache0.put(key, key + "-expiring", 1000, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
ts1.advance(1001);
assertNull(cache1.get(key));
int expectCount = clusterListener.hasIncludeState() ? 2 : 1;
eventually(() -> clusterListener.events.size() >= expectCount);
assertEquals(expectCount, clusterListener.events.size());
CacheEntryEvent event = clusterListener.events.get(clusterListener.hasIncludeState() ? 1 : 0);
assertEquals(Event.Type.CACHE_ENTRY_EXPIRED, event.getType());
assertEquals(key, event.getKey());
assertEquals(expectedValue, event.getValue());
}
public void testAllExpire() throws InterruptedException {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
Cache<Object, String> cache1 = cache(1, CACHE_NAME);
Cache<Object, String> cache2 = cache(2, CACHE_NAME);
MagicKey key = new MagicKey(cache0);
String expectedValue = key + "-expiring";
cache0.put(key, key + "-expiring", 1000, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener);
ts0.advance(1001);
ts1.advance(1001);
ts2.advance(1001);
assertNull(cache0.get(key));
assertNull(cache1.get(key));
assertNull(cache2.get(key));
int expectCount = clusterListener.hasIncludeState() ? 2 : 1;
eventually(() -> clusterListener.events.size() >= expectCount);
// We can't assert size here, thiis is because expiration is done asynchronously. As such you could have more
// than 1 expire command come at the same time, although from different nodes. Currently we assume a null is
// okay to say it was expired, so you can get multiple expirations
CacheEntryEvent event = clusterListener.events.get(clusterListener.hasIncludeState() ? 1 : 0);
assertEquals(Event.Type.CACHE_ENTRY_EXPIRED, event.getType());
assertEquals(key, event.getKey());
assertEquals(expectedValue, event.getValue());
}
@Test
public void testSimpleExpirationFilterNotOwner() {
testSimpleExpirationFilter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)));
}
@Test
public void testExpirationMetadataFilterNotOwner() {
final String keyToFilterOut = "filter-me";
testExpirationFilter(keyToFilterOut, 50l, new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), 1000l,
new KeyValueFilterAsCacheEventFilter(new LifespanFilter<Object, String>(100)));
}
protected void testSimpleExpirationFilter(Object key) {
final String keyToFilterOut = "filter-me";
final long commonLifespan = 1000l;
testExpirationFilter(keyToFilterOut, commonLifespan, key, commonLifespan, new KeyFilterAsCacheEventFilter<Object>(
new CollectionKeyFilter(Collections.singleton(key), true)));
}
protected void testExpirationFilter(Object keyToFilterOut, Long keyToFilterOutLifespan, Object keyToUse, Long keyToUselifespan, CacheEventFilter<? super Object, ? super String> filter) {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
//put from a non-owner
cache0.put(keyToFilterOut, FIRST_VALUE, keyToFilterOutLifespan, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, filter, null);
ts0.advance(keyToFilterOutLifespan + 1);
ts1.advance(keyToFilterOutLifespan + 1);
ts2.advance(keyToFilterOutLifespan + 1);
assertNull(cache0.get(keyToFilterOut));
// We should not have gotten the message since it was filtered
assertEquals(clusterListener.events.size(), 0);
String expectedValue = keyToUse + "-expiring";
cache0.put(keyToUse, keyToUse + "-expiring", keyToUselifespan, TimeUnit.MILLISECONDS);
ts0.advance(keyToUselifespan + 1);
ts1.advance(keyToUselifespan + 1);
ts2.advance(keyToUselifespan + 1);
assertNull(cache0.get(keyToUse));
verifySimpleExpirationEvents(clusterListener, 2, keyToUse, expectedValue);
}
@Test
public void testSimpleExpirationConverterNotOwner() {
long lifespan = 1000l;
StringTruncator converter = new StringTruncator(0, 2);
testExpirationConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), FIRST_VALUE, FIRST_VALUE.substring(0, 2), lifespan, converter);
}
@Test
public void testMetadataExpirationConverterSuccessNotOwner() {
long lifespan = 25000l;
LifespanConverter converter = new LifespanConverter(true, 500);
testExpirationConverter(new MagicKey(cache(1, CACHE_NAME), cache(2, CACHE_NAME)), FIRST_VALUE, lifespan, lifespan, converter);
}
protected <C> void testExpirationConverter(Object key, String value, Object expectedValue, Long lifespan,
CacheEventConverter<Object, ? super String, C> converter) {
Cache<Object, String> cache0 = cache(0, CACHE_NAME);
cache0.put(key, value, lifespan, TimeUnit.MILLISECONDS);
ClusterListener clusterListener = listener();
cache0.addListener(clusterListener, null, converter);
ts0.advance(lifespan + 1);
ts1.advance(lifespan + 1);
ts2.advance(lifespan + 1);
assertNull(cache0.get(key));
verifySimpleExpirationEvents(clusterListener, clusterListener.hasIncludeState() ? 2 : 1, key, expectedValue);
}
}