package org.infinispan.stream;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.infinispan.Cache;
import org.infinispan.commands.write.RemoveCommand;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.TransientMortalCacheEntry;
import org.infinispan.context.Flag;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.FlagBitSets;
import org.infinispan.distribution.MagicKey;
import org.infinispan.filter.CacheFilters;
import org.infinispan.filter.CollectionKeyFilter;
import org.infinispan.filter.CompositeKeyValueFilterConverter;
import org.infinispan.filter.KeyFilterAsKeyValueFilter;
import org.infinispan.filter.KeyValueFilter;
import org.infinispan.filter.KeyValueFilterConverter;
import org.infinispan.interceptors.base.BaseCustomInterceptor;
import org.testng.annotations.Test;
/**
* Base class for stream iterator tests
*
* @author wburns
* @since 8.0
*/
@Test(groups = "functional", testName = "stream.BaseStreamIteratorTest")
public abstract class BaseStreamIteratorTest extends BaseSetupStreamIteratorTest {
public BaseStreamIteratorTest(boolean tx, CacheMode mode) {
super(tx, mode);
}
protected abstract Object getKeyTiedToCache(Cache<?, ?> cache);
protected Map<Object, String> putValuesInCache() {
// This is linked to keep insertion order
Map<Object, String> valuesInserted = new LinkedHashMap<Object, String>();
Cache<Object, String> cache = cache(0, CACHE_NAME);
Object key = getKeyTiedToCache(cache);
cache.put(key, key.toString());
valuesInserted.put(key, key.toString());
return valuesInserted;
}
@Test
public void simpleTest() {
Map<Object, String> values = putValuesInCache();
Cache<MagicKey, String> cache = cache(0, CACHE_NAME);
Iterator<Map.Entry<MagicKey, String>> iterator = cache.entrySet().iterator();
Map<MagicKey, String> results = mapFromIterator(iterator);
assertEquals(values, results);
}
@Test
public void simpleTestIteratorWithMetadata() {
// This is linked to keep insertion order
Set<CacheEntry<Object, String>> valuesInserted = new HashSet<>();
Cache<Object, String> cache = cache(0, CACHE_NAME);
for (int i = 0; i < 3; ++i) {
Object key = getKeyTiedToCache(cache);
TimeUnit unit = TimeUnit.MINUTES;
cache.put(key, key.toString(), 10, unit, i + 1, unit);
valuesInserted.add(new TransientMortalCacheEntry(key, key.toString(), unit.toMillis(i + 1), unit.toMillis(10),
System.currentTimeMillis()));
}
Set<CacheEntry<Object, String>> retrievedValues = new HashSet<>();
Iterator<CacheEntry<Object, String>> iterator = cache.getAdvancedCache().cacheEntrySet().stream().iterator();
while (iterator.hasNext()) {
CacheEntry<Object, String> entry = iterator.next();
retrievedValues.add(entry);
}
assertEquals(retrievedValues.size(), valuesInserted.size());
// Have to do our own equals since Transient uses created time which we can't guarantee will equal
for (CacheEntry<Object, String> inserted : valuesInserted) {
CacheEntry<Object, String> found = null;
for (CacheEntry<Object, String> retrieved : retrievedValues) {
if (retrieved.getKey().equals(inserted.getKey())) {
found = retrieved;
break;
}
}
assertNotNull("No retrieved Value matching" + inserted, found);
assertEquals(found.getValue(), inserted.getValue());
assertEquals(found.getMaxIdle(), inserted.getMaxIdle());
assertEquals(found.getLifespan(), inserted.getLifespan());
}
}
@Test
public void simpleTestLocalFilter() {
Map<Object, String> values = putValuesInCache();
Iterator<Map.Entry<Object, String>> iter = values.entrySet().iterator();
Map.Entry<Object, String> excludedEntry = iter.next();
// Remove it so comparison below will be correct
iter.remove();
Cache<MagicKey, String> cache = cache(0, CACHE_NAME);
KeyValueFilter<MagicKey, String> filter = new KeyFilterAsKeyValueFilter<>(new CollectionKeyFilter<>(
Collections.singleton(excludedEntry.getKey())));
Iterator<CacheEntry<MagicKey, String>> iterator = cache.getAdvancedCache().cacheEntrySet().stream().filter(
CacheFilters.predicate(filter)).iterator();
Map<MagicKey, String> results = mapFromIterator(iterator);
assertEquals(values, results);
}
@Test
public void testFilterAndConverterCombined() {
Map<Object, String> values = putValuesInCache();
Iterator<Map.Entry<Object, String>> iter = values.entrySet().iterator();
Map.Entry<Object, String> excludedEntry = iter.next();
// Remove it so comparison below will be correct
iter.remove();
Cache<MagicKey, String> cache = cache(0, CACHE_NAME);
KeyValueFilterConverter<MagicKey, String, String> filterConverter = new CompositeKeyValueFilterConverter<>(
new KeyFilterAsKeyValueFilter<>(new CollectionKeyFilter<>(Collections.singleton(excludedEntry.getKey()))),
new StringTruncator(2, 5));
try (Stream<CacheEntry<MagicKey, String>> stream = CacheFilters.filterAndConvert(
cache.getAdvancedCache().cacheEntrySet().stream(), filterConverter)) {
Map<MagicKey, String> results = mapFromStream(stream);
assertEquals(values.size(), results.size());
for (Map.Entry<Object, String> entry : values.entrySet()) {
assertEquals(entry.getValue().substring(2, 7), results.get(entry.getKey()));
}
}
}
@Test
public void testKeySetRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Object> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE).keySet().iterator();
it.hasNext();) {
assertTrue(values.containsKey(it.next()));
it.remove();
}
assertEquals(0, cache.size());
}
@Test
public void testKeySetStreamRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Object> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE).keySet().stream()
.iterator(); it.hasNext();) {
assertTrue(values.containsKey(it.next()));
it.remove();
}
assertEquals(0, cache.size());
}
@Test
public void testValuesRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Object> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE).values().iterator();
it.hasNext();) {
assertTrue(values.containsValue(it.next()));
it.remove();
}
assertEquals(0, cache.size());
}
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testValuesStreamRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Object> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(Flag.SKIP_CACHE_STORE).values().stream()
.iterator(); it.hasNext();) {
assertTrue(values.containsValue(it.next()));
it.remove();
}
}
@Test
public void testEntrySetRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Map.Entry<Object, Object>> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(
Flag.SKIP_CACHE_STORE).entrySet().iterator(); it.hasNext();) {
Map.Entry<Object, Object> entry = it.next();
Object key = entry.getKey();
assertEquals(values.get(key), entry.getValue());
it.remove();
}
assertEquals(0, cache.size());
}
@Test
public void testEntrySetStreamRemove() {
Map<Object, String> values = putValuesInCache();
final Cache<Object, Object> cache = cache(0, CACHE_NAME);
cache.getAdvancedCache().addInterceptor(new BaseCustomInterceptor() {
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
assertTrue(command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE));
return super.visitRemoveCommand(ctx, command);
}
}, 0);
for (Iterator<Map.Entry<Object, Object>> it = cache(0, CACHE_NAME).getAdvancedCache().withFlags(
Flag.SKIP_CACHE_STORE).entrySet().stream().iterator(); it.hasNext();) {
Map.Entry<Object, Object> entry = it.next();
Object key = entry.getKey();
assertEquals(values.get(key), entry.getValue());
it.remove();
}
assertEquals(0, cache.size());
}
}