package org.infinispan.notifications.cachelistener; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.List; import org.infinispan.Cache; import org.infinispan.commands.FlagAffectedCommand; import org.infinispan.commands.tx.VersionedPrepareCommand; import org.infinispan.commons.hash.MurmurHash3; import org.infinispan.compat.TypeConverter; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.Configuration; import org.infinispan.container.InternalEntryFactory; import org.infinispan.container.entries.CacheEntry; import org.infinispan.container.versioning.EntryVersionsMap; import org.infinispan.container.versioning.VersionGenerator; import org.infinispan.context.Flag; import org.infinispan.context.InvocationContext; import org.infinispan.context.impl.NonTxInvocationContext; import org.infinispan.context.impl.TxInvocationContext; import org.infinispan.distribution.DistributionManager; import org.infinispan.distribution.LocalizedCacheTopology; import org.infinispan.distribution.TestAddress; import org.infinispan.distribution.ch.ConsistentHash; import org.infinispan.distribution.ch.impl.DefaultConsistentHash; import org.infinispan.interceptors.impl.WrappedByteArrayConverter; import org.infinispan.interceptors.locking.ClusteringDependentLogic; import org.infinispan.lifecycle.ComponentStatus; import org.infinispan.metadata.Metadata; import org.infinispan.notifications.cachelistener.cluster.ClusterEventManager; import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent; import org.infinispan.notifications.cachelistener.event.Event; import org.infinispan.remoting.transport.Address; import org.infinispan.topology.CacheTopology; import org.mockito.Mockito; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @Test(testName = "notifications.cachelistener.OnlyPrimaryOwnerTest", groups = "unit") public class OnlyPrimaryOwnerTest { CacheNotifierImpl n; Cache mockCache; PrimaryOwnerCacheListener cl; InvocationContext ctx; MockCDL cdl = new MockCDL(); @BeforeMethod public void setUp() { n = new CacheNotifierImpl(); mockCache = mock(Cache.class, RETURNS_DEEP_STUBS); Configuration config = mock(Configuration.class, RETURNS_DEEP_STUBS); when(mockCache.getAdvancedCache().getStatus()).thenReturn(ComponentStatus.INITIALIZING); when(mockCache.getAdvancedCache().getComponentRegistry().getComponent(any(Class.class))).then( invocationOnMock -> Mockito.mock((Class<?>) invocationOnMock.getArguments()[0])); when(mockCache.getAdvancedCache().getComponentRegistry().getComponent(TypeConverter.class)).thenReturn( new WrappedByteArrayConverter()); when(mockCache.getAdvancedCache().getComponentRegistry().getComponent(any(Class.class), anyString())).then( invocationOnMock -> Mockito.mock((Class<?>) invocationOnMock.getArguments()[0])); n.injectDependencies(mockCache, cdl, null, config, mock(DistributionManager.class), mock(InternalEntryFactory.class), mock(ClusterEventManager.class)); cl = new PrimaryOwnerCacheListener(); n.start(); n.addListener(cl); ctx = new NonTxInvocationContext(null); } private static class MockCDL implements ClusteringDependentLogic { private static final TestAddress PRIMARY = new TestAddress(0); private static final TestAddress BACKUP = new TestAddress(1); private static final TestAddress NON_OWNER = new TestAddress(2); boolean isOwner, isPrimaryOwner; @Override public LocalizedCacheTopology getCacheTopology() { List<Address> members = Arrays.asList(PRIMARY, BACKUP, NON_OWNER); List<Address>[] ownership = new List[]{Arrays.asList(PRIMARY, BACKUP)}; ConsistentHash ch = new DefaultConsistentHash(MurmurHash3.getInstance(), 2, 1, members, null, ownership); CacheTopology cacheTopology = new CacheTopology(0, 0, ch, null, CacheTopology.Phase.NO_REBALANCE, null, null); Address localAddress = isPrimaryOwner ? PRIMARY : (isOwner ? BACKUP : NON_OWNER); return new LocalizedCacheTopology(CacheMode.DIST_SYNC, cacheTopology, key -> 0, localAddress); } @Override public void commitEntry(CacheEntry entry, Metadata metadata, FlagAffectedCommand command, InvocationContext ctx, Flag trackFlag, boolean l1Invalidation) { throw new UnsupportedOperationException(); } @Override public Commit commitType(FlagAffectedCommand command, InvocationContext ctx, Object key, boolean removed) { return isOwner ? Commit.COMMIT_LOCAL : Commit.NO_COMMIT; } @Override public EntryVersionsMap createNewVersionsAndCheckForWriteSkews(VersionGenerator versionGenerator, TxInvocationContext context, VersionedPrepareCommand prepareCommand) { throw new UnsupportedOperationException(); } @Override public Address getAddress() { throw new UnsupportedOperationException(); } } public void testOwnership() { // Is not owner nor primary owner cdl.isOwner = false; cdl.isPrimaryOwner = false; n.notifyCacheEntryCreated("reject", "v1", null, true, ctx, null); n.notifyCacheEntryCreated("reject", "v1", null, false, ctx, null); assert !cl.isReceivedPost(); assert !cl.isReceivedPre(); assert cl.getInvocationCount() == 0; // Is an owner but not primary owner cdl.isOwner = true; cdl.isPrimaryOwner = false; n.notifyCacheEntryCreated("reject", "v1", null, true, ctx, null); n.notifyCacheEntryCreated("reject", "v1", null, false, ctx, null); assert !cl.isReceivedPost(); assert !cl.isReceivedPre(); assert cl.getInvocationCount() == 0; // Is primary owner cdl.isOwner = true; cdl.isPrimaryOwner = true; n.notifyCacheEntryCreated("accept", "v1", null, true, ctx, null); n.notifyCacheEntryCreated("accept", "v1", null, false, ctx, null); assert cl.isReceivedPost(); assert cl.isReceivedPre(); assert cl.getInvocationCount() == 2; assert cl.getEvents().get(0).getCache() == mockCache; assert cl.getEvents().get(0).getType() == Event.Type.CACHE_ENTRY_CREATED; assert ((CacheEntryCreatedEvent) cl.getEvents().get(0)).getKey().equals("accept"); assert ((CacheEntryCreatedEvent) cl.getEvents().get(0)).getValue() == null; assert cl.getEvents().get(1).getCache() == mockCache; assert cl.getEvents().get(1).getType() == Event.Type.CACHE_ENTRY_CREATED; assert ((CacheEntryCreatedEvent) cl.getEvents().get(1)).getKey().equals("accept"); assert ((CacheEntryCreatedEvent) cl.getEvents().get(1)).getValue().equals("v1"); } }