package org.infinispan.stream; import static org.testng.AssertJUnit.assertEquals; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.TransactionManager; import org.infinispan.Cache; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.container.entries.CacheEntry; import org.infinispan.distribution.DistributionManager; import org.infinispan.remoting.transport.Address; import org.infinispan.test.TestingUtil; import org.testng.annotations.Test; /** * Test to verify distributed stream iterator works properly when they key is a byte[] which has issues with normal * equality. * * @author wburns * @since 8.0 */ @Test(groups = {"functional", "smoke"}, testName = "stream.DistributedStreamTxEquivalenceTest") public class DistributedStreamTxEquivalenceTest extends BaseSetupStreamIteratorTest { public DistributedStreamTxEquivalenceTest() { super(true, CacheMode.DIST_SYNC); } @Override protected void enhanceConfiguration(ConfigurationBuilder builder) { super.enhanceConfiguration(builder); } enum OwnerMode { PRIMARY { @Override boolean accept(Object key, DistributionManager dm, Address localAddress) { return dm.getPrimaryLocation(key).equals(localAddress); } }, BACKUP { @Override boolean accept(Object key, DistributionManager dm, Address localAddress) { List<Address> owners = dm.locate(key); Iterator<Address> iter = owners.iterator(); // Skip primary owner iter.next(); while (iter.hasNext()) { if (localAddress.equals(iter.next())) { return true; } } return false; } }, NOT_OWNER { @Override boolean accept(Object key, DistributionManager dm, Address localAddress) { return !dm.locate(key).contains(localAddress); } }; abstract boolean accept(Object key, DistributionManager dm, Address localAddress); } public void testByteArrayExistingTransactionOnPrimaryOwner() throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException { testOwner(OwnerMode.PRIMARY); } public void testByteArrayExistingTransactionOnBackupOwner() throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException { testOwner(OwnerMode.BACKUP); } public void testByteArrayExistingTransactionOnNonOwner() throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException { testOwner(OwnerMode.NOT_OWNER); } private void testOwner(OwnerMode mode) throws SystemException, NotSupportedException { byte[] keyBytes = "my-key".getBytes(); Cache<byte[], String> cache = getCache(mode, keyBytes); cache.put(keyBytes, "my-value"); TransactionManager tm = TestingUtil.extractComponent(cache, TransactionManager.class); tm.begin(); try { // Note it is the same bytes but different instance byte[] keyBytes2 = "my-key".getBytes(); cache.put(keyBytes2, "filtered-value"); Iterator<CacheEntry<byte[], String>> iterator = cache.getAdvancedCache().cacheEntrySet().stream().iterator(); Map<byte[], String> results = mapFromIterator(iterator); assertEquals(1, results.size()); } finally { tm.rollback(); } } private <K, V> Cache<K, V> getCache(OwnerMode mode, Object key) { List<Cache<K, V>> caches = caches(CACHE_NAME); for (Cache<K, V> cache : caches) { if (mode.accept(key, cache.getAdvancedCache().getDistributionManager(), cache.getCacheManager().getAddress())) { return cache; } } throw new IllegalStateException("No caches matched somehow!"); } }